I never was comfortable with the idea of “complex domain”.
“Use DDD only in complex domain” is a mantra used by DDD experts to avoid the Silver Bullet Syndrom. It is really convenient to avoid uncomfortable discussion.
Why do I mind?
We’d like to know what is a complex domain to know when to use DDD.
From a strategic perspective, I already argued that we could always use it. The remaining question is: when should I use DDD from a tactical perspective? When should I implement hexagonal architecture, CQRS/ES and other fancy stuff like that?
Not in a CRUD software?
Whatever the implementation we choose, software is a business abstraction. When we choose a CRUD implementation, we bet the future software will have few features. We bet we won’t need many abstractions. The cognitive load due to the domain will stay low, implying we can mix business logic with technical terms, without building unmanageable software.
In my experience, lots of applications begun as simple CRUD, but they quickly evolved in something more complex and useful for the business. Unfortunately we keep coding them as simple CRUD, which results in a massive mess. Certainly not in purpose, adding just a bit of complexity day after day makes it hard to grab the whole complexity of the solution. We are the boiling frog.
The over-engineering theory
The challenge is to find at which point our simple CRUD application becomes a more complex line of business application.
My theory is that we consider patterns from tactical DDD over-engineering all the time. Because we are unable to feel the complexity of the software we are building day after day. Worse, we think that the knowledge we accumulate about this complexity makes us valuable as the dungeon master. We are deeply biased to sense our own work.
But what happens when we go working on another project? The will to rewrite the full software from scratch. Push the frog in hot water, and she won’t stay for long.
Looking for the inflection point
We’d like to find when it becomes interesting to implement tactical DDD patterns, despite the cost it has.
A part of the solution may be to check how long a new comer needs to be productive. When it is too long, there is room for improvement, and tactical patterns can help to decrease the code complexity.
Another solution may be to ask for a few audits by different DDD experts, but it could be more expensive.
A simpler solution may be to assume that the software will become more complex. It implies we should look at which tactical pattern can fit our needs, day after day.
Remember there is a world of practices in tactical DDD patterns. Using all of them all the time is not desirable. Picking the good one at the good time is the actual difficulty.
When should I use tactical DDD patterns?
I do not have a definitive answer for that, just an empirical observation: I’ve seen countless software implemented in a CRUD way that would be greatly improved by a DDD tactical approach. I’ve seen no software implemented with a tactical DDD approach that would be greatly improved by a CRUD implementation.
“If you think good design is expensive, you should look at the cost of bad design.” -Dr. Ralf Speth, CEO Jaguar
4 thoughts on “The over-engineering theory”
Nice one. The boiling frog analogy is particularly insightful.
As a result of Distillation, I’ve often found a strong link between generic and supporting subdomains and genuine CRUD candidates. Things like reference data administration, category management, identity, authentication or authorization subdomains can legitimately be implemented as CRUD since they’re basically about putting data into more or less structured boxes. Not a lot of domain invariants or processes to be found there.
At the end of the day, aren’t the applications you mention Core Domain in disguise that we failed to identify? How could a Generic Subdomain possibly slide towards Core Domain over time?
My gut feeling is that Distillation done right should avoid most of these bad CRUD choices – and that the mess-ups you mention are due to teams that were not fully proficient with DDD or skipped that analysis step altogether. But I might be wrong. Do you have concrete examples of apps that were sincere CRUDs at first but have “boiled” to the point of deserving full fledged tactical DDD treatment?
“My gut feeling is that Distillation done right should avoid most of these bad CRUD choices – and that the mess-ups you mention are due to teams that were not fully proficient with DDD or skipped that analysis step altogether.”
You’re absolutely right. This is most of the time the result of a bad, or lack of DDD analysis. Full ACK also for the link between generic and supporting subdomains and CRUD candidates. But even for a core domain, it could make sense to start with a quick and dirty CRUD implementation to challenge some business assumption. Or business and techs can agree that the domain looks simple enough to be managed with a CRUD implementation.
“Do you have concrete examples of apps that were sincere CRUDs at first but have “boiled” to the point of deserving full fledged tactical DDD treatment?”
A lot, but a real life talk would be better to explain the different experiences, usually meet as a trainer or consultant. One of the trick imho is that, when asking to the business, they often feel that their needs are really basics. The challenge is then implementing what they need, not what they want, which is not a trivial exercise.
Super definitive article,
Articulates the problem since I wasn’t really expressive verbally. Would be a good base in my arguments.
I attend to a team that strongly applies DDD approach to any nail is in the zone. To be honest after exposed by that for a period of time, I even started to question my standing point… Why the hell of a reason complicating the stuff by complexity that isn’t there. I’ve just seen blurring the air with buzz words just to name it properly and iterate in “every small requirement change” then propogate all around the code all those changes, which supposed to be a small microservice by definition. Deletion of massive amount of code written just a sprint before, layers of abstraction that doesn’t have any functional benefits but just to convince this is a high level style code written. Complicating for the sake of a recognition as a code philosopher
I don’t see that much of a point to start to a fresh project with all DDD practices at all, many of the fresh project doesn’t mature enough to even talk about domain.
Following is a very sweet point regarding to my frustration.
I’ve seen countless software implemented in a CRUD way that would be greatly improved by a DDD tactical approach. I’ve seen no software implemented with a tactical DDD approach that would be greatly improved by a CRUD implementation.
“I don’t see that much of a point to start to a fresh project with all DDD practices at all, many of the fresh project doesn’t mature enough to even talk about domain.”
I think this is really important, and actually explain why we always feel that we arrive “late” to fix the mess.
These different phases (learning what is the problem VS implementing a core domain) are not clear for many programmers, and even less for business people.