sirwhinesalot 33 minutes ago

I agree with the article, but I will note that we have a great tool for this problem that is (or at least can be) "statically typed": the relational model. Databases are precisely what you want for this sort of problem (even better if it's Datalog and you can encode rules that derive relevant information).

Most mainstream languages are very poorly equipped to do relational modeling. ORMs are a disaster (object-relational mismatch) and you don't necessarily need an actual database running in the background.

Clojure's approach is superior to the class hierarchy or sum type solution for this sort of very loose business domain modelling, for the reasons stated in the article, but it's also a local optima, and so is the "fat struct" solution (which is the statically typed equivalent). Even entity component systems are but a shadow of the relational model.

rorylaitila 31 minutes ago

I mostly agree. I have quipped once that I write "spaghetti and meatballs" code. The meatballs are the core domain objects, explicitly typed. The spaghetti is the business rules, untyped. With experience you get a good intuition where to draw the line. But the untyped code needs extensive testing.

Where I disagree with the article is on refactoring. It's identically hard both ways. Migrating to new business rules while simultaneously running the old and new system is the hard part. I don't find static typing helps or hurts me in particular. Compiler warnings are useful, but my unit tests catch the dynamic parts as well. Either way a lot breaks and often needs temporary scaffolding between the versions.

hackyhacky 38 minutes ago

Maybe I'm just missing something, but the "domain expert" that is described here is just... a function? The big win in Clojure is apparently using code instead of types?

  (defn apply-shipping-rules [order]
    (cond-> order
      (and (= :premium (:customer-type order))
           (> (:order-total order) 100))
      (assoc :shipping-cost 0)))
  • rjknight 23 minutes ago

    The "domain expert" is the business-person who is, it is suggested, more capable of reading and comprehending the Clojure code than the Haskell code.

    Since there is an equivalence between types and propositions, the Clojure program also models a "type", in the sense that the (valid) inputs to the program are obviously constrained by what the program can (successfully) process. One ought, in principle, to be able to transform between the two, and generate (parts of) one from the other.

    We do a limited form of this when we do type inference. There are also (more limited) cases where we can generate code from type signatures.

    I think op's point is that the Clojure code, which lays the system out as a process with a series of decision points, is closer to the mental model of the domain expert than the Haskell code which models it as a set of types. This seems plausible to me, although it's obviously subjective (not all domain experts are alike!).

    The secondary point is that the Clojure system may be more malleable - if you want to add a new state, you just directly add some code to handle that state at the appropriate points in the process. The friction here is indeed lower. But this does give up some safety in cases where you have failed to grasp how the system works; a type system is more likely to complain if your change introduces an inconsistency. The cost of that safety is that you have two representations of how the system works: the types and the logic, and you can't experiment with different logic in a REPL-like environment until you have fully satisfied the type-checker. Obviously a smarter system might allow the type-checker to be overridden in such cases (on a per-REPL-session basis, rather than by further editing the code) but I'm not aware of any systems that actually do this.

  • sirwhinesalot 28 minutes ago

    Yes, the point of the article is that people should do this (as is common in Clojure) rather than try and encode the rules in the type system (be it as a class hierarchy or a sum type).

moomin 18 minutes ago

I feel like this article is missing the point by a country mile. FP proponents very much know that requirements can change and wreak havoc with their type systems forcing them to change large numbers of likes. What the author is missing is that this is be welcomed and vastly preferable to the situation we find ourselves in with Python codebases where those lines still need updating but the code will happily run incorrectly if you fail to find them all. Switching off the alarm doesn’t stop the fire spreading.