The bulk of a system’s cost is not in writing it. It is in the years afterwards: keeping it running, understanding it well enough to change it, and adapting it to things nobody anticipated.
“Maintainable” on its own is a compliment, not a property. Split into three, it becomes something you can actually check.
Operability: can the people on call succeed?
Good operations can keep bad software running. The reverse — good software surviving bad operations — is much rarer.
Operability is the set of affordances that let the humans responsible for a system do their job, and it is mostly unglamorous:
- Visibility into runtime behaviour. Not just “is the process up” but what it is doing: queue depths, error rates by endpoint, saturation of the thing that saturates first.
- Support for automation. Anything done more than twice at 3am should be a command, not a checklist.
- No dependence on individual machines. If a specific host’s death requires a specific person’s memory, the system is not operable — it is a hostage situation.
- Documentation that matches reality, especially an operational model: what it does when healthy, what the failure modes look like, and what to do about each.
- Predictable behaviour, and good defaults — with the ability to override them when the situation is not the predicted one.
- Self-healing where possible, manual control where necessary. An automated failover that cannot be stopped by a human who understands the situation is a liability during an incident it was not designed for.
Simplicity: whose complexity is it?
Every non-trivial system is complex. The useful distinction is where the complexity comes from.
The idea
Essential complexity is inherent in the problem: tax rules really are that convoluted; distributed consensus really is that hard. Accidental complexity is complexity you introduced that the problem did not require. Only the second kind can be removed, and it is usually the larger share.
Accidental complexity has recognisable symptoms: tangled dependencies where everything imports everything, inconsistent naming for the same concept, special cases bolted on to work around a bad abstraction, and state whose ownership nobody can state clearly.
The main tool against it is abstraction — but abstraction earns its keep only when it actually hides something. A good abstraction lets you use a component without reading its internals, and lets you change those internals without breaking anyone. An abstraction that requires you to understand its implementation to use it correctly has added a layer and removed nothing.
Evolvability: how expensive is the change you have not thought of yet?
Requirements change. The measure of evolvability is how much a change costs relative to how big it sounds.
The reliable sign of trouble is when a small-sounding change touches many places. “Add a middle name field” should not require edits in nineteen files — and when it does, the cause is almost always the same: one concept represented in nineteen slightly different ways, with no single owner.
Evolvability is mostly downstream of simplicity, which is why the two are hard to argue about separately. A simple system is one you can hold in your head; a system you can hold in your head is one you can safely change.
Making the claim checkable
If someone says a system is maintainable, the follow-up questions are:
- Operability. When it broke last, how long until someone knew? How long until they knew why? Was the runbook right?
- Simplicity. How long until a new joiner shipped something to production? What did they get wrong, and was it their fault or the system’s?
- Evolvability. Name the last small-sounding change. How many files? How long? Did it break something unrelated?
These have answers. “It’s pretty clean” does not.
Check yourself
A service has 14 payment-provider integrations behind one interface. Each provider genuinely has different auth, retry semantics and settlement timing. A new engineer needs two weeks to add the fifteenth. What is the most defensible reading?
What to take away
Maintainability decomposes into three properties with observable consequences. Operability is about the humans on call. Simplicity is about which complexity you chose. Evolvability is what the first two buy you when the requirements change — which they will, which is where the rest of this course lives.