Skip to content
Latticework
Esc
Try
No. 018Systems & Structure

Law of Leaky Abstractions

All non-trivial abstractions leak; eventually you have to understand what is beneath them.

“All non-trivial abstractions, to some degree, are leaky.”

Sooner or later the layer an abstraction hides shows through, and you need to understand it.

To an executive

Managed services and platforms save effort but do not remove the need for expertise. Under stress their hidden workings surface, so keep some in-house understanding.

To an engineer

Learn what lies beneath each abstraction you adopt, such as query plans beneath SQL or network behaviour beneath TCP. Expect it to show through under load and failure.

The idea

In a 2002 essay, Joel Spolsky stated that all non-trivial abstractions are, to some degree, leaky. His main example was TCP: it promises reliable delivery over an unreliable network, but it cannot hide a cut cable, and a congested network shows through as slowness. SQL is another: logically equivalent queries can differ in speed by orders of magnitude, so you end up reading query plans.

His conclusion was that abstractions save us time working, but not time learning. Every platform, managed service and framework an architect adopts is an abstraction, and it will leak under stress, usually at the worst moment.

Why it works

Abstractions hide detail, not physics. Latency, memory, limits and failure still exist beneath the interface. The abstraction only decides when you notice them.

Leaks appear at the edges. Normal use rarely shows the layer beneath. Peak load, failures and unusual inputs do.

Debugging needs the lower layer. When something breaks through the abstraction, the fix is usually in the layer it was meant to hide.

Where it applies

  • Vendor and platform selection, where you choose which leaks you are willing to live with.
  • Managed and serverless services, which hide servers until cold starts, quotas or throttling appear.
  • Object-relational mappers and query builders, which hide SQL until a query is slow.
  • Remote calls dressed up as local ones, which hide the network until it fails.

How to apply

  1. List the known leaks. For each key abstraction, write down its limits, quotas and failure modes before you depend on it.
  2. Keep the knowledge in the team. Make sure someone understands the layer beneath every critical abstraction.
  3. Design an escape hatch. Allow raw SQL, direct API access or a configuration override for the cases the abstraction does not fit.
  4. Test at the edges. Load-test and fault-test where the abstraction is most likely to leak.

Example scenario

A team built a launch campaign on a serverless platform that promised not to need any thought about servers. During the launch, cold starts pushed latency past the service level objective and an account-wide concurrency limit throttled requests across unrelated functions. Nobody on the team knew how the runtime managed instances.

They brought in someone who knew the runtime, reserved concurrency for the critical functions, kept a small pool of instances warm, and added the platform's limits to their design checklist. The abstraction stayed; the team just stopped pretending it had no floor beneath it.

Questions to ask

  • Where will this abstraction leak under load, failure or unusual input?
  • Who on the team understands the layer beneath it well enough to debug it?
  • What is the escape hatch when the abstraction does not fit our case?

When not to use it

  • Stable, well-understood abstractions where the leaks are documented and rarely matter at your scale.
  • As a reason to delay every decision until the whole stack is understood; some leaks are best learned in production with good monitoring.

How it misleads you

Refusing to use abstractions at all. Leaks are a cost to plan for, not a reason to hand-build everything. Hand-built replacements leak too, and you also have to maintain them. Choose abstractions whose leaks your team can handle.

Further reading

Last reviewed · Suggest an improvement