Law of Leaky Abstractions
Joel Spolsky's observation that every abstraction that hides real complexity eventually exposes the details it was supposed to hide, so you still need to understand what's underneath.
Also known as: Leaky Abstraction, Leaky Abstractions, Spolsky's Law of Leaky Abstractions
Category: Principles
Tags: software-design, software-development, software-architecture, abstraction, complexity, principles
Explanation
"All non-trivial abstractions, to some degree, are leaky." Joel Spolsky wrote that in 2002, on his blog Joel on Software, and it has been quoted in architecture discussions ever since.
An abstraction hides complexity behind a simpler interface. That's its whole purpose. A leak happens when the hidden details break through: the abstraction stops behaving the way its interface promises, and you have to understand the layer below to fix the problem.
**Spolsky's examples**:
- **TCP** promises reliable delivery over an unreliable network. If your pet snake chews through the network cable (his example), no amount of abstraction delivers your packets. Your app just waits
- **SQL** lets you describe what data you want, not how to get it. Then two equivalent queries run at wildly different speeds, and you need to understand indexes and query plans
- **Iterating over a 2D array** row by row or column by column gives the same result. One can be much slower, because of how memory and caches work
- **Network file systems** look like local disks, until latency or a dropped connection shows that they aren't
**More recent leaks**:
- **ORMs**: the N+1 query problem appears the moment you need to care about the SQL being generated
- **Garbage collection**: memory is "automatic" until a GC pause shows up in your latency charts
- **Cloud services**: "infinitely scalable" storage still has rate limits, regions and eventual consistency
- **LLM APIs**: a chat interface looks like a conversation, until the context window fills up and earlier messages fall out
**What it means in practice**:
1. **Abstractions save time while you work, not while you learn**: You can use a tool without knowing its internals. You can't debug it without knowing them
2. **Learn one layer down**: Know enough about the layer under your main tools to recognize a leak when it happens
3. **Expect leaks at the edges**: Performance, failures, concurrency and limits are where abstractions break first
4. **Design for honest abstractions**: When you build one, document where it leaks, and offer escape hatches for the cases it can't hide
**How it connects**:
Hyrum's Law describes the other direction: users start depending on details the abstraction never promised. Both point to the same lesson. An interface never fully hides what's behind it, so good design acknowledges the leaks instead of pretending they don't exist.
This is also why "it's just a wrapper" is rarely true. The wrapper simplifies the common case. The leaks remain for everything else.
Related Concepts
← Back to all concepts