chapter three

3 Building the domain core

 

This chapter covers

  • Building domain entities that enforce business invariants at construction time
  • The Always-Valid Domain Model: Why invalid objects should never exist
  • Factory methods as the only gateway into your domain
  • Value objects that make implicit concepts explicit
  • Domain services for logic that spans multiple entities
  • Validation strategies: What works, what fails, and the recommended approach

We’ve mapped the five migration phases for WriteFlow. Phase 1—Extract the domain—is where we start building. Most teams reach this point after the hard part is already done: stakeholders are aligned, the migration has been approved, and everyone agrees the current system is too fragile to evolve safely. What comes next is often less obvious. When you start from the middle of the hexagon, you are solving a very specific problem: how to rebuild the business core so that invalid states become impossible, rules live in one place, and the domain can evolve independently of frameworks.

3.1 What lives inside the domain layer

3.2 Three principles that shape the domain

3.3 The Always-Valid Domain Model

3.3.1 What not to do: Validation after construction

3.3.2 The recommended approach: validateThenCreate

3.3.3 An alternative: canBeCreated

3.3.4 A note on records

3.4 Value objects: Making implicit concepts explicit

3.5 Domain services

3.6 Factories

3.7 Model identity: Filling the gap

3.8 Two kinds of validation

3.8.1 Input validation with the Validation monad

3.9 Guard clauses

3.10 Summary