The Cost of Abstraction
Abstraction is leverage. Real leverage, the kind that changes what’s possible. But it’s not magic.
Every abstraction leaks and hides complexity you’ll eventually need to understand. The power is real - you just have to know what you’re trading for it.
All abstractions leak
Joel Spolsky called it the Law of Leaky Abstractions:
“All non-trivial abstractions, to some degree, are leaky.”
His go-to example is TCP. TCP provides the abstraction of reliable delivery over unreliable IP. Packets can get lost, arrive out of order, get corrupted - TCP handles all of that. From your perspective as a programmer, you just send data and it arrives.
Except when there’s a hardware failure. Or when the network is congested and packets are getting dropped. TCP still works - it retries, reorders, recovers - but you feel it in latency. The abstraction is supposed to hide unreliability, but the unreliability leaks through as slowness.
This happens everywhere:
- Memory as a flat array - works great until you’re iterating a 2D array the wrong direction and hitting page faults on every access
- SQL as declarative queries - until you discover that logically equivalent queries can perform a thousand times differently
- Remote files as local files - until the network hiccups and your email forwarding script fails silently
The abstraction works until it doesn’t. And when it doesn’t, you need to understand what’s underneath.
Learning time vs working time
Here’s Spolsky’s key insight:
“Abstractions save us time working, but they don’t save us time learning.”
This cuts against the dream of just using the higher level and ignoring everything below. The code-generation tool that writes everything for you, the framework that handles everything, the ORM that means you never write SQL - they save you time working. You can get things done faster.
But when the abstraction leaks - and it will - you need to understand what it was abstracting. The only way to deal with leaks competently is to learn how the abstraction works and what it’s hiding.
You can’t skip the learning. But that’s fine - the learning is usually worth doing anyway.
The wrong abstraction
Sandi Metz’s warning is one of the sharpest:
“Duplication is far cheaper than the wrong abstraction.”
The pattern goes like this:
- Programmer A sees duplication, extracts it into an abstraction
- Time passes. A new requirement comes in that almost fits the abstraction
- Programmer B adds a parameter and a conditional to handle the new case
- Repeat. More requirements. More parameters. More conditionals.
- The abstraction becomes incomprehensible, but everyone’s afraid to touch it
- Sunk cost keeps it alive long after it should have died
The abstraction that once clarified now obscures. It’s worse than duplication because duplication at least says what it does. A bad abstraction pretends to simplify while hiding a mess.
Metz’s solution: “When the abstraction is wrong, the fastest way forward is back.” Inline the code. Delete what you don’t need. Let the duplication sit there until the right pattern emerges. You need to see when you’re at the wrong level - when the abstraction is hurting more than helping.
Essential complexity doesn’t compress
Fred Brooks made a distinction that still matters: essential complexity versus accidental complexity.
Accidental complexity is the stuff we made hard for ourselves. Bad tools, awkward languages, unnecessary ceremony. We can fix this. Better abstractions help.
Essential complexity is inherent to the problem itself. It’s the irreducible core of what you’re trying to do. And here’s the trap:
“Descriptions of a software entity that abstract away its complexity often abstract away its essence.”
You can’t abstract away essential complexity. Trying to do so doesn’t eliminate it - it just hides it somewhere you can’t see. The complexity is still there, but now you can’t reason about it.
ORMs are the classic example. Objects are graphs with references. Relations are tuples in tables. These models are mathematically different - that’s essential complexity. You can use an ORM and benefit from it, but you’ll still need to understand SQL when the abstraction doesn’t do what you expect.
The compound cost
Butler Lampson warned about what happens when abstractions stack:
“If there are six levels of abstraction, and each costs 50% more than is ‘reasonable,’ the performance will suffer dramatically.”
Every layer has overhead. Each abstraction you add is another layer of indirection, another set of assumptions, another thing that can leak. Individually, each might be worth it. But they compound.
And it’s not just runtime cost. It’s debugging cost - the mental overhead of tracing through layers when something goes wrong.
The right abstractions are still worth it. You just want to stack them deliberately, not accidentally.
None of this means abstraction is bad. The leverage is real. The question is whether you’re paying attention to the cost.
Use the abstraction. But learn what it’s hiding.