← all articles

A Dependency In Prose Is Not A Dependency

A Dependency In Prose Is Not A Dependency

If a change genuinely has to happen before another one, and the only place that says so is a sentence in a description, you don't have an ordering constraint. You have a constraint that currently happens to be respected, by people who currently know to look for it, which is a very different and much more fragile thing.

I saw this pattern again this week in a pair of related changes: a server-side update and a client-side update to the same feature, with a note attached to one of them explaining that the server change needed to go out first. The note was clear. The reasoning was sound — the client would send a shape of request the old server didn't understand, so releasing client-first would break things for anyone caught in between. Nothing about the explanation was wrong. What was missing was any mechanism that made the explanation matter. Nothing in the pipeline checked deployment order. Nothing in the code refused to run against an incompatible partner. The entire constraint lived in the willingness of whoever pressed the deploy button to have read that paragraph, remembered it, and acted on it in the right sequence, possibly days later, possibly by a different person than the one who wrote the note.

That gap is easy to miss because most of the time nothing goes wrong. The person who writes the constraint down is usually also the person who enforces it by hand, so the prose and the reality line up. The failure only shows up later, when the work gets picked up by someone else, when a release gets reordered under pressure, when two changes land in the same deployment window and nobody double-checks which one the automation actually ran first. By the time it breaks, the person debugging it has no reason to suspect an ordering problem, because nothing in the system said ordering mattered. They'll read logs, check configuration, maybe blame the network, long before they think to go back and read a description field on a change that merged a week ago.

This is really a special case of a much broader habit worth building: if something must be true for the system to behave correctly, encode it somewhere the system checks, not somewhere a human has to remember to check. A comment that says "don't call this with a null customer ID" is weaker than a type that can't hold null. A wiki page that says "always run the migration before deploying this version" is weaker than a startup check that refuses to boot against an incompatible schema. A description that says "server first" is weaker than a feature flag the client respects until the server confirms it understands the new shape, or a version negotiation that lets the client detect what it's talking to and behave accordingly. None of these mechanisms are exotic. They're just work, and the work is easy to skip because the prose version looks like it solved the problem. It compiles. It reads clearly. It even works, for a while.

The reason this is worth taking seriously rather than filing under "nice to have" is that ordering dependencies are exactly the kind of failure that's cheap to prevent and expensive to diagnose. Preventing it usually means a small amount of defensive code or a gate in the deployment pipeline — hours, not weeks. Diagnosing it after the fact means someone reconstructing, under pressure, why a system that looked fine in isolation broke the moment two pieces met in the wrong order, with a production incident and possibly a customer conversation riding on how fast they can work it out. That asymmetry is the whole argument. It's not that documentation is worthless — the explanation of why the order matters is genuinely useful, and I'd rather have it than not. It's that documentation and enforcement are solving different problems, and treating the first as a substitute for the second is where the risk actually lives.

There's a judgement call buried in here, and it's worth naming honestly rather than pretending every ordering constraint deserves a pipeline gate. Building real enforcement costs something — engineering time, a bit more complexity in the deployment process, sometimes a genuinely awkward bit of backward-compatibility code that only exists to smooth over a two-week window. For a constraint that's low-stakes, rare, or about to become irrelevant anyway, a clear note and a trusted team might be the right call, and I wouldn't want to see that team spend a day building a mechanism to protect against a mistake that would cost twenty minutes to fix. The point isn't that every dependency needs a machine watching it. It's that the decision to rely on prose instead of enforcement should be made on purpose, weighing the actual cost of getting it wrong, rather than happening by default because writing the sentence was easier than building the check and nobody stopped to compare the two.

What I've started doing differently, partly because of incidents like this one, is treating any sentence that starts with "make sure to" or "this needs to happen before" as an open question rather than a finished thought. The question is simple: what happens if nobody reads this in time? If the honest answer is "a customer sees broken data" or "a service starts throwing errors" or "someone loses an hour figuring out why two things that both deployed cleanly don't work together," that's a strong signal the constraint belongs in code or configuration, not in a paragraph next to the change. If the honest answer is "someone notices within a day and it's a minor annoyance to fix," prose might genuinely be enough, and adding machinery would be solving a problem that doesn't justify its own cost.

The underlying discipline is the same one that shows up everywhere reliable systems get built: don't ask people to be the mechanism that holds an invariant together if you can ask the system instead. People are good at judgement, at handling situations nobody anticipated, at noticing when something looks wrong even without a rule telling them to look. They're bad at reliably remembering a specific fact at a specific future moment under the ordinary pressure of shipping the next thing. Write the constraint down for the humans who'll want to understand why it exists. Then build something that doesn't need them to remember it.

Matthew Ratcliffe, software developer and architect, Ballarat
Senior Software Engineer & Architect

20+ years across the technology stack — from greenfield builds to brownfield rescues. Based in Ballarat, VIC, focused on AI, healthcare and high-risk data systems. Full resume →

Share your thoughts