Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Domain Model

Pattern

A reusable solution you can apply to your work.

A domain model captures the concepts, rules, and relationships of a business problem in a form that both humans and software can reason about.

“The heart of software is its ability to solve domain-related problems for its user.” — Eric Evans, Domain-Driven Design

Also known as: Conceptual Model

Understand This First

  • Data Model – a data model implements a subset of the domain model in a storable form.
  • Requirement – requirements reveal which domain concepts the software must represent.

Context

Before you write code, before you choose a database, before you direct an agent to build anything, you need to understand the problem domain. A domain model is that understanding made explicit: a structured representation of the real-world concepts your software deals with, the rules those concepts follow, and how they relate to each other.

This operates at the architectural level, above any particular technology choice. Where a data model answers “what does the system store?”, a domain model answers a broader question: “what does the business actually do, and what concepts matter?” A data model for a shipping company might have tables for shipments and addresses. The domain model captures those entities too, but adds rules like “a shipment can’t be delivered before it’s dispatched” and distinctions like “a billing address and a shipping address serve different purposes even though they look identical.”

Problem

How do you build software that faithfully represents a real business when developers (or agents) don’t share the domain expert’s understanding of how that business works?

Software that misunderstands the domain produces subtle, expensive bugs. An e-commerce system that treats “order” as a single concept will struggle when it discovers that a pending order, a fulfilled order, and a returned order follow completely different rules. The code grows a tangle of conditional checks because the underlying model never distinguished these concepts. When an AI agent works in that codebase, it reads the tangled code, infers the wrong rules, and generates more code that entrenches the misunderstanding.

Forces

  • Domain experts think in business concepts; developers think in code structures. The translation between these worlds loses information.
  • Simple models are easier to understand but can’t represent important domain distinctions. Rich models capture nuance but take longer to learn.
  • The domain itself evolves. Regulations change, business processes shift, and new product lines introduce concepts that didn’t exist when the original model was built.
  • Agents need explicit, unambiguous concepts to generate correct code. Tacit knowledge that experienced developers carry in their heads is invisible to an agent.

Solution

Build the domain model collaboratively with people who understand the business. Identify the core entities (Customer, Order, Shipment), the rules that govern them (an order must have at least one line item; a shipment can’t exceed its carrier’s weight limit), and the relationships between them (a customer places orders; an order triggers shipments). Write these down in a form the whole team can reference.

A good domain model isn’t just documentation. It lives in the code as objects whose methods enforce the business rules directly. Martin Fowler calls this “an object model of the domain that incorporates both behavior and data.” A Shipment object doesn’t just store a status field; it exposes a dispatch() method that checks preconditions and transitions the state. This matters because agents generating code from a well-structured domain model produce objects that enforce rules, not passive data containers that push rule-checking into scattered conditional logic elsewhere.

The model doesn’t need to start as a formal diagram, though diagrams help. What matters is that it’s explicit and shared. Eric Evans, who introduced domain-driven design, argued that the most productive teams speak a single language drawn directly from the domain model. When a developer says “aggregate” and a product manager says “order bundle” and they mean the same thing, everyone wastes time translating. When both say “order group” because that’s the term in the model, communication gets faster and code gets clearer.

For agentic workflows, include the domain model in the agent’s context as a reference document: a glossary of terms, a list of entities with their rules, a map of relationships. The agent then generates code that uses the right names, respects the right constraints, and organizes logic around the right concepts. Without this, the agent invents its own vocabulary, and you spend your review time untangling naming inconsistencies instead of evaluating logic.

How It Plays Out

A team building a veterinary clinic management system sits down with the clinic staff. They learn that “appointment” means something different from “visit.” An appointment is a scheduled slot; a visit is what actually happens when the animal arrives. Appointments can be canceled. Visits can’t, because they represent something that occurred. This distinction shapes the entire data layer: appointments live in a scheduling module, visits live in the medical records module, and a visit links back to the appointment that triggered it but follows its own lifecycle.

When the team later directs an agent to add a billing feature, they include the domain glossary in the prompt: “An invoice is generated from a visit, not an appointment. A visit may produce multiple invoices if treatments span different insurance categories.” The agent builds the billing logic correctly on the first pass because the domain model told it exactly which concept to attach invoices to.

Example Prompt

“Read the domain glossary in docs/domain-model.md. Then add a waitlist feature to the scheduling module. A waitlist entry is created when no appointment slots are available. It references a patient and a preferred provider but has no scheduled time. When a slot opens, the system should suggest the longest-waiting entry.”

Consequences

A shared domain model reduces miscommunication between business experts, developers, and agents. Code organized around domain concepts is easier to navigate because the software’s structure mirrors the problem it solves. New team members and new agents ramp up faster because the model provides a map of the territory.

The cost is upfront effort. Building a domain model requires conversations with domain experts, and those conversations take time. The model also needs maintenance: as the business evolves, the model must evolve with it, or it becomes a misleading artifact. Teams sometimes over-model, capturing distinctions that don’t matter for the software they’re building. A practical test: if a concept distinction doesn’t change how the code behaves, the model doesn’t need it yet.

There’s also a temptation to design everything upfront. Resist it. Start with the concepts you need for the features you’re building now. Expand the model as new features demand new distinctions. The model grows with the software, not ahead of it.

  • Uses / Depends on: Data Model – a data model implements a subset of the domain model in a storable form.
  • Enables: Schema (Database) – the database schema encodes domain model entities as tables and constraints.
  • Enables: Boundary – domain boundaries (bounded contexts) map to system boundaries.
  • Enables: Cohesion – modules that align with domain concepts tend to be highly cohesive.
  • Contrasts with: Data Structure – data structures are implementation-level; a domain model is conceptual.
  • Enables: Ubiquitous Language – the domain model identifies concepts; the ubiquitous language gives them authoritative, shared names.
  • Enables: Naming – the domain model identifies the concepts that need names in code.
  • Uses / Depends on: Requirement – requirements reveal which domain concepts the software must represent.

Sources

  • Eric Evans introduced domain-driven design as a discipline in Domain-Driven Design: Tackling Complexity in the Heart of Software (2003). The core ideas in this article — building the model collaboratively with domain experts, speaking a single language drawn from the model, and organizing code around domain concepts rather than technical layers — originate in that book.
  • Martin Fowler cataloged the Domain Model as a pattern for organizing domain logic in Patterns of Enterprise Application Architecture (2002), defining it as “an object model of the domain that incorporates both behavior and data.” The article quotes this definition directly.
  • The concept of bounded contexts — domain boundaries that map to system boundaries, referenced in the Related Patterns section — was introduced by Evans in the same 2003 book as part of his strategic design vocabulary.

Further Reading

  • Vaughn Vernon, Domain-Driven Design Distilled (2016) – a shorter, more accessible introduction to Evans’s ideas. Good starting point if the original feels too heavy.