Every abstraction leaks eventually. The useful question is not whether it leaks, but how much it costs you on the day it does.
We grade abstraction boundaries by what escapes them under pressure: error detail, performance characteristics, ordering guarantees. A good boundary leaks predictably and documents the leak.
A small taxonomy#
- Transparent — you can see through it on purpose (a thin wrapper).
- Opaque — it hides a decision you might need to revisit (a cache).
- Pretend — it hides a decision it cannot actually keep (a sync API over an async world).
The dangerous one is the third. It works in the demo and betrays you under load, because the thing it promised was never true.
Name the leak before it names you.
A code review comment we keep quoting
When we cannot avoid a leak, we surface it in the type signature — a Result, a deadline, a backpressure signal — so the caller is forced to acknowledge reality.