2022-11-15

Domain-Driven Design (DDD)

What is Domain-Driven Development (DDD)

Domain-Driven Design (DDD) is a software development methodology that prioritizes understanding the core domain of a system to build robust, maintainable, and adaptable software solutions. At the heart of DDD lies the collaboration between domain experts and software developers, which ensures that the resulting software closely models the problem space it addresses.

Benefits of DDD

There are several advantages to using DDD in software development:

  • Aligning software with business needs
    DDD ensures that the software model accurately represents the underlying domain, which in turn helps developers create software that directly addresses business requirements.

  • Enhancing maintainability and adaptability
    DDD promotes a clean separation of concerns, making it easier to modify, extend, or refactor the software as the domain evolves.

  • Facilitating collaboration
    By emphasizing communication and a shared language, DDD encourages collaboration between domain experts and developers, leading to better-informed software design decisions.

Common Terms in DDD

There are several common terms in DDD:

Ubiquitous Language

A shared language used by domain experts and software developers to communicate and collaborate effectively. The ubiquitous language ensures that all stakeholders have a common understanding of the domain, its concepts, and its rules.

Domain Model

A representation of the domain's core concepts, business rules, and relationships. The domain model serves as the foundation for the software system, informing its design and implementation.

Bounded Context

A self-contained area of the domain with its own model, language, and rules. Bounded contexts encapsulate domain logic and minimize dependencies on other contexts, making the system more maintainable and scalable.

Context Mapping

The process of identifying and documenting the relationships between bounded contexts. Context mapping helps developers understand how different parts of the system interact and collaborate.

Building Blocks of DDD

DDD defines several high-level concepts that can be used in conjunction with one another to create and modify domain models.

DDD terms
EP32: REST vs. GraphQL

Entities

Entities are objects that have a unique identity and a lifecycle within the domain. They often represent the core concepts of the domain and are characterized by their mutable state. Entities are distinguished from one another by their identities, even if their attributes are otherwise identical.

Value Objects

Value objects are immutable objects that represent aspects of the domain but do not have a distinct identity. They are often used to describe characteristics or attributes of entities. Value objects are defined by their properties, and two value objects with the same properties are considered equal.

Aggregates

Aggregates are groups of related entities and value objects that form a single unit, with one entity serving as the aggregate root. The aggregate root is responsible for enforcing business rules and ensuring the consistency of the aggregate as a whole. Aggregates help to enforce invariants and maintain consistency within a specific context of the domain.

Repositories

Repositories are responsible for providing access to a collection of aggregates or entities, often by abstracting the underlying persistence mechanism. They act as a bridge between the domain model and the data storage, allowing developers to focus on the domain logic without worrying about the specifics of data retrieval and storage.

Factories

Factories are responsible for creating and assembling complex domain objects, such as entities and aggregates. They encapsulate the logic required for object creation, ensuring that the resulting objects adhere to the domain's business rules and invariants.

Services

Services are stateless operations that encapsulate domain logic that doesn't naturally fit within entities, value objects, or aggregates. They are typically used to implement use cases, coordinate interactions between aggregates, or perform calculations or validations that span multiple domain objects.

Domain Events

Domain events represent significant occurrences within the domain that are of interest to other parts of the system. They are used to communicate changes in state or business rules between different components of the system, often in a decoupled manner. Domain events enable a more modular and flexible architecture by allowing components to react to events without being tightly coupled to the event's source.

Layers in DDD

DDD typically organizes a software system into four distinct layers, each with its own set of responsibilities. These layers are:

  • Domain Layer
    The domain layer contains the core business logic and represents the heart of the system. It is composed of domain objects such as entities, value objects, aggregates, and domain events. This layer is responsible for enforcing business rules, invariants, and ensuring that the system's state is consistent with the domain's requirements.

  • Application Layer
    The application layer sits on top of the domain layer and is responsible for coordinating activities and managing the flow of data between the domain and other layers. This layer typically contains application services, which define use cases and orchestrate interactions between domain objects and external components. Application services are often stateless and do not contain any business logic themselves, instead delegating to the domain layer as needed.

  • Infrastructure Layer
    The infrastructure layer provides the technical capabilities needed to support the other layers of the system. This includes components such as repositories, data access mechanisms, messaging systems, and external service integrations. The infrastructure layer often implements interfaces or abstractions defined in the domain or application layers, allowing those layers to remain focused on their core responsibilities and remain decoupled from the specific technology choices.

  • Presentation Layer (also known as the User Interface Layer)
    The presentation layer is responsible for presenting information to users and capturing user input. It could be a graphical user interface (GUI), a command-line interface (CLI), or even an API for other systems to consume. The presentation layer communicates with the application layer to retrieve data, initiate actions, and display the results. It should not contain any business logic or domain knowledge, as that would violate the separation of concerns principle.

Python directory structure implementing DDD

A typical Python directory structure implementing DDD principles might look like the following:

my_project/
│
├── app/                # Application layer
│   ├── services/
│   │   ├── __init__.py
│   │   ├── account_service.py
│   │   ├── order_service.py
│   │   └── ...
│   ├── views/
│   │   ├── __init__.py
│   │   ├── account_view.py
│   │   ├── order_view.py
│   │   └── ...
│   ├── __init__.py
│   ├── config.py
│   └── main.py
│
├── domain/            # Domain layer
│   ├── aggregates/
│   │   ├── __init__.py
│   │   ├── account.py
│   │   ├── order.py
│   │   └── ...
│   ├── entities/
│   │   ├── __init__.py
│   │   ├── customer.py
│   │   ├── product.py
│   │   └── ...
│   ├── value_objects/
│   │   ├── __init__.py
│   │   ├── address.py
│   │   ├── email.py
│   │   └── ...
│   ├── events/
│   │   ├── __init__.py
│   │   ├── account_events.py
│   │   ├── order_events.py
│   │   └── ...
│   ├── factories/
│   │   ├── __init__.py
│   │   ├── account_factory.py
│   │   ├── order_factory.py
│   │   └── ...
│   └── __init__.py
│
├── infrastructure/   # Infrastructure layer
│   ├── repositories/
│   │   ├── __init__.py
│   │   ├── account_repository.py
│   │   ├── order_repository.py
│   │   └── ...
│   ├── orm/
│   │   ├── __init__.py
│   │   ├── models.py
│   │   └── base.py
│   ├── messaging/
│   │   ├── __init__.py
│   │   ├── event_bus.py
│   │   └── ...
│   ├── __init__.py
│   └── settings.py
│
├── tests/           # Test suite
│   ├── unit/
│   │   ├── __init__.py
│   │   ├── test_account.py
│   │   ├── test_order.py
│   │   └── ...
│   ├── integration/
│   │   ├── __init__.py
│   │   ├── test_account_integration.py
│   │   ├── test_order_integration.py
│   │   └── ...
│   ├── __init__.py
│   └── conftest.py
│
├── .gitignore
├── README.md
└── requirements.txt

This structure separates the different layers of the DDD architecture, such as the domain, application, and infrastructure layers. It also organizes domain building blocks like aggregates, entities, value objects, events, and factories into dedicated directories. The test suite is organized into unit and integration tests, providing coverage for the various components of the system.

References

https://blog.bytebytego.com/p/ep32-how-does-grpc-work
https://www.linkedin.com/pulse/microservices-domain-driven-designdd-ahmed-emad
https://www.thoughtworks.com/en-us/insights/blog/architecture/domain-driven-design-in-functional-programming
https://blog.airbrake.io/blog/software-design/domain-driven-design

Ryusei Kakujo

researchgatelinkedingithub

Focusing on data science for mobility

Bench Press 100kg!