In the statically typed functional programming community, and especially so in the Scala community, there seems to be a trend towards more and more abstractions. Some of the abstractions people are particularly crazy about have been formalized in category theory. It is easy to be excited about those abstractions, and about finding them in your program: “Oh, this here is actually a functor! Let’s abstract!”
These abstractions have their virtue, but they are not without problems, and I think they are often applied prematurely, wherever it seems possible. In this post, I want to focus on one such problem I see when you combine this approach with domain-driven design: Using abstractions from category theory in your domain model is at odds with one of the core principles of DDD: the ubiquitous language. The ubiquitous language is all about having a common language between domain experts and developers. In fact, it should be so ubiquitous that it’s used not only for communication between developers and domain experts, but is also reflected in the code that makes up your domain model.
Are Semigroup
, Monoid
, Monad
, Functor
, Kleisli
, and Yoneda
pervasive in your domain model? Unless your core domain is mathematics, category theory is not the language used by your domain experts. You may discover that an abstraction can be applied to your domain model. Good luck getting your domain experts to understand the language introduced by that abstraction, let alone talk in that language. I have often seen a big disconnect between the overly abstract language of math and that of the actual domain.
If you are serious about the ubiquitous language — and you have to be if you want to be serious about domain-driven design — strive to keep such abstractions to a minimum in your domain model. What you do outside of your domain model is a totally different story.