--- slug: abstraction type: pattern summary: "The tool that lets you ignore what doesn't matter right now so you can focus on what does, by hiding detail behind a simpler surface." created: 2026-04-04 updated: 2026-04-18 related: boundary: relation: related note: "Every abstraction implies a boundary." component: relation: enables note: "Abstraction is what makes modular design possible." composition: relation: enables note: "Composable parts rely on stable abstractions at their interfaces." consumer: relation: shields note: "A consumer interacts with an abstraction rather than an implementation." coupling: relation: reduces note: "Abstracting away details reduces implementation coupling." dependency: relation: hides-from note: "Abstraction lets you depend on a stable interface instead of volatile internals." interface: relation: uses note: "An interface is the visible face of an abstraction." module: relation: enables note: "Abstraction is what makes modular design possible." naming: relation: contrasts-with note: "Naming makes things concrete and specific; abstraction hides specifics behind a generalized interface." platform-as-a-product: relation: used-by note: "The platform hides infrastructure complexity behind a simpler interface, the same way any good abstraction hides implementation details." separation-of-concerns: relation: enables note: "You separate concerns by abstracting them behind boundaries." shape: relation: depends-on note: "Recognizing the shape of a system helps you choose the right abstractions." copy-paste-programming: relation: corrects note: "Abstraction removes duplicated behavior when the copies truly mean the same thing." --- # Abstraction > **Pattern** > > A named solution to a recurring problem. > "All non-trivial abstractions, to some degree, are leaky." > — Joel Spolsky ## Understand This First - [Shape](shape.md) -- recognizing the shape of a system helps you choose the right abstractions. ## Context Software systems are too complex to hold in your head all at once. **Abstraction** is the tool that lets you ignore what doesn't matter right now so you can focus on what does. It operates at the **architectural** scale, though every level of software construction depends on it. When you call a function without reading its source, use a library without studying its internals, or prompt an AI agent without knowing how it tokenizes your words, you're relying on abstraction. ## Problem How do you manage complexity that exceeds what a single person (or a single agent context window) can hold at once? ## Forces - Real systems contain more detail than anyone can reason about simultaneously. - Hiding detail makes things simpler, but hiding the *wrong* detail causes surprises. - Too many layers of abstraction make it hard to understand what is actually happening. - Too few layers force you to think about everything at once. ## Solution Create boundaries that separate *what* something does from *how* it does it. An [interface](interface.md) is the visible face of an abstraction: it tells you what you can do. The implementation behind it is the hidden body: it handles how. A good abstraction has a stable, understandable interface that you rarely need to look behind. The art is in choosing what to hide. A database abstraction that hides the query language is useful; one that hides whether your data is persisted is dangerous. The right level of abstraction depends on who the [consumer](consumer.md) is and what decisions they need to make. In agentic coding, abstraction determines how much an AI agent needs to know to do useful work. If your codebase has clean abstractions, you can point an agent at a single [module](module.md) and say "implement this interface." Without them, the agent needs to understand the whole system, which may exceed its effective context. ## How It Plays Out A team builds a payment processing system. They create a `PaymentGateway` interface with methods like `charge` and `refund`. Behind it, one implementation talks to Stripe, another to PayPal. The rest of the codebase only sees the interface. When a new payment provider comes along, they add a new implementation without changing anything else. An AI agent is asked to write tests for a service that sends emails. The service depends on an `EmailSender` interface. Because the interface abstracts away the actual sending, the agent can write tests using a simple mock. It doesn't need to understand SMTP, API keys, or retry logic. The abstraction makes the agent's job tractable. > **⚠️ Warning** > > Leaky abstractions are inevitable. When performance degrades or unexpected errors surface, someone will need to look behind the curtain. Design your abstractions so that peeking behind them is possible, not forbidden. > **💡 Example Prompt** > > "Create a PaymentGateway interface with charge and refund methods. Write a Stripe implementation behind it. The rest of the codebase should depend only on the interface, never on Stripe directly." ## Consequences Good abstractions multiply productivity. They let teams work in parallel on different parts of a system, let agents operate on bounded slices of a codebase, and make code reusable across contexts. But every abstraction is a bet that certain details won't matter to the consumer. When that bet is wrong and the abstraction leaks, the resulting confusion can be worse than having no abstraction at all. You now have to understand both the abstraction *and* the reality it was hiding. The cost of a bad abstraction isn't just complexity; it's *misleading* complexity. ## Sources - David Parnas introduced information hiding as the principle behind effective modularization in "[On the Criteria To Be Used in Decomposing Systems into Modules](https://dl.acm.org/doi/10.1145/361598.361623)" (*Communications of the ACM*, 1972). His argument that modules should hide design decisions, not simply divide work into steps, is the intellectual foundation of abstraction in software. - Edsger Dijkstra demonstrated hierarchical layers of abstraction in practice with the THE multiprogramming system, described in "[The Structure of the 'THE'-Multiprogramming System](https://dl.acm.org/doi/10.1145/363095.363143)" (*Communications of the ACM*, 1968). Each layer depended only on the layers below it, establishing the pattern of reasoning about complex systems one level at a time. - Harold Abelson and Gerald Jay Sussman formalized the concept of abstraction barriers in *[Structure and Interpretation of Computer Programs](https://mitpress.mit.edu/9780262510875/structure-and-interpretation-of-computer-programs/)* (1984), teaching generations of programmers to build systems as towers of cleanly separated layers. - Joel Spolsky coined the Law of Leaky Abstractions in a [2002 essay on *Joel on Software*](https://www.joelonsoftware.com/2002/11/11/the-law-of-leaky-abstractions/), observing that all non-trivial abstractions leak some detail from the layer beneath. The article's epigraph quotes this law directly. --- - [Next: Component](component.md) - [Previous: Shape](shape.md)