The tactical patterns of DDD answer the question "how to express a domain model in code": Entity, Value Object, Aggregate, Domain Event. But that question has a predecessor that often gets skipped: where does the model itself come from? Why did "Order" become an aggregate and not "Cart"? Why is "address" a Value Object while "customer" is an Entity? The answers come not from the patterns but from the layer below — the domain's system of concepts. It's called an ontology, and it's the most underrated stage of DDD.

The ontology: what it is and why you already have one

A domain ontology describes the domain's concepts, their properties, relations and rules: "an order consists of line items," "an order has one customer," "a cancelled order cannot be paid." No code — meaning only.

The key fact: every project has an ontology even if nobody wrote it down. The team operates on concepts either way — just with a different version in each head. DDD practices are, at bottom, ways to make the system of concepts explicit and shared: knowledge crunching extracts concepts from experts, the ubiquitous language fixes the vocabulary, and bounded contexts draw the boundaries inside which words mean exactly one thing.

The second point matters too: a model is never "true" — only fit for purpose. A "customer" in the sales context and in the delivery context are two different concepts, and that's not disorder — it's the very reason bounded contexts exist: a context is a boundary of a system of concepts, not a folder in a repository.

How concepts become building blocks

Almost any ontology reduces to five elements: object, relation, state, event, rule. Now look at DDD's tactical vocabulary — it's the same five elements expressed in code:

Ontology elementIn the domain model
An object with identity ("this particular order")Entity / Aggregate Root
A value object ("address," "money amount")Value Object
A relation ("an order consists of line items")links inside an aggregate, or id references between aggregates
A state with transitions ("placed → paid," "no way out of cancelled")the aggregate's state model
An event ("order paid")Domain Event
A rule ("the sum of line items equals the order total")the aggregate's invariant

Hence a practical order of work: first honestly write out the concepts, relations, states and rules — as plain text, on a page; then these elements fall into the patterns almost mechanically. The aggregate boundary stops being an art: an aggregate is the cluster of concepts that must change atomically to preserve a rule. "Order + line items" are one aggregate precisely because the invariant "sum of items = order total" binds them into a whole.

When this ontology step is skipped and aggregates are "designed straight away," the patterns get draped over unexamined concepts: aggregates are cut along tables, Value Objects are never found (everything is an Entity), and invariants are discovered after the fact — in production.

An aggregate is not a table

A separate trap on this path is substituting the storage schema for the concept model. The symptoms are familiar: an aggregate "cut" exactly along a table; "order" and "line items" as two independent repositories because "they're two tables"; the concept of an "overdue payment" missing from the model because "it's just a WHERE."

The correct dependency direction is the reverse: the concept model is primary; the DB schema is a way to store it. One aggregate may live in three tables; the repository exists precisely to hide that from the domain. Design concepts → aggregates → and only then the schema, for queries and load. A detailed treatment of this trap is in "A conceptual model is not a database schema".

Ontology, spec, and AI

An explicit system of concepts now has a third consumer beyond the team and the code — the AI agent. A written ontology (vocabulary, states, invariants) is what turns a prompt into a specification: the agent doesn't guess whether a cancelled order can be paid — it's written down. The whole pipeline looks like this: ontology → domain model → spec → code (by human or agent) → acceptance against invariants. DDD and working with AI don't compete here — they stand on the same foundation: an explicit system of concepts. For the ontology basics outside the DDD context, see "A system of concepts: ontology in plain words".

In short

  • The domain model grows out of an ontology — the domain's system of concepts (concepts, relations, states, events, rules). DDD practices make it explicit and shared.
  • The five ontology elements map almost mechanically onto the tactical patterns: object → Entity/Aggregate, value → VO, state → state model, event → Domain Event, rule → invariant.
  • The aggregate boundary isn't an art but a consequence of the rules: an aggregate is a cluster of concepts changing atomically for the sake of an invariant.
  • An aggregate ≠ a table: the concept model is primary, the DB schema is storage, and the repository hides it from the domain.
  • An explicit ontology is the shared foundation of DDD and of working with AI: both the aggregates and the agent's spec grow out of it.

How to extract that system of concepts from the business — in the next article: Event Storming.