SOFTWARE ARCHITECTURE / SYSTEM CONCEPT BRIEF

Domain-Driven Design

Domain-Driven Design (DDD), introduced by Eric Evans, is an approach to building software around a deep model of the business domain, developed together with domain experts using a shared ubiquitous language.

AdvancedPhase 08 / Topic 5 of 17RequirementsTrade-offsFailure modes
01

Overview

Domain-Driven Design (DDD), introduced by Eric Evans, is an approach to building software around a deep model of the business domain, developed together with domain experts using a shared ubiquitous language. It has two parts: strategic design (splitting a large domain into bounded contexts and mapping their relationships) and tactical design (patterns like entities, value objects, aggregates, domain events, repositories).

Bounded contexts are the most important idea for system design: each context has its own model and language (a 'Product' means different things to Catalog and Shipping), and they make natural boundaries for modules or microservices. Aggregates define consistency boundaries: invariants are enforced within one aggregate in one transaction, while cross-aggregate consistency is eventual.

Different departments, different vocabularies

To sales, a 'customer' is a lead with a pipeline stage; to billing, it is an account with invoices; to support, a person with tickets. DDD lets each department keep its own precise model instead of forcing one bloated 'Customer' on everyone.

02

When to use it

  • Complex business domains (insurance, logistics, finance, healthcare).
  • Finding service or module boundaries.
  • Teams struggling with inconsistent terminology and tangled models.
  • Designing consistency and transaction boundaries.
03

Where it shows up in interviews

Finding service boundaries

Recognize it when: how do you split this domain?

  • Design an insurance platform
  • Design a logistics system
  • Decompose an e-commerce monolith
Consistency boundaries

Recognize it when: what must be updated atomically?

  • Design a booking system
  • Design order and inventory models
04

Where it is used in real software

Event storming

A workshop technique by Alberto Brandolini where teams map domain events on sticky notes to discover contexts and aggregates.

Microservice boundaries

Many companies (Zalando, ING, Uber's domain-oriented architecture) align services with bounded contexts.

Axon and EventStoreDB

Frameworks combining DDD aggregates with CQRS and event sourcing.

05

Key terms

Ubiquitous language
Shared terms used by developers and domain experts, in code too.
Bounded context
Boundary within which a model and language apply consistently.
Aggregate
Cluster of objects treated as one unit for changes, with a root.
Value object
Immutable, identity-less object defined by its values (Money).
Domain event
Something important that happened (OrderPlaced).
Context map
Relationships between contexts (upstream/downstream, anti-corruption layer).
06

How it works, step by step

  1. 1
    Explore the domain with experts

    Event storming to find events, commands, and actors.

  2. 2
    Identify bounded contexts

    Where language and models change.

  3. 3
    Map context relationships

    Who depends on whom; add anti-corruption layers.

  4. 4
    Design aggregates

    Small, enforcing invariants in one transaction.

  5. 5
    Integrate with domain events

    Cross-aggregate and cross-context consistency is eventual.

07

Bounded contexts in e-commerce

Same word, different models

Step 1 / 5
Context'Product' meansKey aggregates
CatalogTitle, description, images, categoriesProduct
PricingPrice lists, discounts, currencyPriceList, Promotion
InventorySKU, stock per warehouseStockItem
OrderingLine item snapshot at purchaseOrder (with OrderLines)
ShippingWeight, dimensions, hazmat flagsShipment

NOWContext: Catalog | 'Product' means: Title, description, images, categories | Key aggregates: Product

Each context can be a module or service with its own data; they share IDs and events, not one giant Product table.

08

Implementation

// Value object: immutable, compared by valueexport class Money {  private constructor(readonly cents: number, readonly currency: "USD" | "EUR") {}  static of(cents: number, currency: "USD" | "EUR") {    if (!Number.isInteger(cents) || cents < 0) throw new Error("Invalid amount");    return new Money(cents, currency);  }  add(other: Money) {    if (other.currency !== this.currency) throw new Error("Currency mismatch");    return Money.of(this.cents + other.cents, this.currency);  }} // Aggregate root: all changes go through it, invariants enforced insideexport class Order {  private lines: { sku: string; qty: number; price: Money }[] = [];  private status: "draft" | "placed" = "draft";  readonly events: { type: string; orderId: string }[] = [];   constructor(readonly id: string) {}   addLine(sku: string, qty: number, price: Money) {    if (this.status !== "draft") throw new Error("Cannot modify a placed order");    if (this.lines.length >= 50) throw new Error("Too many lines");    this.lines.push({ sku, qty, price });  }   place() {    if (this.lines.length === 0) throw new Error("Empty order");    this.status = "placed";    this.events.push({ type: "OrderPlaced", orderId: this.id }); // other contexts react asynchronously  }}
09

Complexity and performance

Transaction scopeOne aggregate

Keep aggregates small.

Cross-aggregate consistencyEventual via events

Sagas for workflows.

10

Trade-offs

Model quality vs upfront effort

DDD needs time with domain experts and modeling skill; it pays off in complex domains, not in simple CRUD.

Small aggregates vs convenience

Small aggregates scale and avoid contention but require eventual consistency between them.

11

Variants and related techniques

Anti-corruption layer

Translate a legacy or external model at the boundary.

Shared kernel

A small model shared by two contexts, by agreement.

12

Common mistakes

  • One huge aggregate.

    Fix: Causes lock contention and big transactions; split by invariants.

  • Applying tactical patterns without strategic design.

    Fix: Bounded contexts matter more than repositories and factories.

  • A single canonical enterprise model.

    Fix: Let each context have its own model.

13

Interview questions

How do bounded contexts help design microservices?

Each bounded context has a consistent model and language and minimal coupling to others, making it a natural candidate for a service with its own data and team.

What is an aggregate and how big should it be?

A cluster of domain objects changed together through a root, enforcing invariants in one transaction. Keep it as small as the invariants allow; reference other aggregates by ID and coordinate them with domain events.

14

Practice problems

ProblemDifficultyWhat it trains
Identify bounded contexts for a ride-hailing appMediumStrategic design.
Design aggregates for hotel bookingHardInvariants and contention.