Building Software

Engineering Fundamentals for the Agent Era

Contents Section 1, Intent

Domain Modeling and Invariants

Mistakes to catch in review

  1. A lifecycle modeled as scattered booleans (isPaid, isShipped, isCancelled) that allows impossible combinations such as shipped but never paid.

  2. A rule enforced in the main code path and skipped in the bulk import, the admin tool or the background job.

  3. One 'user' object stretched to mean customer, administrator and billing contact, so a change for one breaks the others.

Naming the things in the problem, their lifecycles and the rules that must always hold, so code and tests can enforce them.

Topics

Entities, Values and Relationships
Identifying the nouns of a domain, which of them keep an identity over time, and how they relate to each other.
A Shared Language
Using the same names in conversation, specs, code and database, so business rules can be checked by reading them.
Lifecycles as State Machines
Modeling orders, accounts and jobs as explicit states with allowed transitions instead of loose flags.
Invariants
Rules that must hold at every moment, such as a balance never going negative or every order having exactly one owner.
Bounded Contexts
Recognizing that the same word means different things in different parts of a business, and drawing lines between those parts.
Making Illegal States Unrepresentable
Choosing types and schemas so invalid combinations cannot be constructed in the first place.
Properties a Machine Can Check
Stating an invariant precisely enough for a property test or a model checker to try to break it; agents can now carry the proof, so stating the property is the part that stays with you.

You understand it when you can

  • Draw the state machine for an order or subscription, including which transitions are forbidden.
  • State three invariants for a system you use daily and say where each one should be enforced.
  • Given a bug report, identify which domain rule or invariant was violated.

Drill

An agent modeled subscriptions with the fields isActive, isTrial, isCancelled and isPastDue. Find a combination of values that the business says is impossible, then redraw the model as a state machine that cannot represent it.

Start here

Watch

What is DDD - Eric Evans - DDD Europe 2019

Eric Evans, 2019. 57-minute talk.

The originator of domain-driven design explains ubiquitous language and bounded contexts, including why one word such as 'user' should mean different things in different contexts.

Read

Learning Domain-Driven Design: Aligning Software Architecture and Business Strategy

Vlad Khononov, 2021.

A modern, compact introduction to ubiquitous language, bounded contexts, aggregates and where invariants are enforced, written for working developers.

Domain Modeling Made Functional: Tackle Software Complexity with Domain-Driven Design and F#

Scott Wlaschin, 2018.

Teaches encoding lifecycles as state types and constraints as wrapper types, making illegal states unrepresentable; the ideas carry directly to TypeScript discriminated unions.

Domain-Driven Design: Tackling Complexity in the Heart of Software

Eric Evans, 2003.

The original source for entities versus value objects, aggregates as invariant boundaries, and bounded contexts.

Primary sources

  • Reference

    Parse, don't validate (Alexis King)

    Explains why checking a rule once and passing raw data along lets the bulk import or admin path skip it, and how parsing into a stronger type makes the invariant hold everywhere.

  • Reference

    BoundedContext (Martin Fowler)

    A short, canonical definition of bounded contexts with the example of one term meaning different things in sales and support.