Domain-Driven Design (DDD) is often misunderstood as a complex architecture or a framework.
In reality, DDD is a way of thinking and designing software around business problems.
This article answers four essential questions:
What is Domain-Driven Design?
Why was it invented
What problem does it solve?
What is Ubiquitous Language?
What are bounded contexts and strategic design principles?
What Is Domain-Driven Design?
Domain-Driven Design is an approach, not an architecture.
DDD focuses on:
Understanding the business domain
Modeling software around real business concepts
Aligning developers and domain experts using a shared language
Instead of organizing your project by technical layers (Controllers, Services, Repositories), DDD encourages organizing it by business capabilities.
Simple definition:
DDD is about structuring your software to reflect how the business actually works.
Why Was DDD Invented?
DDD was introduced by Eric Evans to solve a common problem in software projects:
The growing gap between business knowledge and technical implementation
Common problems before DDD:
Business rules scattered across the codebase
Developers and domain experts use different terminology
Large, monolithic models that try to represent everything
DDD addresses these problems by:
Strategic Design vs Tactical Design
DDD is divided into two complementary parts:
1️⃣ Strategic Design (The big picture)
2️⃣ Tactical Design (Inside a boundary)
Entities
Value Objects
Aggregates
Repositories
Domain Services
Ubiquitous Language
Ubiquitous Language is a shared vocabulary used by everyone, domain, and developers.
This language is used in meetings, appears in documentation, and is reflected directly in code
Without a shared language, developers guess the business meaning, business people misunderstand technical constraints, and we are lost.
Example
In an e-commerce system, the word Order might mean different things:
To a customer: "What I bought"
To accounting: "An invoice"
To shipping: "A package with weight and address"
DDD says: don't force one meaning everywhere.
Bounded Context
A Bounded Context defines a clear and explicit boundary around a specific domain scope, with its own domain model and its own vocabulary. Inside a bounded context, every term has one precise meaning, and the model remains consistent and unambiguous. However, across different bounded contexts, the same word may carry different meanings, depending on the business perspective and rules of that context.
E-commerce Example
| Context | Meaning of "Order" |
|---|
| Ordering | Items, quantities, prices |
| Shipping | Dimensions, address, weight |
| Billing | Invoice, taxes, payment status |
We can't merge all of these into one Order class.
Context Map
A Context Map describes:
It is usually visualized as a diagram.
Example: Banking System (Why Context Maps Matter)
Imagine a banking system with:
Context 1: Banking
Account
- AccountNumber
- Balance
Context 2: Payee Management
Account
- AccountNumber
- Notes
At first glance, both have an Account class.
In a classic UML only approach, a developer might say:
"We already have Account. Let's reuse it."
This creates tight coupling and wrong assumptions:
How Context Maps Fix This
The context map makes boundaries explicit:
Anti-Corruption Layer (ACL)
An Anti-Corruption Layer protects one domain from another.
Example
Instead of using an external ExternalCustomerDto directly:
public class CustomerTranslator
{
public Customer Translate(ExternalCustomerDto dto)
{
return new Customer(
new CustomerId(dto.Id),
dto.FullName
);
}
}
Your domain stays clean and consistent.
Shared Kernel
Sometimes, two bounded contexts must share a small part of the model.
This shared part is called a Shared Kernel.
Example:
These items may be saved in a common project between different contexts.
Tactical Design (Inside a Bounded Context)
Once boundaries are clear, we design the internals.
Entities
Have identity
Change over time
Equality based on ID
class Customer
{
public CustomerId Id { get; }
public string Name { get; private set; }
}
Value Objects
Immutable
Identified by value
No identity
public record Money(decimal Amount, string Currency);
Aggregates
Example:
Benefits of Domain-Driven Design
Better communication with domain experts
Code reflects real business rules
Easier to evolve with business changes
Clear separation of concerns
Reduced accidental complexity
Real Life Steps to Apply DDD
Understand the business domains
Define a Ubiquitous Language
Identify bounded contexts
Draw a context map
Design aggregates inside each context