03 Domain Driven Design
A software development approach born out of the XP programming world, carrying with it all the OO concepts from UML, and focuses on modelling the problem domain within which a software system operates. It’s a continuation of the good works of Ivor Jacobson (Use Case Modelling) and Rebecca Wirfs-Brock CRC Cards and Modelling.
Domain - Focus on developing a deep understanding of the domain in which the software system will exist. The domain model should encompass the real-world concepts, rules, and processes that the software is intended to model or support. The logical modelling of tech Block 2 represents a part of this modelling.
Driven - Everything you do is guided by that domain knowledge and understanding. Avoid being driven solely by technical issues. It’s domain-driven first, technically driven second
Design - Step back from the edge of going straight into the code, create some kind of blueprint, and then incrementally build out the applications(s).
The two primary concepts are
Strategic Design - defining the architecture of a software system in a way that aligns with the problem domain. It addresses high-level concerns such as domain concepts, partitioning the system into manageable parts, and defining the boundaries between those different parts once the system has been partitioned
Tactical Design - these are patterns that encompass specific strategies or techniques used to realize domain model elements within a software system. These patterns are well established in the software industry and help developers effectively capture the complexity of the domain, whilst promoting maintainability, flexibility, reusability, scalability etc.
01 Domain Knowledge
I’ve always said, “Customers pretty much know what they want but struggle to articulate it, when you show them something, then the light bulb goes on and their directing becomes a lot clearer”.
Steve Jobs famously said “Some people say give the customers what they want, but that's not my approach. Our job is to figure out what they're going to want before they do. I think Henry Ford once said, 'If I'd ask customers what they wanted, they would've told me a faster horse.' People don't know what they want until you show it to them. That's why I never rely on market research. Our task is to read things that are not yet on the page.”
Read this interesting article.
Market research is important but don’t let it stop your drive towards visionary solutions. If you do, then innovation will cease.
02 Strategic Design
Defining the architecture of a software system in a way that aligns with the problem domain. It addresses high-level concerns such as domain concepts, partitioning the system into manageable parts, and defining the boundaries between those different parts once the system has been partitioned
Centres around 6 principles
Bounded Context *
Context Mappings *
Strategic Patterns *
Shared Kernal *
Anti-Corruption Level
Ubiquitous Language
02-01 Bounded Context
A large system is strategically partitioned. These partitions become explicit boundaries within which a particular domain model is defined.
Large systems are notoriously complex and difficult to maintain and manage, as we saw when we played with the VAT calculator application. By breaking large systems into smaller pieces it becomes easier to develop, manage, and deploy, but there is a cost associated with this. We discuss this later.
Consider the timesheet example you saw earlier in the programme
Here we ring-fenced each area of concern, and we labelled them Domain 1, 2, and 3. Our focus for this discussion is the data but it could be software components or hardware components.
As can be seen from the updated diagram, Timesheet Info (a tab in a spreadsheet) becomes Work-Project-Info (some data in a project time management system) becomes Timesheet Acc Info (a type in an accounting system).
If you were to have a discussion with SMEs within each of these domains, you would very quickly learn that they all use a different term for the same thing. Is one term better or more accurate than the other? No, that’s the wrong way to think about it. Each term is valid within its context (the bounded context).
02-02 Context Mapping
The process of defining the relationships and interactions between different Bounded Contexts.
Each bounded context encapsulates the language, concepts, and processes for the domain that it represents. This is a great idea, but when you have to wire the domains back together the system becomes a spaghetti of code. A RPC style approach to wiring things together is very messy, a better approach is to use some kind of service bus, a MOM.
Whether you use a RPC or MOM style architecture context mapping has to occur between each domain (bounded context). So the models above would be redrawn as shown below,
There are pros and cons for both approaches. With the RPC approach the mapping tables are much smaller and tailored specifically towards an individual pair of dependencies. With the MOM approach, you could end up with a single Context Mapper trying to be all things to all Domains. A far better approach would be to create smaller mapping contexts that only listen for certain events.
02-03 Strategic Patterns
Examples of strategic patterns
Aggregates
Domain Events *
Anti-Corruption Layer
02-03.01 Domain Events
In DDD, a Domain Event represents something significant that has happened within a specific Bounded Context. These events are named in the past tense to clearly indicate that they’ve already occurred.
If we talk about events, then we need to talk about states.
States
A state represents a condition that the system is under at any point in time. Systems transition from one state to another because an event has occurred.
To be more precise
State definition:
“is a measure of what something can and can not do at specific points in time”.
The state of the thing of interest is a condition or situation during the life of an object during which it:
Satisfies some condition
Performs some activity
Waits for an event
Transitions
A relationship between two object states indicating the object in the first state will perform certain actions and enter the second state when:
a specified event occurs
specified conditions are satisfied
The duality of states and events
The event is the trigger causing a transition from one state to another
There exists between states and events symbiotic relationship
Some Notation (UML State Modelling - Harel’s Machines)
We can use Harel’s Notation to help us capture the duality of states and events
This model represents the lifecycle of an email application
This model represents the lifecycle of a bank account
You can see that we have used the same notation to model different levels of complexity and abstractions.
02-03.02 Event Sourcing
The Event Sourcing pattern builds on the ideas of state machines. Rather than storing the current state of an entity, you store a sequence of events that represent changes to the entity’s state over time. The current state can then be reconstructed by replaying these events.
Consider an e-commerce system. Instead of storing the current order details, you’d store a series of events like ProductAdded
, QuantityUpdated
, and OrderPlaced
. To retrieve the current order, you'd replay these events from the beginning.
02-04 Shared Kernel (strategic pattern)
A strategic pattern that involves identifying areas of commonality between different Bounded Contexts and establishing a shared subset of the domain model that is used by multiple contexts.
Consider the model below, it’s an extract from the hotel example you worked on during Tech Block 2. The <<domain>> stereotype signifies an area/function of the business.
There are two processes that we want to consider, making a reservation using an online application, and creating the bill when a client checks out of the hotel. The current model (the one above) uses a none DDD approach. Classes are defined in one domain and reused across other domains. This is NOT the DDD philosophy.
Following DDD we could create a shared context called the Billing Context.
This shared kernel pattern facilitates collaboration and integration between contexts whilst allowing each context to maintain its distinct model. This pattern should be used judiciously. And overuse of it can lead to increased dependencies between contexts which ultimately lead to tight coupling.
QL-01 Creating Bounded Context and Context Maps
Using the Hotel Case Study, develop the
Bonded Contexts
Context Maps
Shared Kernels if you think they exist
List the significant events in each context
Define a event sourcing table for one of the triggering events
03 Tactical Design
Tactical design patterns are specific strategies or techniques used to structure and organize the domain model within a software system. These patterns help developers effectively capture the complexity of the domain, while also promoting maintainability, flexibility, and scalability.
The important thing to remember about this phase in DDD is that it’s focused on arming the software developer with the tools they need to implement a software system following DDD approach.
These patterns are
Entity
Value Object
Aggregate
Repository
Factory
Service
03-01 Entity Tactical Design
It captures the idea of representing a domain type in software. In a similar way to how domain types are represented in a relational or none relational database. Unlike the database approach, this software approach would encapsulate the functionality associated with the datatype. Entity objects are equality-comparable based on their identity.
Example
In a banking application, a Bank Account (something that has meaning to the business) might have properties like account number, possibly its balance as this can be derived by summing the transactions against the account, date opened, and last accessed, along with methods to deposit, withdraw, or transfer funds, as well as other useful methods.
03-02 Value Object Tactical Design
An object that describes some characteristic or attribute but carries no concept of identity.
Does an object represent something with continuity and identity, something that is tracked through different states or even across different implementations? This is an Entity. Or is it an attribute that describes the state of something else? This is a value object. Obviously, it depends on who is asking the question, as shown in the diagram below.
Value objects are equality-comparable based on their properties, rather than their identity.
Unlike entities, value objects do not have a distinct identity and are typically used to represent attributes or properties of entities.
03-03 Aggregate Tactical Design
This is a group of domain objects that are treated as a single unit for the purpose of data consistency and transactional integrity. The aggregate consists of one or more entities and value objects, with one entity object designated as the aggregate root. This root object serves as the entry point for accessing and modifying the aggregate’s internal state.
Aggregates enforce consistency boundaries within the domain model, ensuring that changes to related objects are made atomically.
03-04 Repository Tactical Design
A repository object abstracts away the data access and persistence logic from the domain model.
Over the years a number of approaches have evolved, some better than others, but they all serve the same purpose, to provide a standardized interface for querying and storing domain objects, hiding the details of how data is retrieved or stored. They encapsulate the logic for translating between domain objects and underlying data storage mechanisms, such as databases or external services.
This approach enforces the idea of single responsibility. Domain objects should have no knowledge of the underlying technology
This model is all about enforcing the separation of concerns. Entity and Value objects have no idea what underlying technology is being used to manage their persistence.
03-05 Factory Tactical Design
A factory is a creational pattern used to encapsulate the logic for creating instances of complex domain objects. Factories abstract the process of object instantiation, allowing clients to create objects without needing to know the details of their construction. Factories are particularly useful for creating objects that require complex initialization logic or involve multiple steps.
The factory pattern has a wide range of applications
hiding away the complexities of creating objects
instantiating objects that have been moved across a network
ensuring that a specific number of objects are only ever created in a system
03-06 Service Tactical Design
There are those aspects of the domain that are more clearly expressed as actions or operations, rather than as objects. Although it is a slight departure from object-oriented modeling tradition, it is often best to express these as SERVICES, rather than forcing responsibility for an operation onto some ENTITY or VALUE OBJECT. A SERVICE is something that is done for a client on request. In the technical layers of the software, there are many SERVICES. They emerge in the domain also, when some activity is modelled that corresponds to something the software must do, but does not correspond with state.
This is a direct quote from the book “Domain Driven Design” by Eric Evans.
And the behaviour of the service class (Account Owner Service) would look something like this