I've just finished reading The Book about Domain-Driven Design by Eric Evans, finally!. After spending a lot of time reading second-hand about it, my conclusion is: DDD is not exactly what they told us.
For some reason, the references I had heard about the book were quite negative. And it's a shame because I've been postponing reading it more than I should, although it's also true that I have prioritized others that I had more accessible. But, in summary, I liked the book a lot and the content has helped me make sense of many things.
In part, I can understand the "negative" vision of the book since it is not the typical technical book.
Let's start here, the Blue Book of DDD is not a book that gives you recipes about how to implement things but is mainly about how to think and how to talk about the domain, the problem space, and how to start and develop a model as a solution space. However, it is an eminently practical book that offers a system for analysis and design, structured on topics for which it offers a full range of strategies and patterns of action.
As the subtitle says, Domain-Driven Design is about how to tackle complexity in the heart of software
Throughout the book, you will find very little code, just a few examples to illustrate some points, but many diagrams to see how models are presented for different cases and how they can evolve in the face of domain changes. Also, it includes a good sample of conversations and a lot of contexts to understand the examples that illustrate the different topics.
Because DDD is mainly about: conversations, contexts, and models to understand the domain problem and to be able to develop a solution.
However, it is usual to talk about DDD associated with specific technologies or implementations, such as microservices, CQRS, event sourcing, or hexagonal architecture, as if one implied the others. It is also common to insist on the tactical pattern, those that have to do with implementation, and no strategic ones, those that have to do with design, which is what the Blue Book is about.
So, I'd say that the Red Book,Implementing Domain-Driven Design, the book by Vaughn Vernon, is way more popular and known. I understand that this is because it is the one that explains how to do that, that is, the one that deals with tactical patterns. The recipe book, so to speak. I did not read the entire Red Book, but for now, I have been using it as a reference for a specific topic, but many people have read this and not Evans and I think it is a mistake.
In addition, Vaughn Vernon himself later published the Green Book, Domain Driven Design Distilled that some people consider as a good introduction book to DDD. I disagree completely on this. Distilled is a good index for the Red Book, but you won't learn Domain-Driven Design with it.
Possibly a better introduction Evans' Domain-Driven Design Reference: Definitions and Pattern Summaries, whose existence I just found out because I'm that smart.
The insistence on tactical patterns does not cease to have its positive aspect. They are still good practices, but they are not exclusive to DDD, far from it. One of the most typical confusions is about mixing DDD and Hexagonal Architecture. What is usually known humorously as "directory driven development".
DDD and Hexagonal Architecture
Hexagonal Architecture and clean architectures, in general, are perfectly compatible with Domain-Driven Design. This is so for two reasons:
- Layer separation, with the domain at the center.
- Dependency rule, with all dependencies pointing inside, so the domain has no dependencies.
But, nothing is stating that Hexagonal Architecture IS the proper architecture of a DDD application. Hexagonal Architecture is an application of the Dependency Inversion Principle and its associated practices, rather than a proper architecture.
Anyway, we structure the core around three folders/layers: domain, application, and infrastructure. But this, by itself, is not DDD.
The reason for this to work is that DDD asks that the domain model will be represented in code by pure language objects, completely isolated from any technical detail such as persistence or networking. In the words, the so-called building blocks (entities, value objects, domain events, or services) cannot be designed thinking about how they will be persisted or communicated in an API, for example, but should be designed as if they were always living in memory.
But, as is quite evident, we need a mechanism of persistence of entities and aggregates, if only for pure technical necessity.
DDD and Databases
The concept in charge of persistence in DDD is the Repository, a place where to store and retrieve Entities (I'm going to talk about entities and aggregates indistinctly). From the domain point of view a Repository is simply memory storage, which allows me to:
- Store entities
- Retrieve entities, knowing their identities
- Get subsets of entities satisfying a specification
So, in an ideal world, the interface of a Repository only has three methods:
- store
- retrieve(id)
- findSatisfying(specification)
To be able to create implementation-independent Repositories we should apply the Inversion of Dependencies Principle, so we will have a RepositoryInterface at the domain layer, so we don't couple to the concrete persistence technology.
This is a good practice in general terms, not exclusive of DDD. What is characteristic in DDD is the concept of Repository as memory storage of entities, that can not maintain business rules or other invariants. The idea of a Repository with methods that are business rules is a bad practice.
In this sense, the Specification pattern, defined by Fowler and Evans, is the way to go.
DDD and noSQL
Always from the domain point of view, noSQL databases should be the best fit for the Repository concept. It is easy to serialize an entity as a document to persist it as a document and retrieve it given a key, no matter how complex it is.
Yes. There are a lot of technical and valid objections to this statement, such as those about performance, reliability, relation management problems at so on.
DDD and ORM
On the other hand, ORMs, from the same point of view, are poorly suited. Entities in the context of ORM are not DDD entities. Matthias Noback recommends forgetting about ORM when we are designing entities
because ORM inner working is going to interfere with the proper design.
In exchange, he recommends simplifying, even using private properties in entities with the unique goal of a database storing and even rebuilding objects from primitives on the fly.
All this is to keep rich DDD Entities and avoid the anemic models characteristic of database-first approaches.
DDD and CQRS
Command Query Responsibility Segregation is another of those patterns associated with DDD. In part, because it is also tightly related to Event Sourcing, something that makes sense by itself.
CQRS is the extreme application of the CQS (Command Query Segregation Principle) to data models.
CQS says that a function or method must be a command, which produces an effect in the system without getting information from it, or a query, which retrieves information from a system without modifying it, but not both.
In the repository interface that we talk about above, it is assumed that there is only one repository object managing both reading and writing, with each method having its responsibility.
Nevertheless, CQRS separates both operations of reading and writing in different models. So they can be implemented even with different technologies. Its "dark reverse" is consistency: how do we keep the information that is written consistent with what is read?
To resolve this, the notion of eventual consistency is introduced, which, explained very basically, means that the information will end up being consistent at some time when the process that updates the reading models has been able to make all the changes collected by the writing model.
One of the strategies to achieve this is precisely through events that indicate the changes so that the reading models are updated in response to those events.
But, CQRS is fundamentally a pattern of implementing a persistence solution that can work well for environments that require high performance, and that adds excessive complexity to a large majority of applications. Again, there is nothing in DDD that implies that CQRS is a proprietary pattern, although an application designed with DDD methodology can implement a CQRS persistence solution.
Event Sourcing and DDD
Event sourcing is an approach also frequently associated with CQRS and DDD. It should be due to we talk about Domain Event and an event is an event, is an event… Yes, this association makes a lot of sense, but Event Sourcing is not for a silver bullet and neither is a pattern derived from DDD. What is happening here is that it fits very well.
The idea of the Event Sourcing is as follows: In a traditional software system the state of the system, or specifically the state of an entity, such as a student's academic record, tells us about their status at the time of the consultation, but it does not tell us anything about how it has been reached, or if there has been any kind of change over a while. Traditionally, if we are interested in saving history, as in this case, it is explicitly saved. That is why the academic record keeps records of all the courses through which the student has passed.
Now, what happens if instead of updating the state every time there is a change, we collect all the events that change that state? Well, we can have Event Sourcing.
If we have the history of events, we can go through it, rewind it, start over from scratch and get the state of the system at any given time. If necessary, we can collect “snapshots” of that state at certain moments in history. Instead of having databases storing the information of each entity in tables, we can have an event store and generate specific projections for each view that we want to offer in our application, whether visual, API, or whatever.
It would be very neat to talk about the number of things that can be done with Event Sourcing, but imagine being able to rewind your system to a certain date or, change what you change in the software, your data can be automatically adapted because, in reality, you never saved it in the traditional sense.
But again, there is nothing in DDD that says Event Sourcing is a preferred or especially suitable pattern. It is another technological option at your disposal to implement your application. The caveat is that the concept of Domain Events makes Event Sourcing fit easily.
Microservices and DDD
If there has been a star term in recent times, it has been that of Microservices, which is neither new, nor implicit, nor particularly suitable for DDD.
Again, Microservices is a way of implementing a technological solution that, in this case, consists of creating very specialized applications (services), communicating through standardized protocols (typically REST API), with which to compose the software system.
Microservices have been in fashion in recent years. At first, as the paradigm that everyone seemed to want to join. However, difficulties in its implementation have led to lately being fashionable to talk about how microservices have not worked on many occasions.
Part of the association of DDD with microservices may come as a possible implementation for bounded contexts and the context map. In my opinion, it is one of those far-fetched relationships, possibly explaining much of the problems encountered in the implementation of projects based on microservices.
Rather, I think that microservices could arise naturally by identifying highly specialized and removable modules in a monolith, but through an iterative and evolutionary process.
To end
It is not DDD if the emphasis is on implementation and tactical patterns. That is only part of everything that DDD supposes. The keyword in DDD is the last D: Design.
DDD is about conversations, concepts, and models. In short, it's about the design.
Top comments (1)
I want to add a short comment about the DDD with ORM part. ORM entities can still be used with DDD approach; of course, we can't take the ORM as it is and put it in our domain! it requires a little more effort because it needs to be adapted. For my personal experience, it's worth it so you can use the potential offered by the ORM.
Anyway ... great post Fran!