Photo by Trent Erwin on Unsplash
Lately I’ve been fascinated by the idea of domain driven design. Before diving more deeply into it we must understand the concepts that are being used.
Each object should be uniquely identified. The entity should contain those attributes that are required in order to uniquely identify the object. For example for a Car the model it’s not identifying the Car uniquely, so it’s not a good fit. Instead you can use the vehicle identification number(VIN). These attributes can be defined by user or delegate this responsibility to the application or 3rd party tools. Besides this it contains the behavior. For example you can change the car’s license plate numbers. We also make sure the license plates are valid (eg respecting a certain pattern). Validation must be included here.
These should be immutable. They are used for measuring or describing something in the domain. For example, our car has a price. How can we represent this value. Well we know it has a number and a currency. So instead of keeping two properties we bundle them together in a value object. They can be used as collaborators between multiple value objects. Out car has a constructor, so it has a reference(value object) to it called maybe ContructorId which holds the information for uniquely identifying a constructor.
In a nutshell these are a cluster of entities and value objects. The problem that we face here is the size of the aggregate. As a rule of thumb we must design small agregates, or else we lose control. Even if this comes with an increase in complexity(eg lose ACID for BASE) we win in terms of performance and scalability. And we have solutions to this kind of problems like CQRS and Sagas. An aggregate root is the gateway through which the cluster communicates with external components.
Well all those aggregates must communicate with each other. They achieve this by encapsulating business into domain services. These services reside only inside the domain. They have no external dependencies.
If there is a need to persist some data probably you need some kind of storage. The repository pattern can be used here. The repositories should use only aggregates. More importantly they should be an interface. No implementation details should be present here.
These objects need to be created someway. The most common way is through constructors, but we need also to create also their dependencies. Factories are more appropriate. Their sole purpose is to create objects, they are part of the domain but have no other responsibilities.
The Ubiquitous Language
This is the domain language. It is created by the domain experts and the requirements. It is a very specific and only understood by the people who are knowledgeable of the domain. For example if we are talking about cars we can say the following phrase: “
“The term internal combustion engine usually refers to an engine in which combustion is intermittent, such as the more familiar four-stroke and two-stroke piston engines, along with variants, such as the six-stroke piston engine and the Wankel rotary engine.”
and the people who activate in this domain will understand it.
The domain must be grouped into smaller modules. Determining the boundaries of a domain it’s a tricky thing to achieve. We must take the domain models that we have and group them in context. Be careful and not confuse this with entity pattern. If more than one domain models are creating a cluster then it makes sense to group them in the same context. That way we created a boundary. Usually we have more than one bounded contexts, so it’s imperative that they can communicate. In order to achieve this we have patterns at our disposal: event-driven design, CQRS.