Some weeks ago I started to read the famous book written by Eric Evans, "Domain-Driven Design: Tackling Complexity in the Heart of Software". I'm planning to write a few posts to synthesize it and put the concepts that I liked the most in an easy and friendly way. As the famous quote says, the best way to learn is to teach, so I'm doing this as an excercise to retain and internalize knowledge, but hopefully it will also help someone that is reading the book as well. I also invite you to share your thoughts in the discussion section!
In this first part I'll focus on explaining the Domain-Driven Design mindset, which is the core that needs to be understood by the people who want to apply the principles in their daily basis, and start programming using this approach.
First of all, the main requirement for anyone planning to work using DDD is to be willing to collaborate as one team and one brain. This means that there can't be a separation between domain experts (this is, business experts, product owners… you name it) and developers (engineers, architects…). This close relationship will make developers understand business and business understand developers. Think about it, we as developers are very comfortable talking about classes, patterns and architectural elements… but domain experts normally don't understand these concepts, as well as we don't usually tend to care about the business rules, requirements, corner use cases and so on.
The idea is that together, domain experts and developers can come to a final situation in which they speak the same language. Through several brainstormings, talks, reviews and refinements, the domain model will start to emerge using this common language (aka "ubiquitous language", in words of Eric Evans). For example, a developer will understand what a "cargo shipment" is, or a "VIP customer", or a "health insurance", etc; for that company and their business colleagues. In addition, a domain expert will start to understand the relationships that developer is creating across classes, and what these classes do mean.
With several iterations, domain experts and developers should refine the model, continuously learning, filling gaps and fixing contradictions, working as one unit.
The model is like the skeleton, structure or backbone that gives shape to the common language that has been created by domain experts and developers. It can be done using different tools, like UML diagrams that represent classes, rules, operations, interactions, relationships… but we should take into account that the most important thing is the language and the expresiveness of the model. If something is not understandable through UML, use explanatory or auxiliary diagrams, use text, drawings… anything that supports and enriches the model and is supported by the language.
As we need to finally implement the model, the design of the solution has to be bounded with it. This means, any change to the model should be reflected in the design (and supported by the language!) and viceversa.
This implementation has to be doable, of course. Therefore, models must be practical (no hundreds of thousands of classes, please), and if we want the solutions and systems to last, the developers and domain experts should continue working closely throughout all the project lifecycle.
In terms of architecture, it's crucial to isolate the domain in its own layer, no matter which type of architecture we choose. For example, it's common to feel the temptation of including business logic in UI. Wrong! Spreading the business logic across layers will make the solution hard to mantain and hard to understand. If we make a change to the business logic, we want to impact the less possible layers and components in our architecture.
In his book, Eric Evans talks about the following layered architecture as reference, from top to bottom:
- UI layer: Shows info to the users and interprets commands.
- Application layer: Defines jobs and coordinates tasks, but doesn't contain business logic.
- Domain layer: Represents the business logic. Remember, isolated!
- Infrastructure layer: Provides technical capabilities for the upper layers. For example, database configurations, transactions, caches...
And one important aspect of the development process is that we tend to use frameworks a lot. So we need to take into account that we should use frameworks that allow to put the focus in the domain model, and most important, to isolate it.
In following parts of this series about DDD I'll explore the implementation details, how we can express this model through several elements, such as entities, value objects, services, modules and more.