← Blogg

Fixing a Case of Leaky Abstractions

A few years ago I gave a talk about a problem that had been nagging me. We kept seeing the same pattern across our APIs. Consuming one of them felt more complex than the task it was meant to support, and partners wrapped our APIs in their own translation layers to protect themselves from our changes. Every team solved it locally, and we paid for it globally.

That pattern has a name. It is a leaky abstraction, and once you start looking, you see it everywhere.

A plumber under a sink, head in hand, with fittings laid out and an instruction manual open beside him
When an abstraction leaks, someone downstream ends up with the manual open.

What a leaky abstraction is

An abstraction is supposed to hide complexity. A leaky abstraction is one that fails to. The details it was meant to tuck away seep back out and land in the lap of whoever is consuming it. Joel Spolsky named this two decades ago in his Law of Leaky Abstractions:

All non-trivial abstractions, to some degree, are leaky. […] Abstractions save us time working, but they don’t save us time learning.

You cannot eliminate leaks. Every non-trivial abstraction leaks a little. The real question is who pays for it when it does.

The cost lands on the consumer

When an API leaks business logic, the cost does not disappear. It moves to every consumer. They re-implement validation of rules that belong to the producer, submit data that only makes sense inside the producer’s systems, and bend their workflows to match an internal process they cannot see. The more consumers you have, the more times the same cost is paid.

Picture QuickShop, an imaginary e-commerce API for third-party vendors. It started simple, then its internal order and inventory rules began to show through. Vendors ended up encoding QuickShop’s validation, sending data that meant nothing on their side, and following a workflow shaped by QuickShop’s internal process. None of that is the vendor’s problem to solve, yet the vendor is the one solving it.

Only the producer can fix it

A consumer can defend against a leak by building an anti-corruption layer, code whose only job is to translate the producer’s mess into something it can live with. It works, but it is the wrong place to fix the problem. The producer knows the business rules and owns the data model and the workflow. Fix the leak once at the producer and every consumer benefits. Patch it at each consumer and the same fix is built many times over, and the producer is now locked in, because any API change breaks all those hand-built layers.

There are gentler tools too: sensible defaults, shaping external data differently from internal, decent docs. HATEOAS would help most in theory, but the industry never adopted the extra machinery, so it is not much of a fix in practice. The one I keep coming back to, enough that colleagues joke I have joined the “SDK congregation”, is the SDK. An SDK is, in effect, the anti-corruption layer the producer builds once, on behalf of every consumer.

The case for SDKs, and what they cost

An SDK is a layer of indirection between your API and the code running at the consumer. The producer absorbs API changes inside it and keeps it backwards compatible, so migrating to a new version is little more than bumping a dependency. Android does the same at scale, where compatibility libraries let an app target a new platform while old behaviour keeps working underneath. Only genuinely new, incompatible functionality forces real work on the consumer, and that is rare. The alternative is what many live with today, regenerating clients from OpenAPI, Protobuf or Avro every time the API moves, which is itself a leak straight into every consumer’s build.

SDKs are not free. They move complexity into the producer’s organisation, where someone has to own, build and version them. They are a new dependency for consumers, who now rely on your cadence, quality and choice of languages. And a thin SDK over a leaky API does not fix the leak, it relocates it. Sometimes the right answer is no SDK at all, for a small stable API or a clean contract with good docs. The point is not that SDKs always win. It is that the producer should own the leak, and an SDK is one of the better ways to do it.

What AI changes

AI changes the maths but not the principle. Much of the SDK cost was always mechanical, generating and syncing clients across languages, and that is exactly what coding agents are now good at, so the old excuse for skipping SDKs is eroding. It cuts both ways, since the same tools make it cheaper for consumers to generate their own clients. But generated code is not understood code. Someone still has to read it, trust it and catch its mistakes. That is a knowledge tax, the same learning cost Spolsky pointed at, and it does not disappear because a model wrote the client. An agent orchestrating across your APIs still has to learn your business rules. AI lowers the cost of the fix far more than it lowers the cost of the leak.

So which would you pick?

Two API providers offer the same functionality across a large, sprawling API. One gives you an SDK, the other expects you to build and maintain a dozen clients yourself. For a small, stable API the raw contract might win, but for the large, evolving APIs most of us ship, I pick the API with an SDK every time. There is a reason every major premium API provider ships one.

None of this beats the Law of Leaky Abstractions. Every abstraction still leaks a little. What changes is who carries the weight. Left alone, it spreads across every consumer and hardens into lock-in. Owned by the producer, it becomes one problem solved in one place, at a real cost, but paid once by the party best placed to carry it.

Opprinnelig publisert på Medium 21. juni 2026.