One of the most dangerous moments in a developer’s career is when an abstraction works perfectly.
Not because success is bad.
But because perfect abstractions create an illusion.
The illusion is:
I don't need to know what's underneath.
Enter fullscreen mode Exit fullscreen mode
For a while, that’s true.
Then production happens.
Then scale happens.
Then edge cases happen.
Then reality happens.
And suddenly:
The abstraction leaks.
Enter fullscreen mode Exit fullscreen mode
This idea is so common in software engineering that it has a name:
The Law of Leaky Abstractions
And once you see it, you’ll notice it everywhere.
What Is An Abstraction?
An abstraction hides complexity.
Example:
fetch("/users")
Enter fullscreen mode Exit fullscreen mode
Looks simple.
Behind that line:
DNS Lookup
TCP Connection
TLS Handshake
HTTP Request
Network Routing
Server Processing
Serialization
Response Parsing
Enter fullscreen mode Exit fullscreen mode
Thousands of things happen.
The abstraction hides them.
That’s the point.
Why We Need Abstractions
Imagine writing:
openSocket()
performTLSHandshake()
buildHTTPRequest()
serializeHeaders()
sendRequest()
readResponse()
parseJSON()
Enter fullscreen mode Exit fullscreen mode
every time.
Nobody wants that.
Abstractions make software possible.
Without them:
Modern Software Would Not Exist
Enter fullscreen mode Exit fullscreen mode
The Problem
The abstraction hides complexity.
It does not remove complexity.
That distinction matters.
Because eventually:
fetch("/users")
Enter fullscreen mode Exit fullscreen mode
fails.
And suddenly:
You Need To Understand
The Things It Was Hiding
Enter fullscreen mode Exit fullscreen mode
Example #1: ORMs
Developers love ORMs.
Example:
const users =
await User.findAll()
Enter fullscreen mode Exit fullscreen mode
Looks beautiful.
Looks simple.
Looks harmless.
Then somebody adds:
user.posts
Enter fullscreen mode Exit fullscreen mode
inside a loop.
Suddenly:
100 Users
100 Queries
Database Meltdown
Enter fullscreen mode Exit fullscreen mode
The famous:
N + 1 Query Problem
Enter fullscreen mode Exit fullscreen mode
appears.
The ORM abstraction leaked.
Example #2: React
React hides DOM manipulation.
Instead of:
document.createElement(...)
Enter fullscreen mode Exit fullscreen mode
we write:
<UserCard />
Enter fullscreen mode Exit fullscreen mode
Wonderful.
Until:
5000 Components
Frequent Updates
Slow Rendering
Enter fullscreen mode Exit fullscreen mode
Now you need to understand:
Reconciliation
Memoization
Reference Equality
Rendering Lifecycle
Enter fullscreen mode Exit fullscreen mode
The abstraction leaked.
Example #3: Promise.all()
Looks simple.
await Promise.all(
requests
)
Enter fullscreen mode Exit fullscreen mode
Feels magical.
Until:
5000 Requests
Enter fullscreen mode Exit fullscreen mode
hit production.
Now:
Rate Limits
Memory Pressure
Connection Pools
Timeouts
Enter fullscreen mode Exit fullscreen mode
suddenly matter.
Again:
The abstraction leaked.
Example #4: Kubernetes
Developers often say:
Kubernetes Makes Deployment Easy
Enter fullscreen mode Exit fullscreen mode
Until something breaks.
Then:
Pods
Services
Ingress
DNS
Networking
Volumes
Secrets
Scheduling
Enter fullscreen mode Exit fullscreen mode
become your problem.
The abstraction leaked.
Example #5: Functional Programming
Even FP abstractions leak.
Consider:
users
.map(...)
.filter(...)
.map(...)
Enter fullscreen mode Exit fullscreen mode
Looks elegant.
Then:
1 Million Records
Enter fullscreen mode Exit fullscreen mode
arrive.
Now:
Allocations
Garbage Collection
Intermediate Arrays
Enter fullscreen mode Exit fullscreen mode
matter.
Suddenly:
You Need To Understand
The Implementation
Enter fullscreen mode Exit fullscreen mode
The abstraction leaked.
The Reduce Example
Earlier in this series we discussed:
users.reduce(
(acc, user) => ({
...acc,
[user.id]: user
}),
{}
)
Enter fullscreen mode Exit fullscreen mode
Looks elegant.
Looks immutable.
Looks functional.
At scale:
O(n²)
Enter fullscreen mode Exit fullscreen mode
The abstraction leaked.
The implementation became important.
Why Leaks Are Inevitable
Many developers think:
Good Abstractions
Never Leak
Enter fullscreen mode Exit fullscreen mode
This is impossible.
Because reality is more complex than any abstraction.
Always.
Eventually:
Performance
Memory
Concurrency
Networking
Storage
Scale
Enter fullscreen mode Exit fullscreen mode
find a way through.
The Database Example
You can use:
User.findAll()
Enter fullscreen mode Exit fullscreen mode
for years.
Then one day:
Database CPU 100%
Enter fullscreen mode Exit fullscreen mode
Now suddenly:
SELECT *
FROM users
Enter fullscreen mode Exit fullscreen mode
matters.
The SQL was always there.
The ORM simply hid it.
The Cloud Example
Many developers think:
Serverless Means
No Servers
Enter fullscreen mode Exit fullscreen mode
It doesn’t.
It means:
Someone Else's Servers
Enter fullscreen mode Exit fullscreen mode
Eventually:
Cold Starts
Execution Limits
Concurrency Limits
Enter fullscreen mode Exit fullscreen mode
appear.
The abstraction leaks.
Why Senior Engineers Feel Different
Junior engineers often trust abstractions.
Senior engineers respect abstractions.
Those are not the same thing.
A senior engineer sees:
fetch(...)
Enter fullscreen mode Exit fullscreen mode
and mentally understands:
Network
Latency
Retries
Timeouts
Failures
Enter fullscreen mode Exit fullscreen mode
even when they aren’t visible.
That’s experience.
The Best Developers Learn Both Layers
Bad approach:
Only Learn Frameworks
Enter fullscreen mode Exit fullscreen mode
Also bad:
Only Learn Internals
Enter fullscreen mode Exit fullscreen mode
The best developers learn:
Abstraction
+
Implementation
Enter fullscreen mode Exit fullscreen mode
Both matter.
Real World Example: API Studio
Suppose we’re building an API Studio.
We expose:
Send Request
Enter fullscreen mode Exit fullscreen mode
as a button.
Simple.
Behind the scenes:
DNS
TLS
Headers
Body Serialization
Compression
Retries
Timeouts
Certificates
Enter fullscreen mode Exit fullscreen mode
Users shouldn’t see those details.
But we must understand them.
Because eventually:
A Bug Will Live There
Enter fullscreen mode Exit fullscreen mode
Real World Example: Git
Git feels simple.
git commit
Enter fullscreen mode Exit fullscreen mode
Until:
Merge Conflicts
Detached HEAD
Rebase Failures
Corrupted Refs
Enter fullscreen mode Exit fullscreen mode
appear.
Then:
Objects
Trees
Blobs
Refs
Packfiles
Enter fullscreen mode Exit fullscreen mode
suddenly matter.
The abstraction leaked.
The Hidden Connection To This Entire Series
Reduce leaked.
We learned Transducers.
Transducers leaked.
We learned composition.
RxJS leaked.
We learned streams.
Event Sourcing leaked.
We learned reducers.
Every article in this series is actually a story about abstractions leaking.
And that’s not a bad thing.
That’s how deeper understanding develops.
Pros Of Abstractions
1. Faster Development
Less code.
2. Better Productivity
Focus on business logic.
3. Lower Cognitive Load
Hide complexity.
4. Better Reusability
Shared solutions.
5. Better Collaboration
Common interfaces.
Cons Of Abstractions
1. Performance Surprises
The implementation is hidden.
2. Debugging Complexity
Problems occur below the abstraction.
3. Knowledge Gaps
Developers stop learning fundamentals.
4. Vendor Lock-In
Sometimes abstractions become cages.
5. Leaks
Eventually reality breaks through.
Always.
The Real Lesson
The biggest mistake developers make is assuming abstractions remove complexity.
They don’t.
They move complexity.
That’s a huge difference.
The complexity still exists.
It’s simply hidden until something goes wrong.
And when that moment arrives, the engineers who understand both layers:
The Abstraction
and
The Implementation
Enter fullscreen mode Exit fullscreen mode
are the ones who solve the problem.
That’s why great engineers never stop at the API.
Eventually they look underneath.
Because every abstraction leaks.
And that’s where the real learning begins.
What’s Next?
In the next article we’ll discuss:
The Two Hard Things In Computer Science
Because one famous joke contains an uncomfortable amount of truth:
There are only two hard things
in Computer Science:
Cache Invalidation
Naming Things
and Off-by-One Errors
Enter fullscreen mode Exit fullscreen mode
And surprisingly, that joke explains a huge amount of software engineering.
About The Author
Hi, I’m Amrish Khan.
I enjoy building developer tools, exploring software architecture, and writing about the deeper ideas behind everyday programming concepts.
I’m also building Aruvix — a growing ecosystem of local-first developer tools designed to process data directly in the browser without unnecessary uploads.
Here’s a detailed blog on Aruvix:
https://dev.to/amrishkhan05/aruvix-the-ultimate-offline-first-developer-toolkit-e0i
You can follow my work and thoughts here:
Portfolio:
https://www.amrishkhan.dev
LinkedIn:
https://www.linkedin.com/in/amrishkhan
GitHub:
https://www.github.com/amrishkhan05
If you enjoyed this article, consider following for more deep dives into JavaScript, architecture, local-first software, and performance engineering.
답글 남기기