Domain Driven Design: My Reading Notes
- Facing a new system/project, usually the expertise is fragmented and spread all over different documents and the minds of different people, like puzzles.
- At first, we don’t know “what we don’t know”, and such ignorance usually lead us to wrong estimations.
What to do:
- [Action] Cultivate a common language so the 2 groups of people, engineers and domain experts, can increase mutual understandings and shape the model together.
- [Action] Distilling the model: Start from a naive model. During the iterations, abandon the unimportant or unfit parts and make new ones.
- [Principle] Do not separate the ones who create models and the ones who write codes. Let people do both. Otherwise, (1) the intent of the model may be lost during the implementation; (2) the modeler will not sense the performance issues (or other system issues) directly.
- [Principle] Use layered architecture. Extract a domain layer to achieve “separation of concerns”. So that, (1) later changes of UI won’t affect domain layer logic; (2) people can “read” domain knowledge in the same place, instead of spreading all over different components.
- [Principle] Make micro-refactorings one at a time. Don’t seek for giant step, because a big refactoring causes a big impact to the system and the schedule. Instead, use small steps to accumulate deeper domain knowledge, and prepare for a breakthrough idea to come at some point. When it comes, find a proper timing in the project lifecycle to implement it. Chapter 8 provides a very expressive example.
- [Principle] Intention-revealing interfaces: The name of a function or a module should explicitly reveal its role and design intention. So that the later joining developer will not mis-use it and introduce a different intention into the code.
- [Principle] Make side-effect-free functions: Separate command (setters) and query (getters).
- [Principle] In most cases, we build systems that will leverage existing legacy systems. When interfacing with legacy systems, the obvious effort is in the infrastructure layer: the other system may have different data types or protocols, and those are easy to notice. A common mistake is we usually neglect the differences in the domain layer, that the other system probably has a different model. For example, the same terminology in 2 different systems may refer to similar objects with different constraints.=> Use an anticorruption layer to translate the models between systems.
Some key elements in a model:
- Entity: an object that we care about its identity.
- Value object: an object that we don’t care about its identity.
Some patterns used to manage domain objects’ lifecycles:
- Aggregate: contains an entity as root, and the boundary to define which objects are included.
- Factory: When an aggregate is too complicated, use Factory pattern to encapsulate its construction.
- Repository: stores the objects/aggregates (created either by Factory or by simple constructor), and let users to find them through associations.