Lumicrafte logoLumicrafte
← WRITING
ENGINEERING NOTESARCHITECTURESOFTWARE DESIGN

Maybe we have too many abstractions

Software gets easier to change when the right boundaries exist. The problem is that we are very good at creating boundaries that nobody needed.

Lumicrafte
15 MAR 2026 · 2 MIN READ

Abstraction is usually presented as a solution.

Something is repeated, so we extract it.

Something is complicated, so we hide it.

Something might change, so we put a boundary around it.

All reasonable ideas.

But there is another side to abstraction that gets less attention.

Every abstraction creates something new that a future developer has to understand.

A simple function becomes a service.

The service gets an interface.

The interface gets an adapter.

The adapter gets a factory.

Eventually changing one thing means finding the right place among six layers that all exist for a reason that made sense at some point.

The abstraction was not wrong

This is what makes the problem difficult.

Most bad abstractions were not obviously bad when they were created.

They solved a real problem.

Maybe there were two implementations.

Maybe the team expected a third one.

Maybe the architecture was copied from a much larger system.

The problem appeared later.

The reason for the abstraction disappeared, but the abstraction stayed.

Code has a carrying cost

I think about abstractions a little differently now.

Instead of asking:

"Can we abstract this?"

I prefer:

"What problem will this abstraction make easier?"

If the answer is unclear, keeping the code simple is often the better choice.

Not because duplication is good.

Not because architecture is bad.

Just because every layer has a cost.

You pay that cost whenever you read the code, debug it, change it, or explain it to someone else.

The hardest code to remove

The most dangerous abstractions are often the ones that look architectural.

They give the codebase a feeling of structure.

There is a clean separation between things.

Everything has an interface.

Everything is replaceable.

But sometimes nothing actually needs to be replaceable.

A database repository that only wraps one database call does not automatically make the application more flexible.

A service with one implementation does not automatically make the architecture better.

A generic framework for three lines of repeated code may simply turn three easy lines into a small system.

The abstraction is real.

The benefit is not.

A boundary is useful when it gives us something. A boundary that only exists because boundaries are considered good architecture is just another thing to maintain.

Good architecture is not the amount of structure in the code.

It is how much unnecessary structure we managed not to build.

ARCHITECTURESOFTWARE DESIGN
WRITTEN BY
Lumicrafte

We build software products and custom software, and write about the decisions behind them. Notes on engineering, interface craft, and what shipping teaches us.

New writing, occasionally.

One email when we publish something worth reading. No schedule, no marketing, unsubscribe in a click.

Related reading

ALL WRITING →
ENGINEERING NOTES3 MIN

The database is often your real API

We spend a lot of time designing HTTP APIs while quietly letting the database become the place where the real rules live.

ENGINEERING NOTES9 MIN

Maybe programming languages should stop optimizing for typing

AI has made writing code cheap. That changes what we should ask from programming languages: less focus on reducing keystrokes, more focus on making intent explicit and machine-checkable.

ENGINEERING NOTES2 MIN

The cost of a hundred milliseconds

Perceived speed is a design decision before it is an engineering one. Notes on where latency actually comes from in the interfaces we build.