Skip to content
back to the episode
concise episode summary2022Fellow

Learning Domain-Driven Design — Chapter 2, Part 1

The episode maps business-logic models from Transaction Script and Active Record to a rich domain model and Event Sourcing. Selection follows subdomain complexity, invariants, and the value of history—not pattern prestige. As rules grow harder, the model must make them explicit and protect them from accidental bypass.

Code of Architecture · Book Club6 min read

This editorial retelling is based on the accepted automatic captions. Speech disfluencies and recognition errors have been removed; it is not a verbatim transcript.

The main thread of the material
01

Let complexity choose the tool

Transaction Script expresses a simple operation as steps that either all commit or roll back. Its traps appear early: writing to a database plus a file or external service creates a distributed transaction, while retrying a non-idempotent request after a lost response may apply an effect twice. It is economical for simple supporting and generic logic. It becomes harmful when core-domain rules scatter across procedures, duplicate, and diverge.

Active Record provides an object-shaped data interface for CRUD, reporting, and small services, but retains the limits of a simple model. State transitions with many invariants and business differentiation call for a rich domain model. It preserves essential domain complexity while isolating infrastructure concerns. Plain objects express nouns, actions, and rules in the ubiquitous language; storage and transport no longer dictate their form. This investment is contextual, not a universal default.

02

Give every rule an owner

A value object is identified by its values: equal colours or phone numbers are interchangeable, need no ID, and produce a new value when changed. An entity keeps its identity as attributes evolve and therefore has a stable identifier. Dedicated types for a name, phone number, or domain ID place validation beside meaning and prevent primitive values from being confused. The compiler can then reject some invalid states before runtime.

An aggregate groups entities and value objects whose invariants must hold within one transaction. External code changes state through the aggregate root, making rules difficult to bypass. Its boundary follows a business invariant, not the desire to load every related object: an oversized aggregate changes for unrelated reasons, increases contention, and becomes hard to understand. Other aggregates are referenced by identity and may converge later. A domain service can calculate a rule using several aggregates without turning them into one transaction. Domain events emitted by the aggregate describe completed facts and carry the information their consumers need.

03

Treat history as the state model

A conventional domain model stores current state; Event Sourcing makes an ordered stream of domain events the source of truth. Replaying the stream reconstructs an aggregate, reveals a past version, supports debugging, and enables projections that were not imagined when events were recorded. Stream versions also support optimistic concurrency: after a conflict, new events can be read and the application can decide whether the command remains valid. Crucially, domain events preserve the meaning of a change. A database log or Change Data Capture reveals which fields changed but cannot recover the business reason.

Costs include a steep learning curve, event-schema evolution, and support for replaying history. Snapshots accelerate long streams, while independent aggregates can be partitioned. An immutable log complicates deletion: sensitive data may live separately, be referenced instead of copied, or become unreadable after encryption keys are destroyed. Dual-writing current state and events creates two truths and a partial-commit risk. Event Sourcing is justified when history and causality are product capabilities, not a stack preference.

Takeaways

What to take away

  1. 01Transaction Script and Active Record fit simple logic; distributed effects, retries, and accumulating rules reveal their boundary.
  2. 02A rich domain model earns its cost in a core domain where invariants and state transitions matter more than direct table access.
  3. 03An aggregate boundary is the boundary of strict business consistency, not the entire graph of related data.
  4. 04Event Sourcing preserves meaningful history and enables new projections, but demands disciplined evolution, replay, and data deletion.

Sources

Share