the-frey~/blog

DDD in Functional Languages and FP

04 December 2018

Now, I’m by no means an expert in this area, but there was a conversation at work about DDD in FP languages provoked by this great talk by Scott Wlaschin, and I figured I’d write up some thoughts.

Domain Modeling Made Functional - Scott Wlaschin

It seems like Scott’s essential insight (which, granted, is a good one) is that DDD in OO languages is marred by the tight coupling, or (sigh) ‘complecting’ between type and class.

Once you’re just modelling your domain with types and then using those in functions, you have a much greater flexibility in terms of how you compose together functionality (see what I did there?)… while still being able to ‘noun’ your business domain and build up an ontology/bounded context.

It’s worth puts on contrarian hat observing though that this applies more in a typed lambda calculus lang like haskell (or F# as a poor person’s haskell (is that too mean?)) than it does in ancestral FP languages like ML or Lisp, where you will[0] get data in and data out. In those situations the burden is placed more at the point of access rather than the point of definition.

That’s why you[1] see[2] a lot of business domain code being written as functions like

login->session
account-trigger->email
basket->order

Where there’s an implicit type at either end.

"Login form" -> "User session"
"A trigger action performed on an account" -> "An Email"
"A basket of Items" -> "An order"

This is I suppose where the schema-based stuff comes in when using a language like Clojure, and that’s super interesting in terms of weak pseudo polymorphic typing… but crucially for this discussion, allows you to noun your domain.

i.e. a schema for the hash maps that are of the right shape for login, session, account-trigger, email, basket, and order to use my example above.

FWIW, in Haskell, these might be modelled:

logIn :: LogIn -> Session
triggerEmail :: AccountTrigger -> Email
placeOrder :: Basket -> Order


Two of these involve side-effects, so I probably should have chosen examples without that complication, but let’s side-step that for now.

I think the schema-based example is interesting though - because there are points in a system where access is the most important interface, e.g.

That’s where you leave a system boundary (side effects!) so the types and DDD in this manner can’t save you… but schemas can, because that’s contract-based testing on read.

Thus it’s an interesting thought exercise to ponder if for example, REST is harder to reconcile with a pragmatic DDD approach than GraphQL.

[0] Mostly.

[1] Okay, I.

[2] Okay, write.

Fork me on GitHub