In this new entry, we will provide an introduction to Domain-Driven Design, where we will explore what it is and why we should use it. However, this model or design has much more depth to delve into, so I recommend reading or at least taking a look at the book “Tackling Complexity in the Heart of Software” by Eric Evans.
Domain-Driven Design aims primarily to ensure that the software we are developing or implementing reflects the real-world system we are trying to build.
Within DDD, we can define a domain as a unit of knowledge around which the business logic or enterprise logic that we want to implement revolves.
We could say that the Domain is the fundamental unit around which all our development will revolve, serving as the core of our application.
This article has been created by taking into account Eric Evans’ book and personal experience in applying this model.
The goal of applying DDD and what it is
We could say, although it may seem very obvious, that the main goal of applying DDD or Domain Driven Design is to isolate the code that belongs to the domain from the technical implementation details. This way, we can treat them independently and focus on the complexity of each.
If we aim for domain-driven development, it’s important to have a team that is aware of and prepared for this type of development. On one hand, we’ll need domain experts, and on the other hand, developers who will be part of the technical side.
In a traditional system, there might be an analyst who communicates with the business team, and the needs are then transferred to the development team, who are solely responsible for the programming part. This traditional approach often led to problems like missing information, lack of understanding, or developers having to make implementation decisions due to a lack of business knowledge.
That’s why this approach seeks to increase interaction between programmers and the business team. This way, a better understanding is achieved, and both parties can be more actively involved. For example, Eric Evans, in his book on DDD, defines “Ubiquitous Language” to create a standardized way of communication between the development and business teams, making information flow more smoothly.
All of the above involves a learning curve and increased project costs, at least initially. But in the long run, it results in reduced costs and more reliable software with greater testing capabilities for the domains being created.
It’s important to note that teams typically apply this approach to somewhat complex and large-scale development projects, where new functionalities may emerge, or to legacy systems when migrating them to other technologies. This facilitates the creation of new components that can interact with each other in an ever-evolving system.
Core Principles of DDD
We could say that domain-driven design focuses on three fundamental pillars:
- Focusing on the core domain and business logic.
- Transforming intricate designs into domain models.
- Continuous interaction and collaboration with domain experts, which helps resolve doubts and enhances engagement with the development team.
Common Terms in DDD
In DDD, we define several common terms as follows:
- Context: The setting in which a word or statement appears that determines its meaning. Statements about a model can only be understood in a context.
- Model: A model is an abstraction of a system that describes aspects of a domain.
- Ubiquitous Language: A structured and defined language for a domain model that is used and understood by all team members.
- Bounded Context: A Bounded Context defines the description of a boundary within which a specific model is defined and applied. It is typically associated with a specific team or subsystem.
Structure of Domain-Driven Design
When working with DDD, there are three aspects to consider:
- Separation of responsibilities in layers: Isolating the domain.
- Modeling and defining the domain model.
- Managing the lifecycle of domain objects.
Separation of Responsibilities in Layers: Isolating the Domain
As mentioned earlier, DDD focuses on separating the model from the development. To achieve this, it’s necessary to isolate the domain and organize it into layers that are readable and understandable.
We can achieve this division by following the following layered structure:
- Presentation.
- Application.
- Domain.
- Infrastructure.
DDD domain model
An architecture that could fit perfectly with this solution and aligns well with DDD is the hexagonal architecture or ports and adapters architecture.
Presentation layer
Display information to the user.
Application
This layer defines the use cases that translate into software. It keeps them as simple as possible and delegates the tasks of the domain objects to the next layer.
Domain
The domain layer will be responsible for representing business concepts, as well as specific rules and situations.
It is important to note that this layer is the core of the business.
Infrastructure
This layer enables interaction between the four layers through a framework. It is where the technical aspects of the application reside.
Modeling and defining the model
The definition of the model consists of being able to describe all the domain knowledge with structures and concepts that will help implement it to better understand the domain and discuss it.
What needs to be clear is that the domain helps define functions and make a representation of real-life knowledge.
One of the techniques that usually helps with model representation is the use of Ubiquitous Language. This way, both developers and business people can understand it.
At this point, interaction with domain experts is very important; both they and the development team must be very involved. Any change in the model will affect development, so the use of diagrams and a common language will be key to the project’s success.
To define a model, we will use three different tools:
- Value Objects
- Entities
- Services
Value objects
These objects define functionalities and have meaning. People often pass them as parameters in messages between objects, and they typically create them temporarily for some operation and then discard them.
Entities
An entity is an object primarily defined by its identity rather than specific attributes. Typically, an entity will have a unique identifier that sets it apart from a value object.
Services
In those cases where you need to perform an operation that doesn’t belong to a specific object, you can create a service in the model.
Managing the lifecycle of Domain objects
In domain-driven development, a key goal is to shield the model from the application’s lifecycle. Es por este motivo que separamos la lógica del negocio con el ciclo de vida.
When we separate business logic from lifecycle, two new concepts emerge: aggregates and repositories.
Aggregates: A set of entities and value objects that make sense at the domain level and are created and persisted together They encapsulate structures within the model.
Repositories: They provide an interface to add and persist aggregates. The repository communicates and connects to the database in a way that hides domain details from the database. In the domain layer, we create interfaces, but the database communication logic resides in the infrastructure layer. With this approach, using interfaces, we can make changes in the persistence layer without affecting the model or business logic.
Conclusión
As we have seen in this introduction to Domain-Driven Design – DDD, this model will assist us in building our software architectures, although with a learning curve that can sometimes be challenging, the reward is worth it.
Domain-Driven Design could fill many more articles, and you could delve much deeper, so I recommend Eric Evans’ book, ‘Implementing Domain-Driven Design,’ or ‘Tackling Complexity in the Heart of Software.