Short answer
#The five passes
-
What runs, and where
Environments, what is deployed to each, what runs on a schedule, and what runs that is not in the repository. From the cloud console and the crontabs, not from a conversation.
-
The inventory
Every component with a canonical type and one readable sentence. Services, modules, databases, queues, scheduled jobs, front ends, external systems.
Canonical type matters: free-text kinds mean two analyses of the same system produce lists that cannot be compared.
-
The relationships
What uses, depends on, reads from, writes to or implements what — and in which direction. Direction is not decoration; it decides what breaks when something stops.
-
The edges
Interfaces exposed and consumed. For each: the route or channel, what it is for, how it authenticates, and what happens when it fails.
The last two are where a plausible implementation and a correct one look most alike.
-
What could not be established
Every question the passes above raised and did not answer, with a reason and a priority. Recorded on the map rather than left out of it.
#What to record per element
| Field | Why it earns its place |
|---|---|
| Type | Canonical, from a fixed set — so two maps of the same system are comparable. |
| Name | What people call it. Useful, and not identity. |
| Purpose | One or two sentences a non-programmer can read. This field decides whether the map is usable by the person paying for it. |
| Location | A relative repository path, where one exists. Never absolute. |
| Stable identifier | See below. The field everybody forgets and the one the map depends on. |
| Confidence | So a guess does not read as a fact. |
| Evidence | Where it was established — a file and a line range. Turns the map from testimony into something checkable. |
#The field everybody forgets
A map without stable identity works perfectly the first time and stops working on the second update.
To say later that a component changed — rather than that one vanished and another appeared — the two versions of the map have to agree that they are describing the same thing. Names cannot carry that:
- Rename a class and it is still the same class.
- Call two things "Main database" and they are still two different things.
- Move a file and every path-based identity breaks at once.
So give each element something stable to be recognised by: a repository path, a fully qualified name, or a label you choose and keep for things with neither — a database, a queue, a deployment target, a cloud resource. An element with none of the three is a new thing every time the map is rebuilt.
SERVICE Billing service
path: app/Services/Billing/
fqn: App\Services\Billing\BillingService
DATABASE Main database
external id: db.main
(no path, no qualified name — the label is the identity)
QUEUE Payment queue
external id: queue.payments
The two external identifiers are chosen once and never changed. That is the
whole discipline: if somebody renames the queue in the infrastructure next
year, the label stays queue.payments and its history survives.
#One system, five hierarchies
A component belongs in more than one tree at once, and flattening them is what makes most architecture documents feel almost right.
A payment service sits inside an application, inside a deployment, and inside a business capability. Those are three different parents, and forcing them into one hierarchy loses information every time.
- Application — what the software is made of, in software terms.
- Business — what it does, in the company's terms.
- Organization — who owns what.
- Deployment — what runs where.
- Data — what information exists and where it lives.
You do not need all five on day one. You do need to record containment as belonging to a named view rather than as a single tree, or the second view is a rewrite rather than an addition.
#When to draw a diagram
After the list exists, not before. A diagram drawn first becomes the thing people argue about, and it encodes decisions — what to include, what to merge, what to leave out — that should be made from evidence rather than from what fits on a slide.
Once the list exists, a diagram is genuinely useful and cheap: it is a view of something you already have. Two rules keep it honest:
- Date it and say what it was derived from. An undated diagram is unfalsifiable.
- Do not let it become the source. When the diagram and the analysis disagree, the analysis is the one with citations attached.
#Keeping it true
A map is only worth having while it is still true, and the failure is always the same: it is produced once, as a project, and then nobody owns updating it.
Two things prevent that:
- Make rebuilding cheap. If updating the map costs an afternoon of somebody's attention, it will not happen. If it costs one instruction, it will.
- Rebuild on events, not on a calendar. After a release, at the end of an engagement, when a subsystem lands, before a handover. A quarterly cadence produces updates nobody reads and misses the ones that mattered.
The value is then in the difference between two versions rather than in either one — what arrived, what changed, what went away, and which earlier statements are no longer supported.
#What goes wrong
Drawing before listing.
Instead The list is the artefact; the diagram is a view of it. Drawing first encodes decisions nobody made deliberately.
Free-text component types.
Instead A fixed vocabulary. “Service”, “svc”, “microservice” and “backend service” are four names for one thing and make two maps incomparable.
No stable identifier.
Instead Path, qualified name, or a chosen label. Without one the map cannot have a history.
Omitting what could not be established.
Instead Record it. A map with no gaps has either come from a complete analysis or has quietly turned its gaps into silence.
One giant hierarchy.
Instead Record containment per view. A component legitimately has different parents in the deployment and in the business.
#What a map cannot tell you
What this does not do
- Why it was built this way. A map records what exists; the reasoning lives in people.
- Whether the architecture is good. There is no quality judgement and no score.
- What happens at runtime — load, latency, what a specific user sees.
- Anything configured only outside the repository, which appears as an open question rather than as a component.
- Whether it is secure. A map is not a vulnerability assessment.