Part I - Putting the Domain Model to Work
1 - Crunching Knowledge- Communication with Domain Experts is mandatory to accumulate domain knowledge.
- Initial conversations should revolve around an emerging language based on the model.
- Experimenting with different ideas about the model is important.
- Layers of feedback erode the details of the model, only business people and developers needed.
- Learning has to be continuous as the business changes and domain evolves.
2 - Communication and the Use of Language- Domain experts and developers need to speak the same language.
- The language of the model should be reflected in the code.
- Using the language will force model weaknesses into the open and reveal gaps to be - plugged.
- Model should be the backbone of the ubiquitous language, change in change means change in model.
- If experts don't understand the model there is something wrong with the model.
- Diagrams are useful but should be temporary and serve only communicate the present.
- Documents are useful if they add to the model.
3 - Binding Model and Implementation- Model driven design removes the separation of analysis models and design models by having a single model that fits both purposes and makes for a very relevant model.
- If a model does not faithfully express key domain concepts, a new model is needed.
- The model must support the ubiquitous language and start with the domain reflected in code in a very literal way that can be improved as deeper insight is gained. This way the code becomes an expression of the model.
- OOP is a great paradigm for expressing models as it inherently supports objects as opposed to procedural languages.
- It is usually a good idea not to try to hide the inner workings of the system from the user as it prevents the user understanding the model, which is usual of benefit to the user as they can reason about it and make predictions.
- The people involved in modelling need also to be taking part in crafting the code. There are subtle relationships in code carry important information about the model that are difficult to communicate verbally.
Part II - The Building Blocks of a Model-Driven Design
4 - Isolating the Domain- A layered architecture is the most appropriate when trying to employ DDD.
- The Domain layer is where the model lives.
- A separate domain layer allows a model to evolve to be rich and clear enough to capture business knowledge.
- Keeping it separate from infrastructure or UI concerns is imperative.
- Smart UI designs can be practical but are not sustainable long-term.
5 - A Model Expressed in Software- Entities require an identity so they can be uniquely referenced throughout their lifetime.
- Entity class definitions should be should be kept focussed on the lifestyle continuity and identity i.e. properties that make the class findable with intrinsic characteristics.
- Add behaviour to entities that is essential to the concept, move non essential attributes into other objects associated with the core entity.
- Value objects have no identity as it is not important to tell them apart.
- Objects without identities are more transient and can allow for better system performance without the burden of being identifiable. Applying identities where not needed also confuses the design.
- In value objects we only care about the attributes of the class and they should always be immutable - the value object should be replaced rather than manipulated, e.g. address.
- Value objects can be shared where it is acceptable in the model and of benefit to system resources but is difficult in distributed systems. Shared value objects must never be mutable.
- Services represent valid ways of capturing behaviour that do not belong to an object.
- It is easy to create a service and not apply to an object when it should be in an object but forcing behaviour into an object in which it doesn't belong can distort the model.
- Service operations should be part of the ubiquitous language.
- Services are stateless and have interfaces defined in terms of other domain elements e.g. a bank transfer service deals with other domain elements - money (value) & accounts (entities).
- Modules should be treated as fully fledged parts of the domain and organise objects.
- Code divided into modules means being divided into logical domain concepts. This helps coherent thinking about few topics at once and helps to reason about the system as a whole in terms of its modules.
- Modules should act as a communication mechanism and support the ubiquitous language by reflecting insight into the domain.
- Mixing paradigms should only be considered when all other options for using the primary paradigm for the module in question have been exhausted.
- One way to ease the friction on heterogeneous models is to use the same language in all paradigms.
- Paradigms that do not allow expressive representation of the domain with ubiquitous language should not be used.
Slowly learning that the struggle should always be to use the tools in the best possible way to fit the model, not to adjust model problems so that they are easily solved with our tools.
What happens when domain experts do not know the model well enough to answer deeper questions of things the business hasn't decided yet?
6 - The Life Cycle of a Domain Object- Invariants are ways to maintain business rules within an Aggregate
- An aggregate is a cluster of associated objects that we treat as a unit for the purposes of data changes.
- An aggregate route is the one entity (of possibly many) in the aggregate that other entities outside the aggregate can hold reference to.
- That means the other entities inside the aggregate only need identifiers distinguishable inside the aggregate, as nothing outside can access them.
- Aggregates are the only thing in the aggregate that can be accessed directly from the database. A delete operation must remove everything within the boundary.
- Invariants (consistency rules) involve relationships between members of the aggregate and must be enforced by persisting the aggregate as a whole.
- Decouple elements to keep clean distinctions between things inside and outside the aggregate boundary.
- Factories remove the need for object clients to know the inner workings of the client.
- They are not intrinsically part of the model but they are a reasoned necessity of the design.
- A factory should be an atomic operation that creates a valid entire aggregate for an entity with all invariants satisfied.
- Factories can over complicate a simple design but the threshold for choosing a factory method is short.
- Factory parameters should be from a lower design layer or basic objects and abstract types.
- Objects don't need to carry around logic that will never be applied in its active lifetime - so the factory can be a good place host the responsibility of enforcing invariants (especially if they are immutable).
- Factories are also suitable for reconstituting inactive objects, ie loading from the db.
- Infrastructure makes it easy to traverse dbs but developers have to try to keep the model in tact.
- Use a repositories to provide access to aggregates routes. Only ever traverse via the route to access objects internal to the aggregate.
- Repositories help maintain focus on the model by emulating an in-memory collection of all entities of a type.
- Repositories decouple domain design from persistence technology (facade) and allow for easy substitution.
- The specification pattern helps complex querying whilst maintaining the model.
- Keep mappings between objects and tables simple when designing relational dbs by compromising normalisation in favour of tight coupling between model and implementation.
7 - Using the Language: An Extended Example- An Anti Corruption layer can protect external systems that are not based on the same domain model from bleeding into your design.
- Enterprise Segments can be useful value objects for the design to allow communication between modules and preserve the ubiquitous language.
- The application layer should orchestrate the different elements of the domain but should not contain any business logic.
Should repositories be placed in a data access layer or do they belong inside the conceptual modules along with the entities they are for?
Could (or perhaps, should) there be an object oriented language or framework with these concepts of entities, values, aggregates, factories, repositories, anti-corruption layers as first class elements? We would lose precision but we would have a platform that is built for DDD?