← back to the section

Before writing code, a spec, or a task for an agent, it is worth answering a question that is almost never asked out loud: what concepts is our problem made of, and how are they related?

Mismatched concepts used to be smoothed over by people: the analyst asks again, the developer guesses right, the tester notices. An agent does not ask again — it silently fills the gaps with plausible guesses. If "order" means one thing in your head, another in the task description, and a third in the database, the agent will implement a fourth.

This article covers the whole path: from "what is this problem made of" to a glossary used identically by the business, the team, and the agent — and on to a graph you can query.

Every project has a system of concepts

"An order consists of lines. An order has an owner — a customer. An order is settled by a payment. A cancelled order cannot be paid." That is a fragment of a domain description: four concepts, the relations between them, and one rule. The formal name for this is an ontology, but behind the intimidating word is something simple: a list of concepts, their properties, their relations, and their rules.

The important part: every project has such a system — the only question is whether it is written down. A team operates on concepts regardless. If they are not recorded anywhere, they live in people's heads, each with their own version. The product manager means one thing by "order," the developer another, support a third. All three versions work until they meet in the same sprint.

The first trap is looking for the "true" model of the domain. There is none. What is a "customer" for a shop? For marketing, a profile with a history of interests. For payments, a payer with billing details. For delivery, a recipient with an address. Three different models of one person, and trying to build one "universal" concept produces the worst of them all: a bloated notion inconvenient for everyone. The quality criterion for a model is not truth but fitness: does it help solve the problems it was built for, and does everyone read it the same way.

The second practical tool is noticing which level you are speaking at. Concepts stack in storeys: order #4211 from Ivanov for 3,400 → the type "order" (every order has a number, a customer, lines, a status) → "business entity" (orders, customers, payments — all entities with a life cycle) → the conventions by which we describe entities at all. Half the tangled arguments in teams are between people on different storeys: one is talking about a specific order ("but look, here is an order with no customer!"), the other about the type ("an order without a customer does not exist by definition"). Being able to say "we are on different levels" saves hours.

A conceptual model is not a database schema

The most common mistake at the start: hearing the task, an engineer opens an editor and draws tables. It feels like modelling. In fact a whole stage has been skipped, and skipping it is paid for later in schema rework and arguments about what we actually meant.

These are two different questions. A conceptual model answers: what concepts exist and how are they related — an order consists of lines, a payment belongs to exactly one order, a cancelled order cannot be paid. Not a word about tables or indexes. A database schema answers a different question: how to store it — in which tables, with which keys, what to denormalise for speed.

The same conceptual model maps onto dozens of schemas: normalised, denormalised for reads, document-oriented, event-based. Choosing a schema is an engineering trade-off against load and queries; choosing concepts is an agreement about meaning. When you jump straight to tables, the agreement about meaning is made silently, as a side effect of the storage structure.

A useful un-learning exercise: stop assuming a concept corresponds to a table.

  • One concept, several tables. "Order" lives in orders, order_lines, order_status_history — three tables, one concept.
  • One table, several concepts. users often mixes "account" (login, password, roles) and "person" (name, contacts) — two concepts with different life cycles, glued together by storage. That is where pains like "we deleted the user and lost the author of the orders" come from.
  • A concept with no table. "Overdue payment" is a full concept with rules, but in the database it is a WHERE condition, not a table.

If the conceptual model is not written down separately, the database schema becomes the conceptual model, compromises and all. A year later nobody remembers that gluing "account" and "person" together was an accident, and new features are built on top of it as if it were a deliberate decision. This has outward consequences too: the API starts to mirror the tables (user_id and joins leak out instead of domain concepts), every migration under load turns into a revision of meaning, and the argument "do we need a separate table for X" masks the unresolved question "is X a concept at all, or an attribute of Y?"

With an agent this matters twice over: give it only the DDL and it will honestly take the storage structure for the domain model, glue-ups and accidents included.

How to model before tables — an hour of honest work, no heavy tooling:

  1. Write out the concepts as nouns from the language of the business: order, line, customer, payment, refund.
  2. Relate them: "consists of," "belongs to," "refers to" — with cardinalities (an order has one customer; a customer has many orders).
  3. Write down states and rules: which statuses exist, which transitions are allowed, what is forbidden ("a cancelled order cannot be paid").
  4. Check it with the business: show the model to whoever owns the problem — at this level, unlike DDL, they can actually spot the error.

The result is a page of text or a simple diagram. The storage structure is designed from it — deliberately, against queries and load.

Ubiquitous language: the glossary as a contract

A conceptual model is useless if only you use it. Its power comes from the business, the code, and the agent speaking the same words. The practice is called ubiquitous language, and it is the most underrated idea in DDD: it is not about architecture, it is about no longer losing meaning in translation.

Look at how many translations an ordinary requirement goes through. The business says "the customer abandoned the cart." The analyst writes "a session with an unplaced order." The developer calls it abandoned_cart, while pending_order lives next to it in the code — "it is basically the same thing." The tester checks "an incomplete purchase." Four wordings, each with a slightly different meaning: almost the same, and "almost" is where defects come from.

Every translation is a point where meaning is lost. Ubiquitous language removes the translations: the word from the conversation with the business goes into the model, from the model into the code, from the code into the tests and into the task for the agent, unchanged. Hence a practical rule: if a concept in the code has no word from the language of the business, that is a signal. Either you invented an entity the domain does not have, or the business uses a concept your model is missing.

The other half of the idea, without which the first does not work: do not try to build one glossary for the whole company. We already saw it with "customer": for marketing, payments, and delivery those are three different concepts. That is not disorder to be defeated, it is the nature of domains. The answer is bounded contexts: ubiquitous language applies inside a boundary. Inside the payments context "customer" is always a payer with billing details, and nothing else. At the boundary there is an explicit translation: the event "order placed" becomes "a payer has appeared" — and that translation is written down rather than happening in someone's head.

All of this works only if the glossary is written. The format is minimal — a page: the term (and its name in the code, if different — though better if it is not), a definition in one or two sentences without "well, everyone knows what that means," the boundaries (which context it applies in, how it differs from the similar term next door), and states and rules if the concept has a life cycle. The sign of a living glossary: in review you can say "we have no concept of a subscription, we have a recurring payment" — and that is an argument, not a matter of taste.

For an agent the glossary is not reference material but a contract. It names entities the way the business does; it does not invent synonyms (Order, not Purchase in the second session); it respects the recorded state rules. Three sessions without a glossary produce three incompatible solutions — not because the model is bad, but because each time it is guessing your system of concepts from scratch. A glossary makes guessing unnecessary.

When there are many concepts: the knowledge graph

While the subject is one task or one service, a page of text is enough. At the scale of a product or a platform another need appears: you want to query the concepts you wrote down.

Ordinary document search finds fragments that are semantically similar to the question. That works well for "what is X" and badly for three kinds of question. Multi-hop: "which services will a change to the payment API contract affect?" — the answer is written nowhere as a single passage, it is derived along a chain of relations. Aggregating: "how many integrations with external providers do we have?" — that is a count over the whole knowledge base. Pinpoint: "who owns service X?" — there are many similar passages, but you need one reliable fact, not the closest paragraph. The common cause: text stores relations implicitly, smeared across wording.

A knowledge graph stores them explicitly, as facts of the form "subject → relation → object": "payment-service — consumes — orders-api," "orders-api — belongs to — team checkout." Nodes are concepts, edges are relations. And so the graph does not turn into a pile of arbitrary arrows, it needs a schema: which node types exist (service, team, contract) and which relations are allowed. That is exactly the system of concepts this article started with, only recorded strictly. A graph can be walked: from a contract to its consumers, from them to their dependants, as many hops as you like, with a verifiable result at each.

Pairing the graph with a model works like this: entities are extracted from the question, relations around them are walked, the resulting subgraph is mixed into the context, and the model formulates an answer from facts rather than similar paragraphs. The weaknesses cancel out: a graph does not understand natural-language questions — a model does; a model invents and does not chain reliably — a graph holds verifiable facts.

The graph has a price: it has to be designed, populated, and kept current — a stale graph is worse than none, because it lies confidently. So for "find and paraphrase" questions ordinary document search is enough, and a graph pays off where the questions are about relations and consequences: impact analysis, service and team dependencies, "which systems touch personal data."

And notice the familiar pattern: a registry of services with owners, contracts, and relations is the knowledge graph of your product, simply recorded in files. Conceptual model, glossary, and graph are one discipline at different scales: write concepts and relations down explicitly, and both people and agents can work from them.

In short

  • Every project has a system of concepts; the question is whether it is written down or lives in heads in differing versions.
  • A model is never true, only fit for its purpose; a universal concept "for everyone" is usually the worst for each.
  • Arguments across storeys (a specific order versus the type "order") cause half of all misunderstandings.
  • A conceptual model is not a database schema. An object is not a table: a concept can live in three tables, and a table can glue two concepts together. Fail to write the model down and the storage structure becomes it, accidents included.
  • The order is: concepts → relations with cardinalities → states and rules → check with the business. Tables come after.
  • Ubiquitous language is one word along the whole path from business to code and tests; every translation between jargons loses meaning.
  • One glossary for a whole company is impossible: words change meaning at context boundaries; inside a boundary the meaning is strict, at the boundary the translation is explicit and written down.
  • For an agent the glossary is a contract that removes guessing: without it every session reinvents your system of concepts.
  • When the questions become about relations and consequences, written concepts turn into a knowledge graph you can query; the price is keeping it current.