note bottom of OrderStore: repository
note top of Order: entity
note right of OrderID: value object
note right of Product: entity
note right of Customer: entity
note top of OrderManagementService: service
note left of OrderEventArgs: domain event
note left of OrderID: value object
note left of ProductID: value object
note right of CustomerID: value object
note right of OrderManagementService: service
DDD Patterns
Towards DDD patterns
Further notions involving contexts
Bounded Context: enforce a model’s boundaries & make them explicit
Context Map: providing a global view on the domain and its contexts
Actual definitions
Context Boundary
The boundary of a context and its software model should be explicit.
This is helpful from several perspectives:
technical (e.g., dependencies among classes/interfaces)
physical (e.g., common database, common facilities)
organizational (e.g. people/teams maintaining/using the code)
Context Map
A map of all the contexts in a domain and their boundaries
and their points of contact
e.g. their dependencies, homonyms, false friends, etc.
providing the whole picture of the domain
Example of bounded context map
Bounded Contexts & Context Maps (best practices)
Clearly identify & representboundaries among contexts
Avoidresponsibility diffusion over a single context
one responsible person / team for each context
Avoid changes in the model for problems arising outside the context
rather, extend the domain by creating new contexts
Enforce context’s cohesion via automated unit and integration testing
to be (re)executed as frequently as possible
Model integrity problem
How to preserve the integrity of the model?
As the domain evolves, the software model should evolve with it
in order to maintain the coupling
Yet, the domain rarely changes as a whole
more commonly, it changes in a context-specific way
Contexts-are bounded, but not isolated
so are models, which may depend on each other
Changes to a context, and its model may propagate to other context / models
Domain / model changes are critical and should be done carefully
Model integrity patterns
Shared kernel: sharing a common model among contexts
Customer–supplier: the consumer model’s team requests changes in the supplier model
Conformist: one model’s team reacts to changes of some model they depend on
Anti-corruption layer: a model’s team isolates itself from another model
Purposes
Preserve the integrity of the model w.r.t. the domain
Minimise the potential impact / reach of changes
each context should be as independent as possible
each change affect as few contexts as possible
Model integrity patterns (background, pt. 1)
Context maps highlight relations among contexts
yet, notall relations are equal, nor symmetric
Model integrity patterns (background, pt. 2)
Each relation among 2 contexts usually involves 2 ends/roles:
upstream end, i.e. the one providing functionalities
downstream end, i.e. the one consuming functionalities
the downstream depends upon the upstream, but not vice versa
Integration among contexts $\leftrightarrow$ interaction among teams
depends on the domain layer (and, possibly, on the application layer)
Storage layer: supports persistent storage/retrieval of domain data
this is where repositories are implemented
may involve some DB technology
depends on the domain layer (and, possibly, on the presentation layer)
Interface layers (e.g. ReST API, MOM, View): let external entities access the software
via a GUI, or via some remote interface such as HTTP
Enforcing the architecture in the code
Layering may be enforced in the code
By mapping layers into modules
module $\approx$ packaging unit
e.g. Gradle sub-projects, Maven modules, .NET assemblies, etc.
each module having its own build dependencies
top to bottom direction
component ":domain" as domain
component ":application" as application
component ":presentation" as presentation
component "third-party serialization library" as gson
component "third-party DB client library" as db
component ":storage" as storage
component ":web-api" as server
component ":message-queue" as mq
component ":command-line" as cli
component product
domain <|-- application
application <|-- presentation
presentation <|-- server
presentation <|-- mq
application <|-- storage
presentation -r-|> gson
presentation <|-- cli
db <|-l- storage
product -u-|> server
product -u-|> storage
product -u-|> mq
Advanced aspects of DDD
Event sourcing (preliminaries)
Whenever there is a mutable entity …
… whose state evolution over time must be tracked …
… state transitions can be memorised in 2 ways:
one may track the current state
or the flow of variations
Event sourcing
A pattern where domain events are reified into time-stamped data and the whole evolution of a system is persistently stored
perfect match with DDD as domain events are first-class citizens
Event sourcing (pros & cons)
Benefits
Historical data can be analysed, to serve several purposes
e.g. predictive maintenance, optimization, analyse & anticipate faults
Past situations can be replayed
e.g. which improves debugging, enables measurements
Enables complex event detection & reaction
Enables CQRS (described later)
Limitations
A lot of data is generated and must be stored, which costs space
Reconstructing the (current) state costs time
Command–Query Responsibility Segregation (CQRS)
Advanced pattern for building highly-scalable applications
It leverages upon event sourcing and layered architecture…
… to deliver reactive, eventual-consistent solutions where:
contexts boundaries can be easily enforced
single responsibility principle is applied extensively
CQRS definition
Split the domain and application layers to segregateread/write responsibilities
Read model (a.k.a. view or query model)
accepts queries aimed at observing the state of the system
Write model (a.k.a. command model)
accepts commands aimed at altering the state of the system
CQRS concept
CQRS workflow (writing)
Whenever users are willing to perform an action into the system:
they create a command and forward it to the write model
i.e. an object describing a variation to be applied to some domain aspect
the command is possibly validated & stored onto some database
an ad-hoc database is available in the model for storing commands
CQRS workflow (reading)
Whenever users are willing to inspect/observe the system at time $t$:
they perform a query on the read model
asking for the state of the system at time $t$
e.g. $t$ $\equiv$ now
commands up to time $t$ are assumed to be reified when reading
a snapshot of the system state at time $t$ is returned to users
CQRS – When are commands reified?
Reification: is the process of computing the state of the system at time $t$ by applying of commands recorded up to time $t$
If queries and commands are stored on different databases
reification implies updating the query database
the query database should be read-efficient
the commands database should be write-efficient
Several, non-mutually-exclusive strategies:
eager: commands are reified as soon as they are received
pull: commands are reified upon reading queries
push: commands are reified in background, periodically