DDD Model Integrity Patterns

Figure 1: A navigation map for model integrity patterns [1]

Strategic Design

Domain-Driven Design (DDD) tackles software complexity at different levels. Strategic design is the subset of DDD that operates at a higher level. Its main goal is to help dealing with large models, and its challenge is to achieve modularity without compromising the benefits of integrating different business operations. Because in large systems such design decisions must be negotiated between teams, strategic design does not take into account only technical considerations, but it often becomes the intersection between design and politics.

Defining explicit context boundaries is not only one of the essential aspects of DDD, but also, along with core domain distillation and large-scale structures, one of the keystones of strategic design. While it is theoretically possible to have a single, consistent model for the whole enterprise, this approach is rather complex and generally impractical. Therefore, letting each team develop its own models and explicitly limiting their applicability is the viable way to go. This pattern is commonly known as bounded context.

Bounded Context

A bounded context sets explicit boundaries in terms of team organization, code base, database schema and so on. In different contexts, different concepts, rules and terminology may be used. This helps in reducing cognitive load and avoiding confusion when shifting attention from one context to another. Furthermore, the correct split of the enterprise system in bounded contexts is fundamental to maintaining model integrity. A bad split of contexts, mixing up elements of distinct models, may cause two kinds of problems:

  • Duplication of concepts: When there are two model elements (and corresponding implementations) that represent the same concept.

Even though bounded contexts do contribute to modularity, this pattern differs from modules/packages. Objects from different bounded contexts will indeed be placed in different modules, but a single bounded context will also be composed of multiple modules, which will help organize the elements within that model.

Continuous Integration

Decoupling distinct models is necessary but not sufficient. Still there will be multiple people working in the same context, which might produce clashing understandings of the same model. In order to ensure consistency within a single context, applying the well-known process of continuous integration can be of great help. Domain-driven continuous integration implies not only an integration of the implementation, using an automated merge/build/test pipeline, but also an integration of model concepts. Concepts can be integrated by the constant exercise of the ubiquitous language in discussions between team members about the model and the application.

Context Map

Maintaining integrity within a single model is also very important, but still not enough. Everyone in the project has to be aware of other contexts as well, and relationships between contexts must also be clear to everyone. That’s where the context map comes into play. The context map identifies every model in the project and defines their bounded contexts, naming each of them and making their names part of the ubiquitous language. The point of the context map is not to envision the ideal scenario, but to map the current situation of the project. Once you can see the actual situation, changes and improvements in the state of affairs will become clearer.

The context map can take many forms. It can be a diagram, a textual description or even a discussion between the team. The important thing is that it is shared and understood clearly by everyone.

Relationships between Bounded Contexts

Several patterns describe the relationships between bounded contexts and their models. Which one to use depends heavily on the situation and the needs present. Here is a list of some of the most relevant among these patterns:

  • Shared Kernel: When two teams agree to share part of the domain model, along with the corresponding design and code. The benefit of this approach is reducing duplication and facilitating the integration between the two subsystems, but the price to pay is increased coupling, because the shared kernel cannot be changed so freely, since such changes affects both teams and have to be discussed and decided together.

Conclusion

Maintaining model integrity is no easy task. Several patterns from DDD aim to achieve this goal, which is one of the main goals of strategic design. Whether it is maintaining integrity within a single bounded context through the application of continuous integration or between different contexts by explicitly limiting their applicability and establishing their relationships, these patterns and techniques help a great deal in keeping models pure, and therefore potent. Thus, take them into account when dealing with large models and systems. You are most likely already applying some of them. Understanding them and mapping them explicitly will certainly help you make better choices regarding your software and improve it continuously.

References

  1. Evans, Eric. Domain-Driven Design: Tackling Complexity in the Heart of Software.

Software Architect at ilegra