DDD

What is Domain Driven Design?

Domain-Driven Design (DDD) is a software development approach that focuses on understanding and modeling the domain problem as closely as possible within the software system.

It emphasizes collaboration between domain experts, software developers, and other stakeholders to create a shared understanding of the domain and its complexities.

DDD is not about a certain technology. Domain-Driven Design (DDD) is an approach to the development of complex software consisting of multiple puzzle pieces.

DDD was introduced by Eric Evans in his book "Domain-Driven Design: Tackling Complexity in the Heart of Software."

Key principles and concepts of DDD

DDD provides a set of principles, patterns, and practices to help developers effectively capture and express domain concepts in their software designs.

In Domain-Driven Design (DDD), both strategic design and tactical design are crucial aspects of building software systems that accurately model and address complex business domains.

A large problem domain can be decomposed into subdomains to manage complexity and separate important parts from the rest of the system. This can be a “core” domain, a “generic” domain, or a “supporting” domain.

  1. Core domain: domains are where we want to excel as a business and our specific skills here really differentiate us from the rest of the market. The most important part of the system is that this will give you a competitive advantage, so focus on this and make it as good as possible.
  2. Generic domain: This is not the core, but the core depends on it. e.g. email sending service, monitoring service, and such. Try to reuse existing parts, and don’t spend too much time on these systems.
  3. Supporting domain: domains that help to support the core but do not provide any competitive advantage. It is not recommended to invest heavily in but still needed in order to succeed in the core domain.

Example

Let's illustrate the identification of domains, including core, generic, and supporting domains, with an example of an e-commerce platform.

Example

Now, let’s dive into the details of event storming.

One of the first things to understand is the different types of details that are captured about the domain. These different types of details are typically represented by different colored sticky notes.

2. Putting the Process Into Action.

Example

In our e-commerce application, we may have bounded contexts such as “Order,” “Product Catalog,” “Payment,” Inventory, Shipping, and “User Management Authentication and Authorization.

Example

Context mapping is a technique used to manage the interactions and relationships between bounded contexts. It helps to identify integration points, establish communication protocols, and handle inconsistencies between different parts of the system. Context maps don’t need to show the detail of a model; instead, they must demonstrate the integration points and the flow of data between bounded contexts.

Context Mapping

A very important factor in DDD context maps is the direction of the relationship between two contexts. DDD uses the terms upstream or downstream.

An upstream context will influence the downstream counterpart while the opposite might not be true. These are often shortened to the letters d and u respectively.

In the example, you have a context map that illustrates a Personal Finance Management Application that talks to an online banking service through an API. So, in this case, the PFM application is the downstream, and the online banking service is the upstream.

PFM application

A Shared Kernel is 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. This shared subset, or kernel helps facilitate collaboration and integration between contexts while still allowing each context to maintain its own distinct model.

In our e-commerce example, the “Order Management” and “Payment Processing” bounded contexts might need to share certain core concepts, such as customer information and order status.

Order Management

DDD distinguishes between different types of domain objects.

Examples For example, in a banking application, a BankAccount entity might have properties like account number, balance, and owner, along with methods to deposit, withdraw, or transfer funds e-commerce application, including Customer, Order, Product, and Card. - Order object that represents and maintains a state about a specific order and implements different operations (add items, add a shipping address, add payment details, etc) that can be carried out on that order.

For example, a Money value object might represent a specific amount of currency, encapsulating properties like currency type and amount.

As an example, consider two aggregates Buyer and Order. Order has as entities Order and OrderItem; and Address as a value object. However, all external interactions are via the Order entity, which is the aggregate root. This entity refers to the root of the Buyer by identity (foreign key).

Pattern

For example, represents an event triggered when a user places an order containing information such as the details of Items user ID, Shipping Address, and payment.

Domain-Driven Design blueprint

The DDD principles can be split into two parts, respectively into Strategic and Tactical sides.
By splitting it up, we can define certain boundaries and tackle elements that are relevant to that part. Strategic patterns shape the solution, while Tactical patterns are used to implement a rich domain model.

The two parts of DDD's Strategic and Tactical sides are connected through ubiquitous language — the binding between the code and the analysis model.

Ubiquitous language

How to get started with DDD?

Steps to implement DDD

  1. Understand the Domain: Start by thoroughly understanding the problem domain, including its business rules, processes, and concepts. Engage with domain experts to gain insights into the domain's complexities. Identify the core aspects of the domain that provide the most significant value to the business.
  2. Create a Ubiquitous Language: Work closely with domain experts to identify and establish a common language, known as a ubiquitous language, that is shared by domain experts and developers. Use this language consistently throughout the project to ensure clear communication and understanding. Document these terms in a glossary or domain dictionary to serve as a reference for the entire team.
  3. Implement Bounded Contexts: Define clear boundaries, known as bounded contexts, within which a particular model, language, and set of concepts apply. Bounded contexts help manage complexity by isolating different parts of the domain and ensuring clear communication between them. In a microservices architecture, each bounded context can be implemented as a separate microservice. Ensure that each microservice is focused on a specific business capability and encapsulates a cohesive set of functionality.
  4. Develop the Domain Model (Entities and Value Objects): Use modeling techniques such as domain modeling workshops, event storming, and domain-driven design patterns and principles to create a domain model that accurately represents the problem domain. Focus on capturing the essential entities, value objects, aggregates, and their relationships.
  5. Design and Implement Aggregates, Aggregate Roots: Identify aggregate roots within the domain model—entities that act as the root of an aggregate and enforce consistency and transactional boundaries within the aggregate. Implement business logic within aggregates to enforce domain invariants and ensure data consistency. Use techniques like domain events and domain services to orchestrate complex behaviors.
  6. Implement Domain Services, Domain Events: Implement domain services to encapsulate behavior that doesn't naturally belong to entities or value objects. Domain services represent domain-level operations and can be used to orchestrate interactions between multiple domain objects. Identify significant events or state changes within the domain that need to be communicated or reacted to by other parts of the system.
  7. Test and Iterate: Write unit tests, integration tests, and acceptance tests to validate the behavior of the domain model and its interactions with other parts of the system. Test-driven development (TDD) can help ensure that the domain model meets the specified requirements. Continuously iterate on the domain model based on feedback from stakeholders and domain experts.
    Test
    Iterate Arrow
    Iterate

When to use DDD?

Some say you can apply DDD principles to every project, whilst others tend to use DDD in projects where business logic is complex. In some cases, DDD would be a great fit, but in others not. Don’t try to apply DDD to everything.

While Domain-Driven Design provides many technical benefits, such as maintainability, it should be applied only to complex domains where the model and the linguistic processes provide clear benefits in the communication of complex information and in the formulation of a common understanding of the domain.

Draw a context map and decide on where you will proceed for DDD and where you will not.

Context map

Benefits of Domain-Driven Design(DDD)

Challenges of Domain-Driven Design (DDD)

Complexity

  1. DDD can introduce complexity, especially in large and complex domains. Modeling intricate business domains accurately requires a deep understanding of the domain and may involve dealing with ambiguity and uncertainty.
  2. Managing this complexity effectively requires careful planning, collaboration, and expertise.

Ubiquitous Language Adoption

  1. Establishing and maintaining a ubiquitous language—a shared vocabulary that accurately represents domain concepts—can be challenging. It requires collaboration between developers and domain experts to identify and agree upon domain terms and meanings.
  2. Achieving consensus on the ubiquitous language may require overcoming communication barriers and reconciling differences in terminology and perspectives.

Bounded Context Alignment

  1. In large and complex domains, different parts of the domain may have distinct models and bounded contexts. Aligning these bounded contexts and ensuring consistency between them can be challenging.
  2. It requires clear communication, collaboration, and coordination between teams working on different parts of the domain to avoid inconsistencies and conflicts.

Technical Complexity

  1. Implementing DDD principles and patterns effectively may require adopting new technologies, frameworks, and architectural approaches. Integrating DDD with existing systems or legacy codebases can be complex and may require refactoring or redesigning existing code to align with DDD principles.
  2. Technical challenges such as performance, scalability, and maintainability must be carefully addressed to ensure the success of DDD adoption.

Why is DDD important in modern-day software architecture?

Domain-driven design (DDD) plays a crucial role in modern software architecture by providing a pragmatic approach to building complex and maintainable systems.

Improved Collaboration

  1. DDD encourages collaboration between technical teams and domain experts (such as business analysts or subject matter experts). By involving domain experts in the software development process, teams can create software that accurately models the problem domain.
  2. This collaboration ensures that the software aligns with the actual business needs, leading to better outcomes.

Focused Development

  1. DDD places the problem domain at the forefront, advocating for a deep understanding and modeling of the domain. It emphasizes Ubiquitous Language, rich domain models, and domain-centric design.
  2. DDD helps identify and focus on the most critical parts of your application—the core domain. By understanding the core concepts, relationships, and behavior of the domain, developers can build software that truly addresses business requirements.
  3. Focusing on the core domain allows teams to allocate resources efficiently and prioritize development efforts where they matter most.

Better Model Representation

  1. DDD emphasizes a deep understanding of the business domain through concepts like ubiquitous language, bounded contexts, and aggregates.
  2. The use of a common language between domain experts and developers ensures that the software accurately reflects the business domain. This alignment leads to a better model representation in the codebase.

Flexibility and Adaptability

  1. The modular nature of DDD fosters enhanced flexibility in design and development. Systems built using DDD can adapt more readily to changes in the business domain.
  2. By modeling the system around domain events and explicitly defining them, developers create systems that are responsive, loosely coupled, and adaptable.

Monolith system architecture with DDD

A monolithic application is a software architecture where different components of the application are combined into a single codebase and deployed as a single unit.

Pros

Cons

Distributed systems with DDD

  1. Distributes system Architecture is an emerging service-based architectural style that focuses on the design and implementation of highly scalable distributed software systems.
  2. To analyze the business domain and its decomposition into services, Domain-driven Design (DDD) is commonly applied.
  3. DDD is an approach for designing software that relies on various model-based concepts to express knowledge about the business domain, e.g. the Bounded Context, which clusters a set of coherent Domain Models.
  4. Use Domain Driven Design to construct the right boundaries from our business contexts using techniques such as event-storming. This process then leads to a context map which shows the relationship between bounded contexts.
  5. Once we have the bounded contexts, we can begin to express the model and capture transaction boundaries in interactions to build a view of “domain aggregates”.
  6. DDD offers an approach to modeling software based on bounded contexts and provides strategic and tactical design techniques for building autonomous software capabilities as services.
    Design technique

Step-by-Step Guide

Incorporating DDD in an E-commerce Application.

Example

Bounded Contexts

Entities

Order Management

Inventory Management

Value Objects

Inventory Management

Aggregates


Order Management

Inventory Management

Aggregate Roots

Domain Services

Domain Events

Summary

In summary, combining Domain-Driven Design principles with distributed architecture in modern software systems enables the creation of scalable, resilient, and domain-driven applications that can adapt to changing business requirements and technological advancements. By aligning domain concepts with distributed services, organizations can build software architectures that are well-suited to the complexities of today's digital landscape.