The clever state machine that nobody wanted to touch
A React feature started as a small flow with a couple of toggles and some conditional UI. It looked like a perfect excuse to be clever.
I reached for useReducer plus context, drew a neat little state diagram, and wired it up as a tiny state machine. It was elegant, strongly typed, and architecturally pure.
Then Emile needed to add a simple print preview flag.
To toggle a single boolean, he had to understand the reducer, the action types, the context provider, and the state transitions. None of it was impossible, but the cognitive load was ridiculous compared to the change he needed to make. He was effectively reverse-engineering a system just to flip one bit.
That was the moment the “beautiful” solution failed. Not technically. Socially.
Replacing the clever thing with three useState calls
I ripped out the reducer and replaced it with three independent useState hooks:
const [isEditing, setIsEditing] = useState(false);
const [isSaving, setIsSaving] = useState(false);
const [showPreview, setShowPreview] = useState(false);
No context. No state diagram. No indirection.
The logic that used to live in a reducer became a handful of if statements and event handlers. There were a couple of duplicated checks that would make a purist twitch. But the behavior was obvious from reading the component. You did not have to scroll to another file to understand what changing a flag would do.
Three months later, the client asked for a fourth toggle. Emile added it in ten minutes, without asking how the system worked, and without needing a doc. He followed the existing pattern, added another useState, and moved on.
The boring version scaled across teammates. The clever version scaled across my ego.
Elegance that only one person understands is a bug
On paper, the reducer pattern was more “correct.” It separated concerns, centralized transitions, and gave us a tidy mental model. In practice, it concentrated knowledge in one person’s head.
I wrote about this earlier in Why I Still Hand‑Code Every Hover State.
That is the real trade-off with clever frontend architecture. You are not just optimizing for CPU cycles or bundle size. You are optimizing for how many people can safely change this file after the original author has forgotten how it works.
In this case, the price of elegance was:
- Extra concepts to load before making a change
- Extra places to look when debugging a bug
- A much higher chance that only the original author felt confident editing it
The three useState hooks were boring enough that nobody needed a mental model. You could scan the component and see the whole story.
Fonts that do not need a PhD
The same pattern showed up again with fonts.
On one project, I considered going all-in on a complex next/font/local setup: unicode-range splitting, axis optimization for variable fonts, and a system that only loaded exactly what each page needed.
It would have been fun. It also would have been something only I understood.
Instead, I loaded two static weights of NouvelR and called it done. No unicode ranges. No clever axis tricks. Just a couple of @font-face declarations that any frontend dev can read.
The difference in first contentful paint was 12 milliseconds. The difference in maintainability was the gap between “Richard knows how this works” and “anyone can see what is going on.” On a two-year project, the second option pays rent every month.
Flat navigation that refuses to break
The Blackhole Networks navigation had the same temptation.
The “right” React pattern would be a recursive <NavItem> component that renders children from a JSON tree. It is satisfying to write: one component, arbitrarily deep nesting, and a clean data structure.
The actual site has a navigation that is three levels deep, maximum, and effectively never changes. So I wrote it as static JSX.
More on this in my article Why I Rebuilt My Portfolio Navigation From Scratch (Twice).
Yes, it violates DRY. Yes, there is some repetition. But it has one important property: it is impossible to break with a malformed CMS payload, because there is no CMS payload. It compiles to exactly what you see in the file.
The clever recursive version would have been a bug farm for a structure that is functionally constant. The flat version is boring and stable. When someone opens the file, they see the navigation as it will render, not a data structure they have to mentally execute.
Spacing that admits it is a judgment call
Every design system article will tell you to abstract spacing. Use a <Spacer size="lg" /> component. Or a carefully curated set of gap utilities. Or a spacing scale that maps tokens to pixels and rems and “rhythm.”
I tried it on FibrXL layouts. It did not survive contact with reality.
The spacing rules turned out to be context-dependent. Sometimes a gap was 24px, sometimes 32px, sometimes a fluid value that did not fit the neat token scale. The abstraction kept lying about how consistent the spacing was, and people trusted it because it looked official.
So I went back to plain margins. className="mt-6". className="mt-8". A boring, explicit decision in the place where the layout actually happens.
A spacing component says “the system knows what this should be.” A literal mt-6 says “a human looked at this particular layout and decided.” For layouts that bend the rules all the time, the second story is closer to the truth.
How boring code survives upgrades
The most invisible benefit of boring code shows up on upgrades.
When I upgraded the Gate Seal site to Tailwind v4, a custom plugin I had written for gradient borders broke. It relied on implementation details that changed.
Read also Ethics Of AI In Frontend: Who Owns Your UI Components?.
The boring version of the same effect, written with core utility classes, kept working. It had nothing special to break.
This is the hidden cost of cleverness: you are coupling yourself to the exact behavior of tools that are still moving. Anything that reaches into their internals or pushes them in directions they were not designed for is a future maintenance task disguised as a neat trick.
Boring code tends to sit closer to the primitives. It uses the parts that are least likely to change. When the ecosystem shifts, it moves along with minimal friction.
When to choose boring on purpose
None of this means “never use a reducer” or “never write a recursive component.” Sometimes the abstraction is genuinely doing work you cannot realistically do by hand.
But there is a pattern: when the clever solution mainly benefits the author, it is a good time to replace it with something boring. Boring code is not exciting to write, but it quietly does the one thing that matters on a long-lived frontend: it keeps working when someone else has to change it.
Subscribe to my newsletter to get the latest updates and news
Member discussion