Part 2 · 2 chapters · ~12 min

DDD Tactical Patterns

Entities and value objects, aggregates as consistency boundaries, repositories per aggregate, domain events, domain services, bounded contexts and ubiquitous language, context maps and anti-corruption layers, and where DDD is overkill.

4

Entities, value objects, aggregates

code
// value object: immutable, compared by value, validates itself
export class Money {
  private constructor(readonly kobo: bigint, readonly currency: 'NGN' | 'USD') {}
  static of(kobo: bigint, c: 'NGN' | 'USD') { if (kobo < 0n) throw new Error('negative'); return new Money(kobo, c); }
  plus(o: Money) { this.same(o); return new Money(this.kobo + o.kobo, this.currency); }
  private same(o: Money) { if (o.currency !== this.currency) throw new Error('currency mismatch'); }
}
// aggregate root method: rules live here, not in controllers
hold(amount: Money, ref: string): void {
  if (this.available().lt(amount)) throw new InsufficientFunds(this.id, amount);
  this.holds.push(new Hold(ref, amount)); this.events.push({ type: 'FundsHeld', accountId: this.id, ref });
}
AN AGGREGATE AND ITS BOUNDARY
one consistency boundary, changed through its root
Account (root)enforces: available ≥ 0Holdamount, expirydomain eventFundsHeldPayout (another aggregate)referenced by id only
swipe the figure sideways, or tap expand for full screen
1/4
the root
An aggregate is a cluster of objects changed together and kept consistent in one transaction. Outside code talks only to the root, which enforces the invariants.
one root guards the rulesinvariant: available ≥ 0
5

Bounded contexts and translation

The word "account" means a ledger account to finance, a login to identity, and a customer to support. A bounded context is the boundary inside which one meaning holds. Between contexts, translate explicitly: an anti-corruption layer maps a partner's or legacy system's model into yours so their naming and quirks do not leak in (a bank rail's status codes become your PayoutState).

context relationshipmeaning
customer / supplierdownstream needs are negotiated into the upstream roadmap
conformistdownstream adopts upstream's model as is (common with big vendors)
anti-corruption layerdownstream translates to protect its model
published languagea shared, versioned schema (events, ISO 20022 messages)

Overkill for CRUD and reporting; worth it in the core domain where rules are subtle and costly to get wrong.