Skip to content

Agentic Domain-Driven Design

A request to “cancel an order” sounds clear until you ask what should happen next. Does it stop fulfillment? Release reserved inventory? Issue a refund? The answer depends on the business, the order's state, and which part of the system is handling it.

A coding agent can implement a plausible interpretation quickly. If the team hasn't agreed on the meaning, that speed can carry the wrong assumption into code, tests, and documentation. This is where domain-driven design becomes particularly useful: it gives people a way to make the concepts behind the software explicit.

After DDD Europe in June, Martin Fowler wrote (opens in new tab) that he expects domain-driven design to remain useful and potentially become more important as LLMs change programming. His observation captures what interests me here. The more implementation we delegate, the more clearly we need to express the system we intend to build.

Agentic Domain-Driven Design

Agree on what the words mean

Two ideas from Eric Evans's domain-driven design are especially helpful when working with agents.

The first is ubiquitous language: a shared vocabulary developed by the people who understand the domain and the people building the software. As Fowler explains (opens in new tab), that language should be used in conversation as well as in the model. Working through examples tests whether the words actually describe the business.

The second is a bounded context: a boundary within which a particular model and vocabulary are consistent. Fowler's explanation (opens in new tab) makes room for different meanings in different parts of a large system, with explicit relationships between them.

In a hypothetical commerce system, an account might mean a person's login in identity management and a billable organization in billing. Both meanings can be useful. Trouble begins when code silently treats them as interchangeable. Naming the boundary tells engineers and agents which meaning applies and where a translation is needed.

Identity and billing bounded contexts with explicit translation between different meanings of account
The same word can represent different concepts in different bounded contexts. Integrations must translate between those meanings explicitly.

This takes more than choosing better names. The team has to decide which concepts exist, how they relate, and what rules govern them. The vocabulary expresses that understanding.

Give the agent a definition it can reuse

A clarification in one conversation only helps later work if the agent can recover it. That may come from code, documentation, or remembered context. A concise glossary gives the team an explicit place to settle terms and review changes to their meaning.

Matt Pocock's domain-modeling skill (opens in new tab) takes this approach during design: challenge vague terms, test relationships with examples, and record a definition when it is agreed. It separates the glossary from implementation details and architectural decision records.

For the order example, a small entry could look like this:

**Order cancellation**:
A request to stop fulfilling an order. It does not by itself confirm a refund.
 
**Refund**:
A return of money previously collected for an order.

These definitions are illustrative; a real business may need different ones. Their value is that they expose a question before it becomes a hidden assumption. Can an order be cancelled after shipment? Who decides whether a refund is due? The discussion can then refine the model.

Pocock also discusses the value of shared vocabulary in this talk:

What the evidence does and doesn't show

A semantic erosion experiment (opens in new tab) tested whether coding agents preserved domain terminology across ten rounds of refactoring in a synthetic Java royalty-management system.

Neutral requests to improve readability preserved the terminology in every tested configuration. Explicit pressure to rename overly specific concepts caused losses that varied by model and harness. Providing domain context through a glossary preserved the tracked terms in the tested controls while still allowing substantial refactoring.

The limits matter. Most configurations ran once, the subject was one synthetic codebase, and differences in thinking configuration complicate comparisons between harnesses. Preserving a name also doesn't prove that the implementation preserves its meaning.

I take this as a reason to include domain language in refactoring reviews. A name that looks unusually specific may encode a distinction the business depends on. An agent needs enough context to recognize that distinction before simplifying it away.

Connect the language to the work

A glossary only helps if it reaches the agent when the task needs it. This is a practical part of context engineering: deciding which information belongs in the model's working context.

For a billing change, I would provide the billing definitions, relevant rules, and the interfaces to neighboring systems. A bounded context helps organize that material. It doesn't eliminate the need to understand an integration when the change crosses a boundary.

The workflow I would use is small:

  1. Resolve ambiguity with an example. Ask what happens in a specific scenario until the team agrees on the behavior.
  2. Record the meaning. Keep the glossary entry short and focused on the concept. Put implementation details in the document or code that owns them.
  3. Use the term consistently. Carry it into interfaces, tests, and task descriptions so the next change starts from the same understanding.
  4. Make the definition discoverable. Point to the relevant glossary from repository instructions or a task-specific skill.
  5. Review meaning as well as naming. If behavior changes, check whether the definition and affected code still agree.

When a choice has consequences that will be hard to reconstruct later, an architecture decision record can preserve the reasoning. A glossary shouldn't have to carry the entire history of the design.

Keep the language useful

A glossary can become stale or collect details that belong elsewhere. It can also make an incorrect assumption look authoritative, especially if an agent writes definitions that nobody reviews.

I would introduce one when recurring ambiguity starts costing the team time. I would split it by context when the domain requires that separation, and revise it when our understanding changes. The amount of documentation should follow the problem.

What I want from DDD in agent-assisted work is a shared model that people understand and the implementation respects. Clear language gives us a way to discuss that model, direct changes to it, and notice when the code has drifted from what we meant.

Related writing