Domain-driven
design: Architectural
patterns
Eleonora Ciceri - 8 February 2022
1
Architectural patterns
Architectural patterns introduce organizational principles for the different
aspects of a codebase and present clear boundaries between them:
- how the business logic is wired to the system’s input
- how the business logic is wired to the system’s output
- how the business logic is wired to the infrastructural components
2
Predominant architectural patterns
Three predominant architectural patterns are as follows:
- layered architecture
- hexagonal architecture
- CQRS
3
Layered architecture
4
Layered architecture
The layered architecture is one of the most common architectural patterns.
It organizes the codebase into horizontal layers, with each layer addressing
one of the following technical concerns:
- interaction with the consumers
- implementing business logic
- persisting the data
5
Layered architecture: Presentation layer
The presentation layer implements the program’s user interface for
interactions with its consumers
In modern systems the presentation layer has a broader scope, i.e., all means
for triggering the program’s behavior: GUI, CLI, API for programmatic
integration with other systems, subscription to events, message topics for
publishing outgoing events
6
Layered architecture: Business logic layer
The business logic layer is responsible for implementing and encapsulating the
program’s business logic. This is the place where business decisions are
implemented
“This layer is the heart of the software”
–Eric Evans
7
Layered architecture: Data access layer
The data access layer provides access to persistence mechanisms.
- In the pattern’s original form this referred to the system’s database
- As in the case of the presentation layer, this layer’s responsibility is
broader for modern systems (including, e.g., object storage, message
buses, API provided by external systems…)
8
Communication between layers
The layers are integrated in a top-down communication model: each layer can
hold a dependency only on the layer directly beneath it.
This enforces decoupling of implementation concerns and reduces the knowledge
shared between the layers
9
Variation: Service layer (1)
The service layer can be an additional layer of the layered architecture, that
acts as an intermediary between the presentation and business logic layers
10
Variation: Service layer (2)
Note: the service layer is a logical boundary, not a physical service!
The service layer acts as a façade for the business logic layer: it exposes an
interface that corresponds with the public interface’s methods,
encapsulating the required orchestration of the underlying layers
Hence, having a service layer:
- improves modularity by fathering all related methods in one place
- decouples the presentation and business logic layers
- makes it easier to test the business functionality
11
Variation: Service layer (3)
12
it is not necessary
when…
it is required if…
the business logic is
implemented as a transaction
script (which makes itself a
service layer)
the business logic pattern
requires external orchestration
When to use the layered architecture
The dependency between the business logic and the data access layers makes
this architectural pattern a good fit for a system with its business logic using
the active record pattern
However, the pattern makes it challenging to implement a domain model!
In a domain model the business entities should have no dependency and no
knowledge of the underlying infrastructure
13
Active record pattern. The pattern uses dedicated objects (known as active records) to
represent complicated data structures. These objects also implement data access
methods (the CRUD operations). Active record objects are coupled to an
object-relational mapping (ORM) or some other data access framework.
Hexagonal architecture
14
Hexagonal architecture
The hexagonal architecture (also called ports and adapters) addresses the
shortcomings of the layered architecture and is a better fit for implementation
of more complex business logic
We can derive it from the layered architecture. See the next slides
15
Infrastructure layer
The presentation layer and the data access layer presented in the layered
architecture are integration with external components (databases, external
services, user interface frameworks)
These technical implementation details do not reflect the business logic, so
we unify them under the hexagonal architecture, calling them infrastructure
layer:
16
Dependency Inversion Principle (1)
The dependency inversion principle (DIP) states that high-level modules,
which implement the business logic, should not depend on low-level modules.
However, that is exactly what happens in the traditional layered architecture
To conform with the DIP, we reverse the relationship, so that the business
logic layer has a central role and does not depend on infrastructural
components
17
Application layer
Finally, we add an application layer as a façade for the system’s public
interface. As in the layered architecture, this layer
- describes all the operations exposed by the system
- orchestrates the system’s business logic for executing them
18
Integration of infrastructural components
Instead of referencing and calling the infrastructural components directly
- the business logic defines the ports that have to be implemented by the
infrastructure layer
- the infrastructure layer implements adapters, i.e., concrete
implementations of the ports’ interfaces for working with different
technologies
19
A classical example of ports and adapters
20
Port in business
logic layer
Adapters in
infrastructure layer
interface TicketRepository {
void save(Ticket ticket);
}
class JdbcTicketRepository implements TicketRepository {
void save(Ticket ticket){
…
}
}
class InMemoryTicketRepository implements TicketRepository {
void save(Ticket ticket){
…
}
}
Variants
This architecture is known as hexagonal architecture, onion architecture,
ports & adapters architecture and clean architecture. All of these patterns
are based on the same design principles, have the same components and the
same relationships between them.
As in the case of the layered architecture, the terminology may differ:
- application layer = service layer = use case layer
- business logic layer = domain layer = core layer
21
When to use the hexagonal architecture
The decoupling of the business logic from all technological concerns makes
this architecture a perfect fit for business logic implemented with the domain
model pattern
22
Command-Query Responsibility Segregation
23
Command-Query Responsibility Segregation
The command-query responsibility segregation (CQRS) pattern is based on
the same organizational principles for business logic and infrastructural
concerns as the hexagonal architecture
It differs, however, in the way the system’s data is managed
This patterns enables representation of the system’s data in multiple
persistent models
24
Why should one need multiple models?
1. In some cases it is impossible to use a single model of the system
business domain. To deliver different functionalities, one could need
different representations of the same data
2. One could need polyglot persistence: using multiple databases to
implement different data-related requirements, e.g., scalability, search
capabilities etc
3. CQRS is closely related to event sourcing: it allows to materialize
projected models into physical databases that can be used for flexible
querying options
25
How does CQRS work? (1)
As the name says, there is a segregation of responsibilities between the
models of the system
26
Read models
this model
holds the truth
about data
Command
execution model
On this model we execute system
commands, i.e., operations that
modify the system state
The model is used to
- implement the business logic
- validate rules
- enforce invariants
These models are defined to present
data to users or supply information
to other systems
They are just precached projections
that may reside in database or even
in in-memory caches
They are read-only models
How does CQRS work? (2)
The overall view is substantially the following:
27
Read side
Write side
Command
execution model
Read model 1 Read model N
…
Command
update read models
Reports
Projecting read models
For the read models to work, the system has to project changes from the
command execution model to all its read models
28
Projecting read models: Synchronous projections
If a synchronous projection is conducted:
- the projection engine queries the write model for updated records after
the last processed checkpoint
- the projection engine uses the updated data to regenerate/update the
read models
- the projection engine stores the checkpoint for the last processed
record, to be used in the next iteration for getting newly changed records
29
Projecting read models: Asynchronous projections
In an asynchronous projection scenario:
- the write model publishes all the committed changes to a message bus
- the projection engines subscribe to the published messages and use
them to update the read models
30
Challenges of CQRS
CQRS has all the challenges of distributed computing:
- the method makes it more challenging to add new projections or to
regenerate existing ones
- if the messages are processed out of order or duplicated, inconsistent
data will be projected into the read models
For these reasons, it is advisable to always implement synchronous projection
and optionally an additional asynchronous projection on top of it
31
When to use CQRS
1. With all those applications that need to work with the same data in
multiple models, potentially stored in different kinds of databases
2. CQRS naturally lends itself to event-sourced domain models
32
References
33
References
[1] Vlad Khononov, Learning Domain-Driven Design - Aligning Software
Architecture and Business Strategy, O’Reilly, 2022
[2] Scott Millett, Patterns, Principles and Practices of Domain Driven Design,
Wrox, 2015
[3] Vernon & Evans, Implementing Domain-Driven Design, Addison-Wesley
Professional, 2013
34

DDD - 4 - Domain Driven Design_ Architectural patterns.pdf

  • 1.
  • 2.
    Architectural patterns Architectural patternsintroduce organizational principles for the different aspects of a codebase and present clear boundaries between them: - how the business logic is wired to the system’s input - how the business logic is wired to the system’s output - how the business logic is wired to the infrastructural components 2
  • 3.
    Predominant architectural patterns Threepredominant architectural patterns are as follows: - layered architecture - hexagonal architecture - CQRS 3
  • 4.
  • 5.
    Layered architecture The layeredarchitecture is one of the most common architectural patterns. It organizes the codebase into horizontal layers, with each layer addressing one of the following technical concerns: - interaction with the consumers - implementing business logic - persisting the data 5
  • 6.
    Layered architecture: Presentationlayer The presentation layer implements the program’s user interface for interactions with its consumers In modern systems the presentation layer has a broader scope, i.e., all means for triggering the program’s behavior: GUI, CLI, API for programmatic integration with other systems, subscription to events, message topics for publishing outgoing events 6
  • 7.
    Layered architecture: Businesslogic layer The business logic layer is responsible for implementing and encapsulating the program’s business logic. This is the place where business decisions are implemented “This layer is the heart of the software” –Eric Evans 7
  • 8.
    Layered architecture: Dataaccess layer The data access layer provides access to persistence mechanisms. - In the pattern’s original form this referred to the system’s database - As in the case of the presentation layer, this layer’s responsibility is broader for modern systems (including, e.g., object storage, message buses, API provided by external systems…) 8
  • 9.
    Communication between layers Thelayers are integrated in a top-down communication model: each layer can hold a dependency only on the layer directly beneath it. This enforces decoupling of implementation concerns and reduces the knowledge shared between the layers 9
  • 10.
    Variation: Service layer(1) The service layer can be an additional layer of the layered architecture, that acts as an intermediary between the presentation and business logic layers 10
  • 11.
    Variation: Service layer(2) Note: the service layer is a logical boundary, not a physical service! The service layer acts as a façade for the business logic layer: it exposes an interface that corresponds with the public interface’s methods, encapsulating the required orchestration of the underlying layers Hence, having a service layer: - improves modularity by fathering all related methods in one place - decouples the presentation and business logic layers - makes it easier to test the business functionality 11
  • 12.
    Variation: Service layer(3) 12 it is not necessary when… it is required if… the business logic is implemented as a transaction script (which makes itself a service layer) the business logic pattern requires external orchestration
  • 13.
    When to usethe layered architecture The dependency between the business logic and the data access layers makes this architectural pattern a good fit for a system with its business logic using the active record pattern However, the pattern makes it challenging to implement a domain model! In a domain model the business entities should have no dependency and no knowledge of the underlying infrastructure 13 Active record pattern. The pattern uses dedicated objects (known as active records) to represent complicated data structures. These objects also implement data access methods (the CRUD operations). Active record objects are coupled to an object-relational mapping (ORM) or some other data access framework.
  • 14.
  • 15.
    Hexagonal architecture The hexagonalarchitecture (also called ports and adapters) addresses the shortcomings of the layered architecture and is a better fit for implementation of more complex business logic We can derive it from the layered architecture. See the next slides 15
  • 16.
    Infrastructure layer The presentationlayer and the data access layer presented in the layered architecture are integration with external components (databases, external services, user interface frameworks) These technical implementation details do not reflect the business logic, so we unify them under the hexagonal architecture, calling them infrastructure layer: 16
  • 17.
    Dependency Inversion Principle(1) The dependency inversion principle (DIP) states that high-level modules, which implement the business logic, should not depend on low-level modules. However, that is exactly what happens in the traditional layered architecture To conform with the DIP, we reverse the relationship, so that the business logic layer has a central role and does not depend on infrastructural components 17
  • 18.
    Application layer Finally, weadd an application layer as a façade for the system’s public interface. As in the layered architecture, this layer - describes all the operations exposed by the system - orchestrates the system’s business logic for executing them 18
  • 19.
    Integration of infrastructuralcomponents Instead of referencing and calling the infrastructural components directly - the business logic defines the ports that have to be implemented by the infrastructure layer - the infrastructure layer implements adapters, i.e., concrete implementations of the ports’ interfaces for working with different technologies 19
  • 20.
    A classical exampleof ports and adapters 20 Port in business logic layer Adapters in infrastructure layer interface TicketRepository { void save(Ticket ticket); } class JdbcTicketRepository implements TicketRepository { void save(Ticket ticket){ … } } class InMemoryTicketRepository implements TicketRepository { void save(Ticket ticket){ … } }
  • 21.
    Variants This architecture isknown as hexagonal architecture, onion architecture, ports & adapters architecture and clean architecture. All of these patterns are based on the same design principles, have the same components and the same relationships between them. As in the case of the layered architecture, the terminology may differ: - application layer = service layer = use case layer - business logic layer = domain layer = core layer 21
  • 22.
    When to usethe hexagonal architecture The decoupling of the business logic from all technological concerns makes this architecture a perfect fit for business logic implemented with the domain model pattern 22
  • 23.
  • 24.
    Command-Query Responsibility Segregation Thecommand-query responsibility segregation (CQRS) pattern is based on the same organizational principles for business logic and infrastructural concerns as the hexagonal architecture It differs, however, in the way the system’s data is managed This patterns enables representation of the system’s data in multiple persistent models 24
  • 25.
    Why should oneneed multiple models? 1. In some cases it is impossible to use a single model of the system business domain. To deliver different functionalities, one could need different representations of the same data 2. One could need polyglot persistence: using multiple databases to implement different data-related requirements, e.g., scalability, search capabilities etc 3. CQRS is closely related to event sourcing: it allows to materialize projected models into physical databases that can be used for flexible querying options 25
  • 26.
    How does CQRSwork? (1) As the name says, there is a segregation of responsibilities between the models of the system 26 Read models this model holds the truth about data Command execution model On this model we execute system commands, i.e., operations that modify the system state The model is used to - implement the business logic - validate rules - enforce invariants These models are defined to present data to users or supply information to other systems They are just precached projections that may reside in database or even in in-memory caches They are read-only models
  • 27.
    How does CQRSwork? (2) The overall view is substantially the following: 27 Read side Write side Command execution model Read model 1 Read model N … Command update read models Reports
  • 28.
    Projecting read models Forthe read models to work, the system has to project changes from the command execution model to all its read models 28
  • 29.
    Projecting read models:Synchronous projections If a synchronous projection is conducted: - the projection engine queries the write model for updated records after the last processed checkpoint - the projection engine uses the updated data to regenerate/update the read models - the projection engine stores the checkpoint for the last processed record, to be used in the next iteration for getting newly changed records 29
  • 30.
    Projecting read models:Asynchronous projections In an asynchronous projection scenario: - the write model publishes all the committed changes to a message bus - the projection engines subscribe to the published messages and use them to update the read models 30
  • 31.
    Challenges of CQRS CQRShas all the challenges of distributed computing: - the method makes it more challenging to add new projections or to regenerate existing ones - if the messages are processed out of order or duplicated, inconsistent data will be projected into the read models For these reasons, it is advisable to always implement synchronous projection and optionally an additional asynchronous projection on top of it 31
  • 32.
    When to useCQRS 1. With all those applications that need to work with the same data in multiple models, potentially stored in different kinds of databases 2. CQRS naturally lends itself to event-sourced domain models 32
  • 33.
  • 34.
    References [1] Vlad Khononov,Learning Domain-Driven Design - Aligning Software Architecture and Business Strategy, O’Reilly, 2022 [2] Scott Millett, Patterns, Principles and Practices of Domain Driven Design, Wrox, 2015 [3] Vernon & Evans, Implementing Domain-Driven Design, Addison-Wesley Professional, 2013 34