Skip to main content

🏛️ Domain-Driven Design

Modeling software around business

The Map-Making Analogy

Making a map of a city:

Bad map: Uses technical terms nobody understands Good map: Uses the same names as locals use

Different neighborhoods have different terminology:

  • Business district: "Office buildings"
  • University area: "Academic buildings"
  • Both are right - in their context!

DDD creates a shared vocabulary between developers and domain experts. Code speaks the language of the business.


What Is Domain-Driven Design?

DDD = Approach to software development that focuses on:

1. Understanding the business domain
2. Using domain language in code
3. Defining clear boundaries between concepts
4. Modeling complex logic explicitly

Not a framework. A mindset.

Core Principles

1. The Domain Is Central

Not technology-first.
Not database-first.

Business logic and domain concepts first.
Technology serves the domain.

2. Collaboration

Developers + Domain Experts together.

Domain experts know the business.
Developers know how to model it.

Neither alone creates great software.

3. Continuous Refinement

Understanding evolves.
Model evolves.
Code evolves.

DDD is ongoing, not one-time.

Ubiquitous Language

The Problem

Domain expert says: "Customer"
Developer writes: "UserAccount"

Domain expert says: "Order"
Developer writes: "TransactionRecord"

Constant translation. Misunderstandings. Bugs.

The Solution

ONE language used EVERYWHERE:
  - In conversations
  - In documentation
  - In code
  - In tests

Customer → class Customer
Order → class Order

Code reads like the business speaks.

Building the Language

Together with domain experts:
  - Define key terms
  - Document meanings
  - Use consistently
  - Evolve together

Bounded Contexts

The Problem

"Customer" means different things:

Sales: Person considering purchase
Shipping: Delivery address
Billing: Payment method

One universal model breaks down.

The Solution

Bounded Context = Clear boundary where terms apply.

Sales Context:
  Customer = lead, interests, contact info

Shipping Context:
  Customer = name, address, delivery preferences

Billing Context:
  Customer = payment methods, billing address

Each context has its own model.
Terms clear within context.

Context Map

How contexts relate:

┌─────────────┐     ┌─────────────┐
│   Sales     │────→│  Shipping   │
│  Context    │     │  Context    │
└─────────────┘     └─────────────┘
       │                   │
       │    ┌─────────────┐│
       └───→│   Billing   │←┘
             │  Context    │
             └─────────────┘

Define relationships and translation.

Building Blocks

Entity

Something with an identity.
Identity persists through changes.

User entity:
  - Has ID
  - Name can change
  - Still the same user

Two users with same name ≠ Same entity.

Value Object

Defined by attributes, not identity.
Immutable.

Address value object:
  - 123 Main St, City, Country

Same address = Same value object.
Different address = Different value object.

Aggregate

Cluster of entities treated as one unit.
One entity is the "aggregate root."

Order aggregate:
  - Order (root)
  - Order items
  - Payment info

Access items through Order.
Consistency boundary.

Repository

Abstraction for data access.

OrderRepository:
  save(order)
  findById(id)
  findByCustomer(customerId)

Domain doesn't know about database.

Domain Service

Logic that doesn't belong to any entity.

TransferMoney(fromAccount, toAccount, amount)

Involves multiple entities.
Stateless operation.

Domain Event

Something significant that happened.

OrderPlaced
PaymentReceived
ShippingScheduled

Past tense. Immutable fact.

Strategic vs Tactical DDD

Strategic DDD

Big picture:
  - Bounded contexts
  - Context mapping
  - Team alignment

Where to draw boundaries.
Organization-level.

Tactical DDD

Implementation patterns:
  - Entities
  - Value objects
  - Aggregates
  - Repositories

How to model within boundaries.
Code-level.

When to Use DDD

Good Fit

✓ Complex business domains
✓ Long-lived applications
✓ Domain experts available
✓ Core business logic (not commodity)
✓ Team willing to invest

Probably Overkill

✗ Simple CRUD applications
✗ Technical domains (no business experts)
✗ Short-lived projects
✗ Solo developers
✗ Time pressure with simple domain

Common Mistakes

1. DDD Everywhere

Not every part needs DDD.
Supporting contexts can be simple.
Focus DDD on core domain.

2. Anemic Domain Model

Entities as data bags.
All logic in services.

DDD: Rich domain model with behavior.
Entities know how to validate, calculate.

3. Ignoring Ubiquitous Language

Using DDD building blocks without shared language.
Missing the point!

Language is the foundation.

4. One Model for Everything

Trying to make one Customer model work everywhere.
Gets bloated and confusing.

Embrace bounded contexts.

FAQ

Q: Do I need to use all DDD patterns?

No! Use what helps. Strategic patterns without tactical is fine.

Q: DDD vs microservices?

They work together! Bounded contexts often map to microservices.

Q: How do I learn DDD?

Read "Domain-Driven Design" by Eric Evans. Practice on real projects.

Q: Is DDD slow?

Initial investment, yes. Pays off in long-lived, complex projects.


Summary

Domain-Driven Design aligns software with business through shared language, bounded contexts, and rich domain models.

Key Takeaways:

  • Domain is central, not technology
  • Ubiquitous language everywhere
  • Bounded contexts for different meanings
  • Entities have identity, value objects don't
  • Aggregates enforce consistency
  • Strategic (boundaries) + Tactical (modeling)
  • Best for complex, long-lived domains

DDD: Build software that speaks the business!

Leave a Comment

Comments (0)

Be the first to comment on this concept.

Comments are approved automatically.