Fork me on GitHub
#clojure-spec
<
2019-09-06
>
potetm02:09:04

the upside of a well-broken-down design is you can always layer on syntax to taste

potetm02:09:25

the fundamental diff between “complex = verbose” and “complex = a few things glommed together” is the former can turn to the latter, but the inverse is not true 🙂

taylor02:09:34

>A complex system that works is invariably found to have evolved from a simple system that worked. A complex system designed from scratch never works and cannot be patched up to make it work. You have to start over, beginning with a working simple system.

potetm02:09:31

this is aligned with my experience

taylor02:09:48

it took me a long time to learn this lesson 🙂

taylor02:09:26

I think this quote resonates with my enjoyment of writing Clojure and how easy it is to compose little solutions into big ones

potetm02:09:17

honestly, the biggest win there is probably immutable data

potetm02:09:37

but I’m continuously surprised at how much simpler thing get if you design them to be run from the REPL

👍 4
potetm02:09:19

every TDDer: It’s like I’ve been saying for yeeeears! troll

taylor02:09:21

yeah, I felt the same way with other ML-like functional/immutable languages before Clojure. OCaml/F# is nice, but Clojure is more enjoyable for me

Leon09:09:12

Thats exactly what im looking for! Thanks, @potetm i was about to spin my own solution and dig into how to create custom spec validators for that (might still do, but only for the learning experience) As i said, i fully agree that well broken down Systems are easier to reason about and work with. But originally coming from Java, and then going to expressive languages like kotlin, haskell, Rust (and now clojure), ive really started to value expressivity. I like to talk in my Code like i would talk to a Person. I like to describe what im trying to achieve, how different Things relate to each other, and what Things represent, and i like to Use expressive Tools to achieve that. The Same way that a for Loop isnt really the best way to describe the relation of a list of numbers to the Same list with every number squared, i feel about using spec. Defining Things that Look and feel like Domain Model/ more complex stuff for simple validations works, but it doesnt Show what i want to express. In my analogy, i want to actually express (map #(* % %) my-list) . Simmiarly, in my spec i dont want to say "the arg title is of type ::title, where ::title is a String." but just "this function takes a String that will be displayed as the tite." It's not so much about complexity in a Code sense, but just about expressivity, readability and also just typing and reading time. And yes. Lines of Code do matter. Otherwise lisps would put their closing parens on New lines

potetm11:09:06

Yeah that makes sense to me.

potetm11:09:10

One thing that I really disliked about spec is that it encouraged creating names where none would suffice.

Leon12:09:09

yes, that is my exact point ;D glad we agree here, and i hope spec2 will change that

misha11:09:34

as a datapoint, in ~2 years I specced like 5 functions, and am really amused how much attention s/fdef and instrument get

potetm12:09:20

whyso? do you just not get a lot of value out of fdef?

Leon12:09:37

i spec pretty much all my functions, but mainly because its the only way to get immediately helpful error messages. especially in clojurescript, sometimes the errors really dont help. i just get some errors in some G_1235 generated function name and have no idea what happened. also, I'd say a big help for speccing all functions are the defn-spec feature of orchestra or things like ds/defn from defn-spec that lets you add specs directly into the function signature

misha12:09:31

there are few functions which benefit from gen-testing. which somewhat rhymes with "you really need just few refs per project". but other things too: - read/write overhead, - maintenance, - "spec pushes you to have global names where none suffice", - project size/complexity is not that out of control, so "specing 100% of the code is the only way out" - wide contact surface with mutable DOM in cljs - etc.

Leon12:09:54

maintainance isn't really a big problem, and the error reporting benefits are just huge

misha12:09:33

I prefer to understand what system is doing, when I can afford it. Admittedly, you are not always in position to have this as an option (project/team size, domain complexity, etc.)

misha12:09:21

some analogies would be: - turning off code highlighter to pay more attention to code. - writing code w/o autocomplete/autosuggest to know better whats there in the project. these things keep your mind in a tonus

misha12:09:03

and more stuff you will know you will have to keep track of, more reluctant you will be to let bloat slide in.

potetm13:09:40

@misha yes, to all that

potetm13:09:48

I’ve honestly had very little urge to use spec at all. Though I’ve spent the last 9mo on a novel thing, so nothing is solidified to the point where I want to invest in pouring some concrete.

4
potetm13:09:17

Actually, there are a fair number of unit tests, and IMO even those aren’t worth enough to bother.

potetm13:09:20

(They have to be touched fairly often and have caught very few/no bugs afaict)

misha13:09:00

and still, pouring concrete on every private function – is questionable

💯 4
seancorfield19:09:25

From our code base (World Singles Networks):

Clojure build/config 52 files 936 total loc
Clojure source 299 files 70282 total loc,
    3207 fns, 662 of which are private,
    441 vars, 29 macros, 62 atoms,
    602 specs, 21 function specs.
Clojure tests 330 files 19116 total loc,
    4 specs, 1 function specs.
We were an early adopter of Spec in production code (`conform`/`valid?`/`explain-data`) but we mostly spec data rather than functions, as you can see above.

gerred22:09:20

@seancorfield are you using valid? and conform in production paths or in tests or their own specs.clj file? that is to say, are you paying the performance costs at runtime for the specs you do have?

seancorfield23:09:52

@gerred We use conform and invalid? mostly, then explain-data to drive heuristics for turning spec errors into codes/messages we can return to client apps. But, yes, that's all production path code.

seancorfield23:09:16

A lot of our input form data and most of our API input parameters are run through Spec. We have conforming Specs that accept strings and will conform them to simple numbers, dates, Booleans etc. Something that Alex frowns on 🙂 but it has worked exceptionally well for us.

seancorfield23:09:33

We usually write the specs to accept either the native type we want or a string that can be parsed/coerced/conformed to that native type, and our specs have generators that produce strings (we mostly generate the underlying spec and then fmap str over that).