The first project I plan to undertake is creating an architecture with a functional domain model. By ‘functional’ I mean using the functional programming paradigm, i.e. focusing on expressions rather than instructions.
The (long) rationale
In my career, where there has been an architecture at all, it has tended to be some form of object oriented domain model. In such a model each domain concept (I’m avoiding saying entity due to it’s Domain Driven Design implications) is represented by a class that exposes all its properties, a collection of get/find methods, save method, and some advanced manipulation that reflects more complex business rules. Eventually someone realizes that a given class is getting too complex and creates a separate service for that behavior. And so we end up with a set of heavily intertwined classes representing some combination of data and operations that is appropriate to the business domain.
I find this approach troubling for many reasons.
Firstly, regardless of the original intentions of the architect, these classes always end up getting big. By big I mean that the combination of possible states of the class’s fields makes it hard to reason about what will happen when a change is made in the class. This means that developers are left relying on unit tests (should they even cover the area of concern) to ensure the integrity of changes. I’m not disputing the value of tests, but I believe that better outcomes can be achieved by understanding the code and therefore being able to simplify it, rather that just painting on another method. Simplification means less code and that is better for maintenance, while code that can’t be understood can’t be maintained and is therefore technical debt.
Basically the class fields start to exhibit all the failings of global variables.
Secondly, it isn’t cohesive. A class with high cohesion is one with as few responsibilities as possible. These classes are responsible for reading data, writing data, and performing many different operations, which makes them very non-cohesive. It strikes a nerve with me that people are happy to violate cohesion by putting reading and writing code into the same class when they are such different operations: writing deals with validation, consistency, error handling; while reading deals with filtering, paging, caching; and beyond that we still have business rules and operations that act across classes.
So I believe that reading and writing classes should be separate, despite the vitriolic sentiments of the OO community calling this approach ‘anemic’.
A third issue is one I mentioned earlier: when should operations be moved from the concept classes into their own one? There simply isn’t a good line, and this is a problem because although it might seem obvious to the architect by virtue of their experience, it won’t to an intermediate developer, and so the code will go into the concept class it make it more unwieldy and less cohesive. Additionally, if the operation is moved into another class, can it access all the data it needs, or is that hidden within concept class?
Finally there is testability. Establishing all the states of the object necessary to thoroughly test is hard, especially when some of the fields are private.
I’m told it’s important to break-up lots of text to help people pause and regroup while reading, so here is a random picture of a plane that I took years ago.
So what’s my suggestion?
If we take the concept class and split the reading and writing functionality into two classes, then all the data needs to be accessible to both classes, necessitating the creation of a data class, a.k.a. the DTO.
At this point I imagine OO proponents yelling “information hiding” at me (largely because some have), but the reality of the systems I’ve worked with is there is seldom any information that is hidden (let alone needs to be hidden) behind complex methods, and where the data needs manipulation to match the repository format, simple property accessors are fine.
Given we are in the world of web development and objects are usually created for a specific request, there seems very little value in keeping state because it probably won’t change anyway. This raises the question: why allow the state to be changed at all? If the state is probably going to be fixed from the moment the object is created, either from data submitted by the user or via repository access, then let’s enforce that by making the state immutable. Now we get all the benefits of immutability, like thread safety, and a clear ability to understand the object because anytime we perform an operation to it or with it we will get the same result.
The end result is a functional domain model, where data is held in an immutable object, and operations are expressed by functions acting on that data.
Given my background is with .NET I’ve decided to do this using F#. To that end I’m presently making my way through Expert F# 4.0 by Syme, Granicz and Cisternino. I’m also hoping to using ASP.NET Core for this, to become more familiar with that.
I’m going to create a basic asset management system to illustrate this. One of the products on worked on around 9 years ago was an asset management system, so the domain for this will draw on what I can vaguely remember from then. The next post will introduce this problem domain.
It will likely be some time before I’m ready to tackle the meat of the project, but before then I’ll try to go into more detail on the problem domain, and get setup with ASP.NET Core in F#.