Domain Driven Design
A distilled explanation
Introduction
If you are starting to learn about Domain Driven Design and your search takes you to this article you are in the right place. I want to mention something, in this article, I’m not going to teach you all the things that you can learn from the Books related to DDD from Eric Evans, but you’re going to learn and understand the key parts of DDD with short and clear descriptions and I’m sure that you can take this as a start point and ones that you start with the books (the thing that I recommend you) you will have an idea about what the concept means.
Topics
Chapter One
— What is Domain Driven Design?
— Domain and Subdomain
— What is the Ubiquitous language?
— Types of domains/subdomains Core, Support, and Generic.
— Bounded context?
— Context and Sub context
— Context MapsChapter Two
— Entity and Identity
— Value Objects
— Repository
— Service
— Aggregate
— ModuleChapter three
— Core Segregation
— Anti-corruption Layer
— Transaction layer
— Integrate Bounded context
What is Domain Driven Design — DDD?
First of all, what is a domain?
The domain is the area of knowledge and expertise of the business that is being modeled in a software system. The domain represents the set of concepts, rules, and processes that are fundamental to the business and that must be understood and reflected in the design of the software.
Knowing that definition we can now talk about what is DDD.
Is a Architectural Stile conformed by different patterns and suggestions that help us to build our software. Although DDD does not mention or obligate us to use a code structure in our project, DDD helps us to understand the Domain that the software is created, because is focused on the domain model detecting the key points, the business rules, and all the relations in the domain logic.
Domains and Subdomain
What is a domain?
In a few words, the domain refers to the specific area of knowledge or business to which the software belongs. This is the central point of DDD.
the domain experts collaborate with developers to identify and understand key business concepts, such as business rules, scopes, processes, etc.
Some examples of domains are:
Software to manage a hospital.
Online Store.
software to manage Schools.
What is a Subdomain?
When we are working with a big domain is recommended to split the scopes into small related scopes taking into account its business rules and functionalities.
Each subdomain manages its functionalities and scopes and is related to other subdomains and forms part of a parent Domain.
Examples of subdomains are:
- Domain ->Web Store — Subdomain -> Products management — Subdomain -> Order management
Ubiquitous language
It refers to the common language that both developers and domain experts use to share their ideas. The ubiquitous language is not related to some programming language is just a terminology definition for all and each one of the components of the domain.
Some of its main points are:
Uses terms that are not technical.
Definition of glossaries
Constant collaboration between domain experts and developers
keep the language updated
The ubiquitous language is very helpful because by using the same language in all areas, misunderstandings are minimized.
Example:
Imagine an e-commerce Domain with two detected subdomains “Product Management” and “Order Management”, now we going to define a possible ubiquitous language for each one.
Domain: E-commerce:
Subdomain: Product Management
Oblique language for the “Product Management” subdomain:
Product: A product available for sale in e-commerce.
Catalog: A collection of available products.
Inventory: The number of products available in stock.
Category: A classification of products according to their type or common characteristics.
SKU (Stock Keeping Unit): A unique identifier for a product in inventory. Could work as an identity.
Price: The monetary value assigned to a product.
Description: The detailed information that describes a product.
Subdomain: Order Management
Oblique language for the “Order Management” subdomain:
Order: It is a purchase request for one or more products made by a customer.
Shopping Cart: A temporary collection of products selected by a customer before finalizing an order.
Order confirmation: The action related to the validation and registration of an order placed by a customer.
Order Status: The current status of the order, it can be pending, processed, shipped, or delivered.
Payment: The process of making payment for an order.
Shipping: The process of physically preparing and delivering the ordered products.
Shipping Address: The location to which the products will be shipped.
Customer: A person or entity that places an order, by means of carrying out a transaction in the e-commerce.
Invoice: A document that details the products purchased, displaying their prices and details, is used by the customer for billing and tax purposes.
Types of domains/subdomains — Core, Support, and Generic.
When we are defining our domain and/or subdomains we going to find three categories that can help us to group our functionalities depending on the importance and impact of the main business.
The types or categories are Core, Support, and Generic. In the following lines, I will explain each one and give you an example of the real world.
Core Domain/Subdomain
The core domain is the essence of the system and often receives special attention in the design and development processes. It refers to the core of the business, where the key functionalities and processes that provide differentiating value to the system are found. This domain covers the core and critical aspects of the business and focuses on complex and specialized business rules.
Support Domain/Subdomain
The Support Domain encompasses the secondary functionalities that are necessary for the general operation of the system, but that are not the central or differentiating part of the business. These functionalities usually include aspects of infrastructure, administrative tasks, user management, security, and notifications, among others. Although they are not the core of the business, they are important for the proper functioning and support of the system as a whole.
Generic Domain/Subdomain
The Generic Domain refers to components and/or functionalities that are generic and reusable and can be applied to multiple domains in the system. These functionalities are common and generic solutions and do not provide direct value to the business. Examples of Generic Domains can be utility libraries, infrastructure components, authentication services, and integration with payment providers, among others.
Example:
E-commerce system.
Bounded context
This is one of the main concepts of DDD since it delimits the characteristics and functionality of a domain model on which it is working. Furthermore, each bounded context defines its ubiquitous language.
In a complex software system, it is common for there to be different concepts, rules, and terminologies that can have different meanings depending on the context in which they are used. For this reason, each bounded context has its domain model, consisting of entities, value objects, aggregates, services, and other items that are relevant and meaningful to that particular context. The domain model within a bounded context is designed and optimized for that specific context, taking into account particular business needs and rules.
Bounded contexts can communicate with each other through well-defined interfaces and by setting clear boundaries for interactions. This allows the different contexts to develop, evolve and maintain independently, without affecting the other contexts. We’re going to dig a little deeper into this part in the next few sections.
Context and Sub context
Context
Context helps define clear boundaries and separations between different areas of the system, making it easier to understand and manage complexity.
The context delimits the functionalities of a Domain Model representing a specific area of the model. Each context has its domain model, its own set of entities, aggregates, services, and value objects that are relevant and specific to that particular context.
Subcontext
Subcontexts are smaller, more specific subdivisions of a larger context, which help us to group and organize functionality based on their affinity and logical relationship. A subcontext allows you to break a large context into smaller, more manageable parts, making it easier to design and maintain your system.
In general, it is important to note that the way contexts and sub-contexts are defined can vary depending on the system and the business in question. The delineation of contexts and sub-contexts must be based on a deep understanding of the business domain and the interactions between different concepts and functionalities.
Context Maps
Context maps are graphical and visual representations that show each one of the contexts in the domain. It focuses on showing the communication, relationship, and collaboration of the different bounded contexts.
Entity and Identity
Entities are one of the fundamental concepts in DDD and play a crucial role in domain modeling since they allow representing and working with key business concepts.
Eric Evans tells us: “An entity is an object with a unique and continuous identity over time. Entities have an independent existence and can be distinguished from other entities by their identifier.”
Explaining a little more, it can be said that an entity is an object that represents a concept of the business domain and has its own identity. This identity allows an entity to be distinguished from other entities, even if they have similar attributes and values. An entity is mutable, which means that its state can change over time, but its identity remains constant.
Entities encapsulate both data and behavior related to a specific concept within the business domain. For example, in an online sales system, an entity could be a “Product” object with attributes such as product number, price, brand, description, etc. The “Product” entity would have associated methods to perform operations such as purchase, check stock, etc.
Identity
An Identity refers to the attribute or set of attributes that make an entity unique and distinguishable from other entities. It is a property that uniquely identifies an entity in the context of the system. For example, in the domain of an “online store”, you can have the entity “Order”, its identity could be determined by a unique order number assigned to each order.
Example:
Imagine a Hotel System where we have two contexts, Hotel reservations (core domain) and Billing (support domain).
Core Domain: Hotel reservations
Entities:
-- Booking
-- ID
-- Entry date
-- Departure date
-- Customer
-- Room
-- Price
-- Hotel
-- ID
-- Name
-- Address
-- Customer
-- ID
-- Name
-- Email
-- Phone
Support Domain: Billing
Entities:
-- Bill
-- ID
-- Client
-- Date
-- Invoice lines
-- Client (reused from main context)
As you can see each entity is a representation of a business model, in this case, booking, Hotel, and Bill. Each entity has an ID property, that property is the identity and is unique for each data related to the entity.
Value Objects
It is a vital building block of DDD, the value objects are used to model a component of the business domain that lacks its own identity. Unlike entities, which are identified by their unique identity, Value Objects are defined by their attributes and characteristics.
When you are trying to decide whether a concept is a Value, you should determine whether it possesses most of these characteristics:
It measures, quantifies, or describes a thing in the domain.
It can be maintained as immutable.
It models a conceptual whole by composing related attributes as an integral unit.
It is completely replaceable when the measurement or description changes.
It can be compared with others using Value equality.
It supplies its collaborators with Side-Effect-Free Behavior
Some common examples of Value Objects could be:
— Address: Composed of attributes such as street, city, state, and zip code.
— Date range: defined by a start date and an end date.
— Currency: with attributes such as currency code and amount.
Example:
We going to take as a base the example defined in the previous section, and we going to add the value objects needed.
Core Domain: Hotel reservations
Entities:
-- Booking
-- ID
-- Entry date
-- Departure date
-- Customer
-- Room
-- Price
-- Hotel
-- ID
-- Name
-- Address
-- Customer
-- ID
-- Name
-- Email
-- Phone
Value Objects:
-- Entry date
-- date
-- Deparature date
-- date
-- Room
-- Number
-- Type
-- Price
-- amount
-- currency
Support Domain: Billing
Entities:
-- Bill
-- ID
-- Client
-- Date
-- Invoice lines
-- Client (reused from main context)
Value Objects:
-- Invoice lines
-- Description
-- amount
-- total
-- amount
-- currency
As you can see the defined value object doesn’t define any identity property as we mentioned in the description.
Service
A Service ****in the domain is a stateless operation that fulfills a domain-specific task.
Services are a key element used to encapsulate complex business logic and operations that don’t fit naturally to a specific object or entity. Helping in processes of coordination and orchestration of the different objects and entities within a context to which they refer.
Unlike entities and value objects, which are used to represent domain concepts with identity and attributes, services focus on tasks, operations, and/or actions performed in the domain, which may or may not be directly associated with a specific entity.
Example:
We going to take again our hotel system, I going to omit the list of entities and value objects and just going to focus on the services.
Application: Hotel reservation platform
Core Domain: Hotel reservations
Entities: Reservation, Hotel, Customer
Value Objects: Check In Date, Check Out Date, Room, Price
Service: Reservation Service
-- Service functionalities:
-- MakeReservation()
-- SendReservationEmail()
-- CancelReservation()
-- SendCancelationEmail()
-- ConsultAvailability()
Support Domain: Billing
Entities: Invoice, Customer
Value Objects: Invoice Line, Total
Service: Billing Service
-- Service functionality
-- GenerateBilling()
As you can see the services are declaring functions to define the entity actions, those actions are related to the business logic and have its representation in the ubiquitous language defined for the domain.
Module
If you are using Java or C#, you are already familiar with Modules, though you know them by another name. Java and Go call them packages. C# calls them namespaces.
In a DDD context, Modules in your model serve as named containers for domain object classes that are highly cohesive with one another.
The goal should be low coupling between the classes that are in different Modules. Since Modules, as used in DDD, are not bland or generic storage compartments, it is also important to properly name the Modules. Their names are an important facet of the Ubiquitous Language.
Eric Evans mentions the following: “Choose Modules that tell the story of the system and contain a cohesive set of concepts. This often yields low coupling among Modules, but if it doesn’t, look for a way to change the model to disentangle the concepts. . . . Give Modules names that become part of the Ubiquitous Language. Modules and their names should reflect insight into the domain”.
In a few words, the modules are used to group functionally that form part of the same context helping us to organize the entities, services, value objects, etc., according to their context definitions.
Example:
Taking the same Hotel system we can define the following modules:
Hotel System
-- Module: ModuleHotel reservation
-- entitie
-- value object
-- service
-- repository
-- agregate
-- Module: Billing
-- entitie
-- value object
-- service
-- repository
-- agregate
Aggregate
I would like to open this section with the following fragment “Clustering **Entities and Value Objects into an Aggregate with a carefully crafted consistency boundary may at first seem like quick work, but among all DDD tactical guidance, this pattern is one of the least well understood”.
Well, I going to tell you in short words what this concept is and what is its usage, but as the introduction phrase says, it is one of the most complicated points in DDD, Or at least if you want to do it right, I recommend you to take a deep look this important part.
An aggregate is a “design pattern” that allows us to group entities and value logically related objects in the domain, in order to treat them as a coherent unit in the domain model. It is used to ensure consistency and integrity in a specific context within the domain.
Aggregates mark off the scope within which invariants have to be maintained at every stage of the life cycle. The following patterns, FACTORIES and REPOSITORIES, operate on AGGREGATES, encapsulating the complexity of specific life cycle transitions.
When you are designing an aggregate you must take into account the following aspects, which are key to its correct design:
Large-Cluster Aggregate
When an aggregate has a large number of entities or value objects plus significant complexity. These aggregates can be difficult to manage and maintain. One of the main recommendations is to break them into smaller aggregates to improve aspects such as consistency, scalability, and concurrency.Multiple Aggregates
It is based on the idea that a domain model can have multiple aggregates, where each aggregate encapsulates a coherent set of related objects and focuses on a specific part of the domain. Having multiple aggregates helps us maintain cohesion and isolation (coupling) between the different parts of the system.Rule: Model True Invariants in Consistency Boundaries
This rule suggests that the true invariances of the domain model should be modeled within the coherence bounds of the aggregates. Aggregates are responsible for ensuring that business rules and constraints are enforced within their boundaries. This helps maintain system integrity and prevents data inconsistencies.Rule: Design Small Aggregates
Promotes the design of small aggregates and focused on a single responsibility. Small aggregates are easier to understand, maintain, and scale. In addition, they allow for greater concurrency, since different aggregates can be manipulated simultaneously without blocking each other.Rule: Reference Other Aggregates by Identity
Reference Other Aggregates by Identity: This rule states that aggregates should reference other aggregates by their identity (ID), instead of holding direct references to the internal objects of other aggregates. This avoids the need to load and manage the entire structure of an aggregate when accessing related objects, reducing complexity and coupling between aggregates.Rule: Use Eventual Consistency Outside the Boundary
Outside the bounds of the aggregate, eventual consistency can be used instead of immediate consistency. This means that updates between aggregates may have delays and may not be instantly consistent. This allows for greater scalability and performance in distributed systems, as strict real-time consistency requirements are relaxed.
Eric Evans mentions in his book, “Cluster the ENTITIES and VALUE OBJECTS into AGGREGATES and define boundaries around each. Choose one ENTITY to be the root of each AGGREGATE, and control all access to the objects inside the boundary through the root. Allow external objects to hold references to the root only. Transient references to internal members can be passed out for use within a single operation only. Because the root controls access, it cannot be blindsided by changes to the internals. This arrangement makes it practical to enforce all invariants for objects in the AGGREGATE and for the AGGREGATE as a whole in any state change.”. That reference could give us more details about what an aggregate is and when to implement it in our domain model.
Some of the logic defined in an aggregate could be for example: “Order aggregate”, defines addProduct(), removeProduct(), and confirmOrder(). In this case “Order aggregate” makes reference to Products, then the relation is done using the identity, in this case, could be the product ID.
Repository
A repository commonly refers to a storage location, usually considered a place of safety or preservation of the items stored in it. When you store something in a repository and later return to retrieve it, you expect that it will be in the same state as it was in when you put it there. At some point, you may choose to remove the stored item from the repository.
A repository acts as an abstraction layer between the domain model and the data storage mechanism, be it a database, web service, or other data source. It provides methods to perform CRUD (create, read, update, delete) operations on domain objects, hiding the implementation details of how these operations are performed on the storage system.
**Example:
**In the following example, we going to take the same case the “Hotel System”, in the domain representation you can see the repository as part of the context “Hotel reservation”, there we going to find implementations to CRUD the entity defined by the context.
Hotel System
-- Context: Hotel reservation
-- entitie
-- value object
-- service
-- repository
-- findAll()
-- Save()
-- Update()
-- findByID()
-- remove()
-- agregate
Talking about the relationship between Entity, Value Object, Aggregate, and Service
Before continuing with the next chapter, I want to share with you a brief explanation of the relationship between entities, value objects, aggregates, and services, which help us maintain cohesion and optimal coupling in the system. In the next paraphs, the relationship between these concepts is shown:
“Relationship between Entities and Value Objects”
Remember, the Entities represent unique and identifiable objects in the domain, which have their own identity and can change state over time, on the other hand, V*alue objects* represent immutable concepts without their own identity in the domain, which are defined by their attributes and characteristics.
Entities can contain value objects as part of their internal structure, using them to represent specific attributes or complex characteristics
Now, one example:
Imagine an e-commerce system, the “Product” entity may have a “Category” **value object **that stores the product characteristics related to each category, the **value object **could define “category name”, “category description”, etc.
“Relationship between Aggregates and Entities/Value Objects”
Remember that an aggregate is a coherent set of entities and value objects that are grouped together and treated as an indivisible unit in terms of transactions and consistency. By defining an aggregate root that acts as an entry point for accessing and manipulating the related entities and value objects.
Example:
Imagine the same e-commerce system, then we have defined a “Shopping Cart” aggregate, that aggregate could contain entities such as “Product” and value objects such as “Shipping Address” and/or “Category”.
Relationship between Services and Aggregates
Remember, Services are responsible for executing high-level operations and coordinating the interaction between aggregates or entities within the domain. Then the relation between Services and Aggregates is listed in the following points:
Services use aggregates and their entities to perform more complex tasks involving multiple domain objects.
Services are used to encapsulate business logic that does not belong to a single aggregate, allowing operations beyond the bounded context.
Example:
Taking the same example, in the e-commerce system, an “Order Manager” service can use aggregates such as “Make order” and entities such as “Products” to coordinate the creation and confirmation of reservations.
Core Segregation
The term core segregation refers to the practice of separating and isolating the core domain from other elements of the system. Establishing clear limits to reduce complexity and promote a more modular and decoupled design, which allows us to focus on the specific domain and its business rules, which facilitates the understanding, maintenance, and evolution of the system over time.
This is a practice that we must apply in the design and architecture of the system from the beginning of the project. Maybe you are wondering When we could implement it? Or, What aspects to take into account for its implementation? So, next, I show you a little list that can guide us to know when we can apply core segregation:
When you have a complex domain rich in business rules
When working with multidisciplinary teams
When the system is expected to evolve and grow
Those are some of the main aspects that can help you detect if it is a good time to separate the domain.
The core segregation helps us to identify Domains and Subdomains in our system.
Anti-corruption Layer
In short, the Anti-Corruption Layer (ACL) in DDD is a pattern used to protect the domain core from external influences. They are commonly used to integrate DDD-based systems with other legacy systems, external services, or complex technical components. Its purpose is to help with the differences presented between the domain’s core language and business rules and the way interactions with those external systems are handled.
The Anti-Corruption layer is placed between the domain core and external systems or components and aims to translate or adapt interactions with those external systems in a way that is consistent with the domain model and business rules.
Some of its key aspects are:
Model translation
This aspect defines the responsibility for mapping and translating the concepts and data from the core domain (DDD system) to the terms and structures used by external systems. This allows the core domain to communicate efficiently and consistently with those systems.Interface adaptation
The Anti-Corruption Layer can adapt the interfaces and protocols used by external systems to be more consistent with the domain model. This may involve creating adapters, translators, or data transformations.Protection of the core domain
Provides a layer of isolation that protects the model and business rules, allowing them to evolve independently. Defines a barrier to prevent the complexities or limitations of external systems impacts directly on the core domain.
Transaction layer
In terms of Domain Driven Design, the transaction layer refers to a layer of the software architecture that is responsible for managing to write and read operations in the database, ensuring data consistency and integrity during transactions.
The purpose of this layer is to ensure that operations are performed atomically, that is, all operations within a transaction are completed or none of them are performed, which prevents inconsistent states or data corruption. In other words, for a transaction to be successful, all its operations must be successful, with a single operation that fails, the transaction is taken as failed and the changes defined in the operations will not be applied.
Integrate Bounded context
It makes reference to the need to communicate different bounded contexts that form part of the same system.
When working on a complex system, multiple bounded contexts are often needed to address different subdomains or areas of responsibility, so it is at this point that integration becomes necessary as it would allow collaboration between the different bounded contexts.
It is worth mentioning that although each bounded context is autonomous and with clear limits, it is important to establish mechanisms to exchange information, and events and collaborate between the bounded contexts.
Some ways we can integrate bounded contexts are interfaces such as REST APIs, events, and messaging systems, implementing integration patterns such as domain events, pub/sub patterns, etc.
The integration of bounded contexts is essential for building scalable and complex DDD systems, as it allows independent development and evolution of different contexts while ensuring collaboration and consistency across the system as a whole.
Final words
As you can see Domain Driven Desing is not hard to understand but is a large topic, in this article I covered some of the points but If I can give you some advice I could say you “read the books”, there you will find more about DDD.
The short descriptions in this article could help you to have a basic knowledge of what DDD is, and once you take more courses or if you read another DDD post or article you can understand faster.
I recommend that you do an exercise, analyze the project you’re currently working on, and try to develop each of the points we discussed in this post. This will help you better understand each of them in a practical way.
Each time that you learn new things you are growing as a professional and you are closer to being a software craftsman.
Thanks for reading and Keep learning!
Written by Israel Josue Parra Rosales
Top comments (0)