As a developer, you may think that your job is to write code. However, Software development is not a product pipeline. If all developers just simply add new features and don’t care about design, software development and maintenance will become more and more complicated. A developer’s job is to solve a problem through software, and coding is just one aspect of software development. Good design and communication are just as important.
Domain driven design(or DDD) is such approach focused on clear communication and shared domain knowledge.
The importance of the shared model knowledge
Before attempting to solve a problem it’s important that we understand the problem correctly. Obviously, if our understanding of the problem is incomplete or distorted, then we won’t to be able to provide a useful solution. And sadly, of course, it’s the developers’ understanding, not the domain experts’s understanding. that gets released to production.
What if the domain experts,the development team, other stakeholders share the same model? In this case there is no translation from the domain expert’s requirements to the code. The code is designed to reflect the shared model directly.
The benefits of this approach can be:
- Faster time to market
- More business value
- Less waste
- Easier maintenance and evolution
Understanding the Domain through business events
A DDD approach to gathering requirements will emphasize building a shared understanding between developers and domain experts.
How to do that? Business logic is not static, it’s a process of transformation, so understanding how it changes is a good starting point. the transformation point of the process is also called domain event. For example “the order submitted” is a domain event will kick off the order selling process.
Use Event storming to discover the domain
There are a number of ways to discover events in a domain, but one that is particularly suitable for a DDD approach is Event Storming, which is a collaborative process for discovering business events and their associated workflows. TW Xi’an team did several workshops for Event Storming in the past days.
Partitioning the Domain into Subdomains
After Event storming we have a good understanding of what the various business processes are. But the big picture is still quite chaotic. The next step is partitioning the problem domain into smaller subdomains When faced with a large problem, it’s natural to break it into smaller components that can be addressed separately.
We have a large problem: Selling domain, Can we break it into smaller pieces?
Yes, we can. We can split it to various aspects of the Order, Charge, Authentication, Availability …, We will call each of these areas a domain.
Creating a solution Using Bounded contexts
Understanding the problem doesn’t mean that building a solution is easy. The solution can’t possibly represent all the information in the original domain. We should only capture the information that is relevant to solving a particular problem. Everything else is irrelevant.
We therefore need to create a distinction between a “problem space” and a “solution space” and they must be treated as two different things. To build the solution we will create a model for the problem domain, extracting only the aspects of the domain that are relevant and then re-creating them in our solution space as bounded context.
1. Why context
Because each context represents some specialized knowledge in the solution. Within the context, we share a common language and the design is coherent and unified.
2. Why bounded
In the real world, domains have fuzzy boundaries, but in the world of software we want to reduce coupling between separate subsystems so that they can evolve independently.
Creating a ubiquitous language
The set of concepts and vocabulary that is shared between everyone on the team is called the Ubiquitous Language. This is the language that defines the shared model for the business domain. The language should used everywhere in the project, not just in the requirements but in the design, and most importantly, in the source code.
Finally, it’s important to realize that you often cannot have a single Ubiquitous language that covers all domains and contexts.
We called User in Authentication domain but called Customer in Order domain.
Domain modeling
We have now got a basic understanding of Domain, but how to document them?
we should use visual diagrams, but these are often hard to work with and not detailed enough to capture some of the subtleties of the domain.
If you have a lot of database experience, your first instinct might be think about tables and the relationships between them. You might envision a Order table, an order line table, and Customer, Contact tables. And then you’ll probably want to describe the relationships between them by foreign key, But if you do this, you are making a mistake. In DDD we let the domain drive the design, not a database schema.
In DDD terminology this step called Domain modeling, For developer we should use code to modeling these domains.
Other concepts
As you know DDD is a large topic, We can not describe all the concepts in here. But you should understand that the core idea of DDD is using code to create a business model that can be shared with domain experts.
Other concepts like Entity, ValueObject, AggregateRoot, CQRS, EventSourcing, MicroService etc require you constantly practice to understand.
Layered architecture
For implementing DDD, we need to design our architecture to achieve this goal. The reason we will split whole system into multiple layers is Separation of Concerns and Single Responsibility Principle. The general idea is that we split persistence, rendering api and application logic to different layers and let developers focus on design and writing domain logic.
Domain Layer
We have the domain layer and business logic at the center, The domain layer will contain enterprise business logic and types.
Application Layer
Contains application logic and types.
The difference between Domain layer and application layers is Domain layer can be invoked by application layer, But domain layer don't know application layer.
Infrastructure Layer
Focus on persistence by database or api
Invert of Control
We don't want to let business logic to be dependent on concerns such as infrastructure and persistence so we invert these dependencies, so infrastructure, persistence and presentation all take a dependency on that center area.
The way we did is we added our abstraction and interfaces inside the core and then infrastructure and persistence implement those abstractions. For example, for persistence, if we were creating a repository there, there would be an IRepository used in the core and in persistence we will implement that IRepository. The result of this design is domain layer doesn't have any dependency on anything, We will got below benefit:
- It's highly testable, We can actually test the core without UI
- It's independent of persistence, whatever you persist data by database or api
- Independent of external system