6 ms·
This is great and now these functions are now square in my radar, as well. As far as his example goes, this IS how you model data: (def people [{:name "E
by wellpast 7y ago
This is great and now these functions are now square in my radar, as well.
As far as his example goes, this IS how you model data:
(def people [{:name "Elsie"
:admin? true
:mod? true}
{:name "Lin Shiwen"
:nickname "Rocky"
:mod? true}])
Notice the lack of a "fill-in" static ADT form. No types here -- no static types NOR no ":type" field. Instead, we say what we know about our data items and we omit what we don't know. Just the facts, ma'am. And then Clojure gives us the obscenely simple tools to deal.
It will forever confound me why some developers/PLs wish to model data in static, inflexible, a priori structures -- given the overtly clear development efficiency and simplicity of NOT doing so (and not HAVING to do so.)
- jjnoakes 7y agoI find one's point of view on the matter is largely colored by one's experience. For example, I personally love static types. In your example I would prefer modelling people as a list of structs, each one with a required "name" (string), an optional "nickname" (string option), and required boolean flags for mod and admin. Why would I prefer it to be that way? Because a huge number of typos I might introduce in my project are caught before I even try to run something. I've been bitten once too many times by a typo somewhere (like looking up the "nick" property instead of "nickname") and having the program raise an error after it's already ran for a while. I can't stand that.
- bjconlan 7y agoThis can all be covered by more abstractions though via some schema/spec/type validation process. Ide integration is the interesting problem here (and typescript does this beautifully) but I agree horses for courses (and experience). I think the idea for using the keyword to hold the nullability of a field interesting, I thought this was more of a meta attribute in clj? In saying that I actually find this style of keywording way easier to read.
- wellpast 7y agoIt is probably true that a majority today favors static types, but I don't think this a subjective issue if the problem is maximizing developer throughput over time. Working on statically typed code bases that model things the way you are describing substantially increases the effort and time it takes to iterate. So while you may prefer them (per your experience or what else), there is still the fact that this way of development is suboptimal with respect to delivery throughput over time. Of course this is arguable (and is a very heavily argued topic) and the common retort is "to each is own" that isn't sufficient to me. One might prefer to work in assembly language (per experience or predisposition) but there is still a general statement that can be made that this is intrinsically a suboptimal way to work if delivery throughput is your goal. I believe that a similar claim can be made to differentiate working in static ADT v. dynamic Map types when modeling business domains. More food for thought. The typo problems you mentioned are solved by static types but at what cost? And is the CBA there? Especially considering that there are other ways to "solve" the typo problem that do not come with the heavy tax burden of statically typed ADTs.
- jjnoakes 7y agoIn my experience static types increase my development velocity. I can make changes and find many bugs at compile time without writing tests. I still write tests of course but I have to write fewer, and I rarely waste time fixing trivial things that raise errors at runtime. It is also much quicker for me to navigate the code. I can find definitions for identifiers instantly and get my mental model refreshed easily every time I switch contexts. I use dynamic languages too, and I find myself spending more time on things that static languages do for me.
- TeMPOraL 7y agoLast time I did a Clojure project, we've constrained the hell out of such maps with Clojure's Spec feature. Despite spending my last few years working with Common Lisp and a bit of Clojure, I've grown fond again of type constraints. Typing your data prevents a lot of silly and easy-to-make mistakes. Spec in Clojure is doubly useful, because specs can serve both as tests and generators. So after you define how your data is supposed to look like, you can make Clojure start pumping out randomly-generated examples, which you can then use to test your code. (Note that typing maps with Spec doesn't mean they're inflexible, a priori structures. You just pin down what you know. In this case, you could define that a "person" needs a :name key, and can optionally have :admin?, :mod? and :nickname fields. If it also has some other fields, no harm done.)
- dustingetz 7y agoSpec can only say what is included in a map, it can't exclude. And the spec is late-bound by the caller. Different callers mandate different specs for the same entity. I see that you know this but I object to the wording "constrained".
- TeMPOraL 7y agoFair enough. It's entirely unlike constraining in statically-typed languages, but in practice it can still work as constraints if you verify the specs as pre/post conditions of your functions (for which Clojure has some nice syntactic goodies available by default). The way we've used it, it worked almost as if the maps were statically-typed, and it saved my bacon quite a few times.
- lsh 7y agoclojure.spec + orchestra for nicely integrated pre/post spec checking https://github.com/jeaye/orchestra https://github.com/jeaye/orchestra
- filoeleven 7y agoSpec alpha 2 supports closed maps: https://github.com/clojure/spec-alpha2/wiki/Differences-from-spec.alpha https://github.com/clojure/spec-alpha2/wiki/Differences-from...