Review a model
A review pass applies every rule, reports every problem, and keeps unknowns visible.
After this page, you can:
- run a quick self-check on a model
- spot the four structural shapes that need a closer look
- ask whether a history has one business identity
- name the main risks of facts that come from another system
Review in a second pass
You review a model in a different pass than you build it. In a review, apply every rule and report every problem. Do not quietly add missing parts. Write findings as comments or tasks, so the team can decide.
Start with this fast check. Answer yes or no to each line:
- Is every Event a past-tense business fact?
- Is every Command an imperative business intent, not a query?
- Is every Read Model named for its data?
- Does any Event hold a computed or summed value?
- Does every Command have one issuer, and does that issuer trace to a Screen or an Automation?
- Does the timeline start with a State View or with an Automation that reacts to an Event?
- Is there a State Change that follows a State Change with no new trigger?
- Does any Screen start more than one Command?
Four shapes to look at twice
Four shapes in the connections often point to a problem. The team uses nicknames for them. Do not use the nicknames with business people. Ask the plain question instead.
| Shape | What you see | How strong | Plain question for the business |
|---|---|---|---|
| Bed | One Screen starts more than one Command. | Always a problem. | This Screen lets someone choose between several actions. Is it clearer if each action is its own step? |
| Left chair | One Command records more than two Events. | A candidate. | When this action works, do all of these facts always happen together? |
| Right chair | One Read Model uses more than three Events. | A candidate. | Does this Screen answer one question or several? |
| Shelf | One slice has far more examples than its neighbors. | A candidate. | Is this step doing more, or does it cover something that needs its own step? |
A count alone does not prove a problem. Read the Events, the fields, and the examples first. Flag a candidate only if it shows several jobs. Drop it if the domain explains it.
Is the data complete?
Check the fields of the whole model, using the model and not your memory.
- Each Event field has an origin and at least one use.
- Each Command input reaches an Event.
- Each field that a Read Model shows comes from a connected Event.
- Each derived value has inputs that you can trace.
Before you call data missing, look for it elsewhere in the model. Then walk the whole story from the start to each end. Include cancellations, failures, and repairs.
A gap has a typical fix. A view field that no Event supplies needs a new field on an Event, or you drop the view field. A calculation that you modeled as an Event moves to a Read Model. A missing failure path needs a new Event.
One history, one identity
Every history of Events must answer one question: the history of which one thing? The answer is one business identity, such as an order ID. "All orders" is a wrong answer.
Length is not the problem. A bank account that is open for thirty years has a long history, and that is fine. The problem is mixed content. Compare these cases:
| What you find | What it means | What to do |
|---|---|---|
| All Events belong to one clear thing. | The boundary is right. | Keep it, however long it is. |
| Events describe a category, such as all orders. | A collection pretends to be a thing. | Keep one history for each order. Show the category in a Read Model. |
| Users, orders, and payments mix in one history. | A log pretends to be a thing. | Use one history for each kind of thing. |
| An active thing and its archive mix. | Two lifecycles are tied together. | Split them if their lifetimes and users differ. |
A rule decides how many earlier facts it needs. The rule "this customer must be registered" needs the registration for that email only. The rule "not already subscribed to this course" needs the subscriptions of that email and that course. Do not pull in more facts than the rule needs.
Facts from another system
When a fact comes from outside, translate it before your model uses it. Seven principles guide the work:
- Correlation first. Record the link between your ID and the outside ID when you start the outside action. Recover your ID before you record a fact.
- Translate the meaning, not only the field names. Convert units and formats, such as cents to a decimal amount.
- Do not leak. Do not use an outside ID as your main ID. Do not copy the outside data shape into your Events.
- Make it idempotent. Idempotent means safe to run twice. A repeated message must not record the same fact twice.
- Validate every message.
- Fill gaps from your own data. Enrich from your system. Ignore what you do not need.
- Choose a default or fail with a clear reason. Do not assume in silence.
Write an example for each of these cases of a translation:
- The message has no link to your ID.
- The message arrives before your thing exists.
- The message arrives twice.
- The message has missing or partial data.
- Messages arrive in the wrong order.
Questions and decisions
A model often holds open questions. Write a genuine question as a comment that stays open until someone answers it. Do not delete the comment. Answering it resolves it. A hotspot is a red note beside the element that has a problem or a dispute. It is not an Event.
Do not hide a gap by guessing. If you fill a gap yourself, say so in a note, so that a person can confirm it. A model with a material open question is not ready to build.
Check yourself
One Screen has the buttons Approve and Reject. Each starts a different Command. Which shape is this, and how strong is it?
Answer
It is the shape that the team calls the bed. It is always a problem. Split it into two Screen states.
A history is called Orders and holds the Events of all orders. What is wrong?
Answer
It is a collection with no single business identity. Keep one history for each order, and show the full list in a Read Model.
A payment provider sends the same message twice. What must your model do?
Answer
Record the fact once. The translation must be idempotent. Keep the outside ID to detect the repeat.
A Read Model uses five Events. Is that wrong?
Answer
Not by itself. Five Events are a reason to look closer. Check whether the Read Model answers more than one question. Keep it if one question needs all five.
A Read Model field has no Event that supplies it. What are two fixes?
Answer
Add the field to an Event that already exists, or remove the field from the Read Model.
Remember:
- Review in a separate pass. Report problems. Do not fix them in silence.
- Four shapes need a second look. Counts start a review. They do not end it.
- Every history has one business identity.
- Translate outside facts: correlate first, record once, and do not leak foreign IDs.