In the world of software development, abstraction is one of the most powerful tools at our disposal. Yet, it is often taken for granted—seen merely as a technical concept or a convenience. In truth, abstraction is much more than that; I agree it’s a confusing topic for some, but it represents a currency of trust and a gateway to creative problem-solving.
Abstraction as Trust
At its core, every abstraction is built on trust. When we build or use a library, framework, API, or even a programming language, we trust the people or systems who designed it. We trust that these abstractors have already handled the intricate details—the “hows”—so that we don’t have to.
Just as currency enables transactions by guaranteeing value, abstraction enables development by guaranteeing that, if we use it correctly, it will do its part. Each layer of abstraction makes an implicit promise:
“I will handle this piece of complexity for you. You can rely on me.”
This trust extends even to our own past work. If you designed a library years ago with effective separation of concerns, you don’t need to recall its minute details to use it today. This promise allows developers to stand on the shoulders of those who came before, building ever more complex and capable systems without getting lost in the weeds of low-level implementation.
Abstraction Frees the Mind
The true beauty of abstraction lies in its ability to liberate the developer’s mind. Instead of worrying about how a particular task is implemented under the hood—how data is stored, how a network packet is transmitted, how a sorting algorithm works—we can focus on higher-level concerns:
- What problem am I solving?
- What is the best design for this situation?
- How can I create value for the user?
This mental freedom accelerates development time. By outsourcing the details to well-designed abstractions, we create space and set priority for creativity, strategy, and architectural thinking.
Examples All Around Us
Abstraction is everywhere in software:
- Operating systems abstract hardware complexities so we don’t write programs in assembly language for each device.
- The Retrofit HTTP client for Android takes away overhead complexities like opening and closing socket connections, formatting headers, handling encryption, and parsing responses.
- Database Object-Relational Mappers (ORMs) abstract SQL so we can think in terms of objects or models.
And abstraction exists beyond software:
- We trust that flipping a light switch will illuminate a room without understanding the engineering behind electrical circuits, springs, or materials.
- We drive cars without needing to know how combustion engines or electric motors work.
- We post letters following established protocols, and the rest is handled by the postal system; we need not worry about how it’s moved from one place to another, where it stops, or other intricacies.
The Developer’s Responsibility
Of course, with trust comes responsibility. Every time we use an abstraction, we are relying on someone else’s work to solve part of our problem—and that trust should not be blind. As developers, we must approach abstractions thoughtfully and skillfully.
Here’s what that means in practice:
- Choose abstractions wisely.
- Understand their limitations and guarantees.
- Respect the contract they offer and use them as intended.
- Know when to peek beneath the abstraction.
Sometimes, it is necessary to peek beneath an abstraction’s surface, especially when debugging or optimizing. But most of the time, abstraction serves as the foundation that allows us to build faster, smarter, and better.
Not all interfaces are abstractions — differentiating abstractions
When I first learned about abstraction, I assumed that every interface represented an abstraction. But over time, I realized that’s not always the case.
- An interface is simply a contract—a way to define what methods or properties should exist.
- Abstraction, on the other hand, goes beyond that. It hides internal complexity and provides a simpler way to achieve a goal.
For something to qualify as a meaningful abstraction, it must do more than just define methods. It must:
- Fulfill a purpose in the easiest way possible
- Hide unnecessary complexity
- Offer a clean and reliable interface that lets developers focus on what they want to achieve, not how it’s implemented
Take libraries like Retrofit or Ktor as examples. These libraries have been thoughtfully designed to abstract away the complexities of network communication—things like:
- Opening and managing connections
- Formatting HTTP requests and parsing responses
- Handling retries, timeouts, redirects, and errors
- Managing threading and background execution
As app developers, we don’t need to worry about these internal details. We simply declare what API we want to talk to, and the library takes care of the rest.
@GET("users")
suspend fun getUsers(): List<User>
That’s abstraction at work: you focus on what you need (the list of users) and trust that the library handles the how (HTTP calls, JSON parsing, etc.).
Not all interfaces are abstractions, but every good abstraction provides an interface—one that lets you work at a higher level of thinking, free from unnecessary details.
Conclusion
Abstraction is more than a coding technique—it is a profound enabler of progress. By trusting in the work of others and leveraging the abstractions they create, we free ourselves to focus on what truly matters: solving problems, creating value, and pushing the boundaries of what software can do.