Fork me on GitHub
#clojure-spec
<
2017-10-06
>
kennethkalmer09:10:57

I need some advice, I’ve hit a strange situation while trying to writes specs for data coming in from an external source… The source returns a map that roughly translates to this: {:productStatus {:productStatus "active" ...} ...}

kennethkalmer09:10:50

how on earth would I spec :productStatus the map, and the string value? I have no control over the output generated by the service

mpenet09:10:58

either you overspecify by creating separate nses for each, or use something more generic like map-of, if it's only one key its fine, if that s a lot of keys that s so so

kennethkalmer09:10:16

think separate ns’s are maybe the way to go here, will test that out, thanks!

kennethkalmer09:10:25

thanks @mpenet! simple, it works, don’t know why I got myself stuck in another loop

jaymartin17:10:25

This may be highly subjective, but will Spec replace :pre and :post conditions as the idiomatic way to validate inputs and outputs? For example, something like this:

(ns rna-transcription)


(def m
  {\G  \C
   \C  \G
   \T  \A
   \A  \U})


(defn to-rna [xs]
  {:pre [(every? #(contains? m %) xs)]}
  (apply str (map m xs)))

jaymartin18:10:02

Or will :pre and :post still have their place and time?

bfabry18:10:41

I could still see myself using :pre and :post to check non-local invariants, but that'd be pretty uncommon

seancorfield18:10:15

@jaymartin You could define specs for your DNA/RNA stuff and use s/valid? in :pre...

(s/def ::dna m)
(s/def ::dna-sequence (s/coll-of ::dna))
(defn to-rna [xs]
  {:pre [(s/valid? ::dna-sequence (seq xs))]}
  (apply str (map m xs)))

guy18:10:01

that looks nice

seancorfield18:10:05

or go further and define ::dna-string as (s/and string? #(s/coll-of ::dna (seq %))) and then {:pre [(s/valid? ::dna-string xs)]}

seancorfield18:10:03

(I hardly ever use :pre or :post, I must admit -- but I'm an advocate of leaving assertions on in production if you're going to use them at all)

guy18:10:24

what do you think about instrument in production? 👀

seancorfield18:10:03

instrument is a different beast, not least because it can trigger generative testing on higher-order function.

seancorfield18:10:08

In addition, instrument can introduce a big performance overhead depending on how much is spec'd and how they're written. The specs for java.jdbc are a case in point: they introduce a huge overhead.

jaymartin18:10:31

Super helpful!

seancorfield18:10:36

(Hmm, that reminds me that I forgot to add :keywordize? to the optional specs in release 0.7.3!)

jeaye18:10:11

@guy We're using it in production.

jeaye18:10:32

Given our specs, I've measured that we spend about 2% of our time with instrumentation.

jeaye18:10:14

As Sean said, that can very wildly, depending on how the specs are written. Primarily whether or not there are a lot of alternate paths which need to be considered.

jeaye18:10:52

For us, it's almost entirely clojure.core predicates and s/keys though, so it ends up being very fast and entirely practical for our production builds.

guy19:10:22

nice thanks @jeaye!