Functional Programming and Domain Driven Design

I was in a meeting full of senior engineers a few months ago, and we were discussing the state of our Javascript which lead to the topic of Functional Programming.  I mentioned that I thought we were spending a lot of time writing packages of functions that were fairly composable, but we were having trouble reducing duplication because our code was organized by project, specific to the problem being solved at any given time, with no concept of problem domains.  I suggested we apply the principals of Domain-Driven Design to raise the level of abstraction and reduce duplication.

Unanimous laughter followed.  Buried inside the laughter was the comment, "DDD?  What is this, 2008?"

I assumed that I was missing something and that the concepts of DDD were incompatible with FP because all of the core "things" described in DDD have the word "object" in their name.  But, while DDD as described by Eric Evans is implemented in an Object Oriented language in his book, it isn't implied by the fundamental approach.

Then, I stumbled on this video which hypothesizes that DDD is even better with FP.  The speaker asserts that there isn't any reason Functional Programs can't also contain a "ubiquitous language", "bounded contexts", etc.




He doesn't exactly prove the hypothesis.  But I assert that DDD, by my definition, is compatible with FP.  So, below is my attempt to map each DDD buzzword to something that is easy to implement in a Functional program.

Value Objects - Immutable Values are all Value Object in FP.
Entities - Giving a Value Object a specific ID makes it an Entity.  Easy in FP.
Aggregate - A collection.  Functional program is full of these.
Aggregate Root - A function that maps over an Aggregate.  I suppose we can use types to protect our Aggregates from external mutation, but this wouldn't be a necessary if we kept all of our data immutable.
Domain Event - Fans of Big Data will likely find the concept of mapping and reducing over raw data, a very Functional idiom.
Service - Functions that operate on data could be considered services.
Repository - In the process of isolating non-pure database access from pure functional code, programmers often use some sort of repository pattern to abstract the database access behind a composable API.

What does this mean? It means that we OO expats, shouldn't throw out everything we were doing to organize our domain.  We should be taking the most important and useful OO tools with us as we assimilate into our new FP world and only deviate once we have proven a superior idiom is available to solve our problems.

7 comments

  1. Moving to FP and throwing out DDD is throwing the baby out with the bathwater. It actually really dovetails nicely into the Free Monad + Interpreter pattern.

    ReplyDelete
  2. Immutable types may be protected from external protection, but giving external clients visibility into the inner structure of my aggregate still introduces coupling, which can be avoided with OO encapsulation.

    ReplyDelete
  3. There are patterns in FP that accomplish the same single interface to a complex domain model. Lenses, for example, solve many of the same problem fairly elegantly. But, I don't believe that there is a single concept in FP that solves the suite of problems aggregates in DDD attempt to solve. What kind of coupling are you attempting to avoid?

    ReplyDelete
  4. How do you prevent anemic domain model by combining FP and DDD?

    ReplyDelete
    Replies
    1. It depends on what you mean by "anemic domain modal" and which FP language you are using. Really, the problem people are trying to avoid is the loss of encapsulation that occurs when raw objects are being passed around in an OO system. So, if you have a way to achieve data encapsulation, you have a way to avoid an anemic domain model.
      Clojure can combine data and functions into a namespace that exports only the parts of the namespace that are safe for outside consumption. Doing this creates an abstraction that can be safe from the problems caused by the anemic domain model. Here's an example https://www.braveclojure.com/organization/

      Delete
  5. Why is it that aggregates are considered as collections? Isn't it an encapsulation of the transaction?

    ReplyDelete
  6. First, what is an Aggregate : https://martinfowler.com/bliki/DDD_Aggregate.html

    I'm not sure if aggregates have anything to do with transactions except for the fact that saving an aggregate to a database would typically create several insert/update statements one would want to enclose in a transaction.

    As for why they might be considered collections in FP - when data and the functions that operate on that data are kept separate, then what's left of an Aggregate is just a collection of domain objects that the Aggregate aggregates. The functions that operate on that collection would still be part of the Aggregate of course.

    ReplyDelete