This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-06-21
Channels
- # aws (2)
- # aws-lambda (1)
- # beginners (62)
- # cider (31)
- # cljs-dev (16)
- # cljsrn (8)
- # clojure (115)
- # clojure-greece (3)
- # clojure-israel (2)
- # clojure-italy (13)
- # clojure-nl (8)
- # clojure-russia (5)
- # clojure-spec (3)
- # clojure-uk (146)
- # clojurescript (108)
- # clojutre (5)
- # code-reviews (3)
- # cursive (48)
- # datomic (22)
- # editors (20)
- # emacs (7)
- # fulcro (16)
- # graphql (10)
- # mount (2)
- # off-topic (47)
- # onyx (22)
- # re-frame (100)
- # reagent (5)
- # reitit (7)
- # ring-swagger (6)
- # rum (5)
- # shadow-cljs (51)
- # specter (2)
- # tools-deps (95)
- # vim (10)
- # yada (7)
The problem is, the parts that don’t match are parts that I use fairly often. Vars, core interface names and methods, numerics, type hints, are all “advanced features” I use everyday and they’re completely different from CLJ and CLJS
If I have passed a class into a function as a var (e.g. (defn foo [klass] ...)
, how can I instantiate an instance of that class? (new klass)
of course is expecting a class called klass
, not using the value of the variable
small nitpick about terminology here, a var in clojure is an instance of clojure.lang.Var which is a mutable container holding a single value plus metadata, local bindings are not vars, they are regular values (unless you use with-local-vars which-- probably nobody needs)
if you need to instantiate it with parameters you’ll have to use some more advanced reflection and use .getConstructors
there is set/join
, I need that, but more like set/left-join
if there is such a thing 🙂
could use this one: https://gist.github.com/ataggart/d00cfde376476c9e495882a60deba904
Why would explain
hang on a simple spec?
But valid
would pass?
Let me check 😉
Nope, they all reduce to primitives (int? and string?)
Wait, I might have found something…
Hmm. No good. This is really odd.
>If there are no common column names, NATURAL JOIN behaves like JOIN ... ON TRUE, producing a cross-product join.
@borkdude The spec causing the issue is not recursive. However, it does derive from an existing spec.
So (s/def ::value string?)
and then (s/def ::old_value ::value)
Why would that be an issue?
there are a couple known issues with aliased specs like that but I don’t know why you’d see hanging. do you have a full repro?
Let me try to whip one up….
might also be possible you have an inconsistent repl state - specs are compiled at the point of definition and downstream specs should be recompiled if they change
occasionally that can lead to seeing something weird
I’ll keep that in mind.
Has anyone put together a strategy for integration of spec with unit testing? Like a checklist, perhaps, of techniques to use and when they’d be appropriate? If not, I’ll just experiment.
For example, I have a db layer, a core/app layer, and the web endpoints. So I can use ring-mock for the endpoints, and transactions for testing the db raw functions.
Then, I guess I can fdef the db functions, and that would let me mock them in stest/instrument for the unit tests in core/app….
@jmckitrick If you have function specs, then you could instrument
the namespace under test in your fixture (an uninstrument it at the end).
You beat me to it 😉
But check
isn't really intended to be run as part of unit tests -- it's a different kind of test (that may take a long time to run).
Ah, good to know. So more for REPL based testing?
You can use exercise
to generate random, conforming data for use in unit tests. So that's another aspect.
I have a few minimal examples I used to demo Clojure to our CTO, but now I need to come up with a comprehensive strategy for each project we do going forward. It’s a Scala shop, so everyone is worried about types, lol.
Well... Spec != types so the you probably don't want to "spec everything", just boundaries.
I demoed exercise, sample, generate, instrument, check, and summarize-results
That’s my thought as well, @seancorfield
yeah make sure that spec != types is very clear. Type-oriented people will definitely try to analogize
What else do you emphasize to those who think types are essential to enterprise projects? Assuming we got the go-ahead to use Clojure, that is. How to assuage their fears, really…
There's a huge shift in how you work, from Scala to Clojure. REPL-driven development (as much of a cliche as that is) means a very different way of "testing" code as you write it.
No question about it, I’ve loved REPL-driven development since discovering common lisp. But when I’m talking to Scala devs, and I’m not so much convincing them to try Clojure as to accept that it will be reliable….
@jmckitrick We initially tried Scala and moved to Clojure because Scala didn't really "fit" how the team liked to work (they were used to dynamic languages). If your team is happy with Scala, I don't know that you will successfully migrate them.
specs are a la carte, you can apply them to third party libs, etc. I think there is a really great sum up in a StuH talk from StrangeLoop 2016 / 2017 -- in the first ten minutes
How are you intended to add Clojure to what you're already doing?
I have to admit, it’s addicting to make a change, and see a bunch of red squiggly marks telling you what to fix next. 🙂
@seancorfield We are writing services and small UI projects for our team in Clojure/Clojurescript.
I have one other dev on our product team, and he’s a huge fan and is productive already. It’s his project I’m spec-ing.
OK, so they are isolated, somewhat independent projects?
A third dev has already contributed code, and really likes it since he had former Clojure experience.
And you're adding specs, after the fact, to an already working project? For what purpose specifically?
Yes, isolated, and calling other services or the db
It’s sort of an example project. I want the new dev to see how spec can/should be used. He was focused on delivering the functionality, while I add in specs.
Not an ideal approach, but it’s a start.
@jmckitrick are you using bare spec or have you found any of the helpers to be, uh, helpful? like expound
, orchestra
, spell-spec
, or spec-tools
for example
I just starting using expound, but not the other 3.
I have today and tomorrow dedicated to spec, so now’s the time!
expound is nice. I think orchestra is a bit stubborn about not understanding why instrumentation doesn't instrument the function return
@ghadi is this a discussion that has happened in an issue somewhere? i did a quick search for ‘return’ on the readme and don’t immediately follow your point
There’s a good discussion with @U064X3EF3 on this topic in the comments on this Reddit post https://www.reddit.com/r/Clojure/comments/7g4fl0/are_return_types_a_black_eye_for_clojure/
I personally find validating return values useful for the reasons explained here https://www.reddit.com/r/Clojure/comments/7g4fl0/comment/dqkgrcb
I haven't tried spell-spec nor know what it is. spec-tools doesn't seem necessary, and might interfere with a nascent team
@lee.justin.m I believe there is some threads on the mailing list
I'd definitely recommend expound
for a nascent team. It's easy to put it in your user.clj and reap benefits
you should check out spell-spec. pretty cool piece of tech from bhhauman. (in my case it has a feature for closed maps that I want but I won’t turn down better error messages)
I’ll start with raw spec and expound, so I understand the fundamentals, and go from there. My first goal is to establish some best practices.
So when spec-ing boundaries, is that generally just library entry points and web service endpoints? Or would it also include any internal API and persistence layer as well?
I realize there isn’t a right or wrong answer, I’m just curious what the general consensus is….
I can share my limited experience. I recently spec'd an internal API/persistence layer. It was my first spec and it seemed like a nice idea to return more meaningful errors over SQL errors for myself/other developers. My web endpoints will probably call the CRUD-like layer and use the same validation. I am hoping to use alexanderkiel/phrase
to convert the spec explanations to readable messages for the user. One thing that was a little funny (I also had the same experience with Django DRF serializers) is that when I have a create
function and update
function... I end up with 3 different specs since the fields are different for creating an object, partially-updating an object and the whole object itself. Whenever I have a new function with different parameters I create a new spec and sometime a new return spec if I validate the response. So in this way I can have a lot of specs and I'm not really sure if there is any way to reduce that.
I've found spec to be much more useful via conform
and valid?
than via instrument
but YMMV. I've found exercise
to be useful in generating "example test" data for situations where there are side-effecting functions in play (e.g., a database, a service call; where I don't want to mock the side-effects or it's "too hard"). In order to use check
you've really got to a) have a side-effect-free function to check and b) figure out useful invariants of your function -- and the latter can be hard for anything but the simplest function (and, of course, for simple functions correctness may be obvious and not worth testing 🙂 )
@seancorfield when you say you find it “much more useful via conform
and valid?
than via instrument
” does that effectively mean that you only use spec as tool during tests rather than during development? or do you mean you manually instrument like you would an assertion library? (or something totally different)
@seancorfield I thought it was just me who felt that way! I use valid?
frequently, and exercise
during development. Then I just fall back to unit testing and with-defs
for mocking.
I’m looking for an effective way to integrate instrument
into our testing strategy.
@lee.justin.m I mean we use it for validation/conformance of data in production code, much more than we use it for function argument/return checking.
We use instrument
from the REPL while developing but only use it in one place as a fixture in one set of unit tests:
(def ^:private test-member-id 12345)
(def ^:private test-facebook-id 123456789)
(def ^:private facebook-me {:id test-facebook-id :name "Test Harness"})
(def ^:private ^:dynamic *me* facebook-me)
(defn instrumented-and-stubbed
"Run tests with fake Facebook session."
[t]
(st/instrument (st/enumerate-namespace 'ws.facebook))
(with-redefs [facebook/me (fn [_] *me*)]
(t)))
and then (use-fixtures :once instrumented-and-stubbed)
(we don't both un-instrumenting that but we probably should)
and yada
, from the same author as Liberator https://github.com/juxt/yada
compojure-api
, if you haven’t heard already, can do so.
Does anyone know of an http library like Aleph or Ring that supports HTTP/2 out of the box?
@jmckitrick if you find yourself wishing for closed “keys” specs, definitely check out spell spec. I also like orchestra a lot.
One value of spec is documentation, and w/o orchestra, I had no confidence that my return specs were correct
Although (doall (map my-fn my-data))
and (seq (mapv my-fn my-data))
produce slightly different types (`LazySeq` vs PersistentVector$ChunkedSeq
) they both produce fully realized sequences and benchmarking suggests the latter is quite a bit faster (for large my-data
collections). Can anyone think of a non-pathological situation where swapping the former out for the latter would introduce bugs or break code that used the resulting sequence?
chunking behavior of consuming the result lazily - but if that breaks the consumer I think it's fair to blame the consumer
user=> (take 3 (map print (seq (mapv identity (take 40 (iterate inc 0))))))
(nil nil nil)012345678910111213141516171819202122232425262728293031
user=> (take 3 (map print (doall (map identity (take 40 (iterate inc 0))))))
(nil nil nil)012
Thank you both. Yes, chunking was the only thing I could think of and I didn't think the producer of the sequence should be blamed for that 🙂 (this relates to some code in clojure.java.jdbc
).