Open In App

Domain-Driven Design (DDD)

Domain-Driven Design (DDD) is an approach to software development that focuses on understanding and modeling the problem domain within which a software system operates. It emphasizes the importance of collaborating closely with domain experts to develop a deep understanding of the domain’s intricacies and complexities. DDD provides a set of principles, patterns, and practices to help developers effectively capture and express domain concepts in their software designs.



What is Domain-Driven Design (DDD)?

Domain

It refers to the subject area or problem space that the software system is being built to address. It encompasses the real-world concepts, rules, and processes that the software is intended to model or support. For example, in a banking application, the domain includes concepts like accounts, transactions, customers, and regulations related to banking operations.



Driven

“Driven” implies that the design of the software system is guided or influenced by the characteristics and requirements of the domain. In other words, the design decisions are based on a deep understanding of the domain, rather than being driven solely by technical considerations or implementation details.

Design

“Design” refers to the process of creating a plan or blueprint for the software system. This includes decisions about how the system will be structured, how different components will interact, and how the system will fulfill its functional and non-functional requirements. In the context of Domain-Driven Design, the focus is on designing the software in a way that accurately reflects the structure and behavior of the domain.

Domain-Driven Design is a concept introduced by a programmer Eric Evans in 2004 in his book Domain-Driven Design: Tackling Complexity in Heart of Software

Importance of Domain Knowledge

Suppose we have designed software using all the latest tech stack and infrastructure and our software design architecture is amazing, but when we release this software in the market, it is ultimately the end user who decides whether our system is great or not. Also if the system does not solve business needs, then it is of no use to anyone. No matter how pretty it looks or how well the architecture its infrastructure are.

According to Eric Evans, When we are developing software our focus should not be primarily on technology, rather it should be primarily on business. Remember,

It is not the customer’s job to know what they want” – Steve Jobs

Strategic Design in Domain-Driven Design(DDD)

Strategic Design in Domain-Driven Design (DDD) focuses on defining the overall architecture and structure of a software system in a way that aligns with the problem domain. It addresses high-level concerns such as how to organize domain concepts, how to partition the system into manageable parts, and how to establish clear boundaries between different components.

Let us see some key concepts within Strategic Design in Domain-Driven Design(DDD)

1. Bounded Contexts

2. Context Mapping

3. Strategic Patterns

4. Shared Kernel

5. Anti-Corruption Layer (ACL)

6. Ubiquitous Language

Ubiquitous Language refers to a shared vocabulary or language that is used consistently and universally across all stakeholders involved in the development of a software system. This language consists of terms, phrases, and concepts that accurately represent domain knowledge and concepts.

Some of the key principles of Ubiquitous Language are:

Tactical Design Patterns in Domain-Driven Design (DDD)

In Domain-Driven Design (DDD), 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.

Let us see some of the key tactical design patterns in DDD:

1. Entity

An entity is a domain object that has a distinct identity and lifecycle. Entities are characterized by their unique identifiers and mutable state. They encapsulate behavior and data related to a specific concept within the domain.

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.

2. Value Object

A value object is a domain object that represents a conceptually immutable value. Unlike entities, value objects do not have a distinct identity and are typically used to represent attributes or properties of entities. Value objects are equality-comparable based on their properties, rather than their identity.

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

3. Aggregate

For example, in an e-commerce system, an Order aggregate might consist of entities like OrderItem and Customer, with the Order entity serving as the aggregate root.

4. Repository

For example, a CustomerRepository might provide methods for querying and storing Customer entities.

5. Factory

For example, a ProductFactory might be responsible for creating instances of Product entities with default configurations.

6. Service

For example, an OrderService might provide methods for processing orders, applying discounts, and calculating shipping costs.

Benefits of Domain-Driven Design(DDD)

Challenges of Domain-Driven Design (DDD)

Use-Cases of Domain-Driven Design (DDD)

Real-world Example of Domain-Driven Design (DDD)

Problem Statement

Lets say, we are developing a ride-hailing application called “RideX.” The system allows users to request rides, drivers to accept ride requests, and facilitates the coordination of rides between users and drivers.

Ubiquitous Language

  1. User: Refers to individuals who request rides via the RideX platform.
  2. Driver: Refers to individuals who provide rides to users via the RideX platform.
  3. Ride Request: Represents a user’s request for a ride, specifying details such as pickup location, destination, and ride preferences.
  4. Ride: Represents a single instance of a ride, including details such as pickup and drop-off locations, fare, and duration.
  5. Ride Status: Represents the current status of a ride, such as “Requested,” “Accepted,” “In Progress,” or “Completed.”

Bounded Contexts

  1. Ride Management Context: Responsible for managing the lifecycle of rides, including ride requests, ride assignments to drivers, and ride status updates.
  2. User Management Context: Handles user authentication, registration, and user-specific features such as ride history and payment methods.
  3. Driver Management Context: Manages driver authentication, registration, availability status, and driver-specific features such as earnings and ratings.

Entities and Value Objects

  1. User Entity: Represents a registered user of the RideX platform, with properties like user ID, email, password, and payment information.
  2. Driver Entity: Represents a registered driver on the RideX platform, with properties like driver ID, vehicle details, and driver status.
  3. Ride Request Entity: Represents a user’s request for a ride, including properties like request ID, pickup location, destination, and ride preferences.
  4. Ride Entity: Represents a single instance of a ride, including properties like ride ID, pickup and drop-off locations, fare, and ride status.
  5. Location Value Object: Represents a geographical location, with properties like latitude and longitude.

Aggregates

  1. Ride Aggregate: Consists of the Ride Entity as the aggregate root, along with related entities such as Ride Request, User, and Driver entities. The Ride Aggregate encapsulates the logic for managing the lifecycle of a ride, including handling ride requests, assigning drivers, and updating ride status.

Repository

  1. Ride Repository: Provides methods for querying and storing ride-related entities, such as retrieving ride details, updating ride status, and storing ride-related data in the database.

Services

  1. Ride Assignment Service: Responsible for assigning available drivers to ride requests based on factors such as driver availability, proximity to pickup location, and user preferences.
  2. Payment Service: Handles payment processing for completed rides, calculating fares, processing payments, and updating user and driver payment information.

Domain Events

  1. RideRequestedEvent: Represents an event triggered when a user requests a ride, containing information such as the ride request details and user ID.
  2. RideAcceptedEvent: Represents an event triggered when a driver accepts a ride request, containing information such as the ride ID, driver ID, and pickup location.

Example Scenario

  1. User Requesting a Ride: A user requests a ride by providing their pickup location, destination, and ride preferences. RideX creates a new ride request entity and triggers a RideRequestedEvent.
  2. Driver Accepting a Ride: A driver accepts a ride request from the RideX platform. RideX updates the ride status to “Accepted,” assigns the driver to the ride, and triggers a RideAcceptedEvent.
  3. Ride In Progress: The user and driver coordinate the ride, with the ride status transitioning from “Accepted” to “In Progress” once the driver reaches the pickup location.
  4. Ride Completion: After reaching the destination, the ride status is updated to “Completed.” RideX calculates the fare, processes the payment, and updates the user and driver payment information accordingly.


Article Tags :