Domain Driven Design
Approach on Software Development focused on the design of a shared Model understood by domain experts and by who implements it. Being a model, it means that it can be implemented in different ways, from diagrams to software.
Concepts #
- Context: The setting a word appers determines its meaning.
- Domain: Sphere of knowledge, influence or activity (aka area).
- Model: System of abstractions that describes a part of the domain.
- Ubiquitous Language: Common language between domain experts and developers.
- Aggregate: Entity or group of entities bounded a root entity (Aggregate Root) that are always consistent (within a ACID transaction). Serves as a building block to implement
Command
within Command Query Responsibility Segregation (CQRS) .
Strategies #
On complex domains, it is hard to have a single unified model, therefore the model is usually split into multiple ones. Follows some strategies used to maintain integrity.
Bounded Context #
Concepts may change from one context to another. It is important to be explicit about it:
- Explicitely define the context where the model applies.
- Explicitely set the boundaries, e.g., team organization, code-bases, database schemas.
- Keep the model strictly consistent within these bounds.
Maintain these boundaries strong allows smoother workflows.
Typically Microservices are build around these contexts. Follows some tips to define them:
- Define use-cases.
- Look how different groups of people interact with a given entity.
- Look for variations of the ubiquitous language as they may suggest a new context.
- Look for variations where informations starts to become or relevant or irrelevant.
Anti-Corruption Layer #
Solves issues where coupling starts. This layer leaves right next to the bounded context to avoid leaking info from/to that bounded context.
Typical example: Let’s put everything in the same bag.
What happens is that we have a layer responsible for translating similar concepts from one bounded context to another.
How to implement: Abstract interface as it represents the contract in its purest way without compromising - Sometimes abstractions are too much indirection but do understand. :shrug:
This is also useful for legacy systems. In this case a Anti Corruption Layer would be preferable on either end.
Context Map #
Are a way of of visualizating Bounded contexts and the relationships between them.
- Arrows represent dependencies.
- Lines may be labelled to indicate the nature of the relationship.
TODO Discovery Process using Event Storming #
Types of Domain Activities #
- Command: A request yet to happen and can be rejected. Usually delivered to a specific destination and changes the state of the domain.
- Events: Action that happened in the past. Hence they can not be rejected. Often broadcast to many destinations. Record a change to the state of the domain, often the result of a command (what are the alternatives?).
- Query: Requestfor information about the domain. Usually delievered to a specific destination. Do not change the state of the domain.
All of these represent the types of messages in a Reactive System and form the API for a Bounded Context.
Domain Objects #
- Value objects: Defined by its attribute. Immuatable. Messages in Reactive Systems are implemented as Value Objects.
- Entity: Defined by an unique identity. The fields may change but not its identitity. Are the source of truth - Actors in Akka or Entitities in Lagom
Monolith - Aggregate: Collection of domain objects bound to a root entity:
- Example: Person (Aggregate Root), Name (Aggregate), Address (Aggregate).
- Transactions should not span multiple aggregate roots.
- The Aggregate Root may change between bounded contexts. Aggregate Root == Root Entity.
- Good cadnidates for distribution in Reactive Systems.
- Question: How to determine?
- Is the entity involved in more operations in the same bounded context?
- Does it make sense deleting other entities when this one is deleted?
- Will a single transaction span multiple entities?
Domain Abstractiosn #
Services #
Busines Logic encapsulated. Should be stateless otherwise they become an entity or a value object.
Should be fairly thin.
Factories #
Constructing domain object may not be trivial as they may have to access external resources (DBs, files, REst APIs, etc).
Repositories #
Similar to factories but used to get or modify existing objects. They work often over databases but can work with files or Rest Apis (I actually prefer “Gateways” for Rest APIs).
Note: Factories and Repositories can be the same in practice.
Hexagonal Architecutre #
Is not directly related with domain driven design but is very compatible.
Domain is at the core and is at teh center becoming the architectural focus. Then there are ports to communicate with the domain exposed as API for the domain. INfrastructure contains adapters that map to the ports.
Like an Onion
- Domain
- API - The ports Infrastructure - Adapts incoming and outgoing traffic in to the ports.
Outer layers depends on inner layers. And inner layers have no knowledge of other layers.
:thinking: This does not seem different from the typical layered design with DB -> Services -> API
Ensures proper spearation of infrastructure from domain.
These layers may be modelled through packages or projects. Details are not important. The important thing is to make the domain portable.
Would like a concrete example on how it really differents from the N tiered design.