Over-Engineered and Unusable: When Abstractions Hurt More Than They?Help
Generated by DALL.E in ChatGPT

Over-Engineered and Unusable: When Abstractions Hurt More Than They?Help


I’ve worked on plenty of projects by now, and if there’s one thing that really grinds my gears, it’s unnecessary abstractions. If I had a penny for every time I encountered the same over-engineered mess, I wouldn’t be a millionaire ???—?but I’d have a decent handful. And that’s still too much.

When we talk about over-abstraction, most people think of convoluted backend logic?—?overuse of design patterns, unnecessary layers, or distributed systems without traceability that make debugging a nightmare. But what often goes unnoticed is how abstraction in UI components can hurt just as much, if not more. A UI that’s too rigid, too detached from real user needs, or too “engineered” can turn a simple task into a frustrating ordeal.

When a Dropdown Refuses to?Update

In one project, we used a dropdown component from a library, but it didn’t quite match our design. The fix? A simple CSS tweak should have done the job. But no?—?someone decided to go the extra mile and wrap the entire component in a custom abstraction.

At first, this didn’t seem like a big deal. We only needed to read user selections, and everything worked fine. But as new features rolled in, we needed to update the dropdown value dynamically?—?and that’s when things fell apart. No matter what we did, the selected value refused to change. The abstraction was so tightly controlled that external updates weren’t properly reflected.

And it didn’t stop there. Not only did the dropdown refuse to update programmatically, but the abstraction also completely broke keyboard navigation. Arrow keys? Useless. Tab key? It skipped right past the dropdown like the options didn’t even exist. Accessibility? Forget about it. The dropdown was essentially a decorative element that looked interactive but refused to behave like one.

It wasn’t like we were trying to make the dropdown perform complex logic or run simulations?—?it just needed to behave like any normal dropdown should. But instead of a simple CSS override, we now had a rigid, over-engineered component that required workarounds for basic functionality.

When UI Follows First Normal Form?—?And That’s Not a Good?Thing

In another project, the UI was technically functional?—?but using it felt like navigating an enterprise-grade database tool rather than a user-friendly application. Every action required clicking through multiple buttons, opening modals, confirming pop-ups, and jumping between different sections. It was as if the UI had been “normalized” just like a database schema?—?each entity separated into its own isolated module with no real consideration for user flow.

To perform a single task, you had to move across five different screens, interacting with multiple dropdowns, switches, and input fields scattered across different sections. Need to update a setting? That’s three different modals. Want to apply changes? Click a button in one section, then confirm in another, then save in yet another. By the time you were done, you almost needed to write a transaction log just to keep track of what happened ??.

It was a classic case of backend-first design?—?data organization took priority over usability. The UI made perfect sense to the developers but was a nightmare for users, turning simple tasks into an overcomplicated maze of interactions.

Abstraction is meant to simplify, not complicate. Whether it’s code or UI, if users need a manual?—?or worse, a database schema?—?to navigate your app, something has gone horribly wrong.

When Abstraction Misses the?Point

On the backend side, I once came across a codebase where someone had clearly tried to apply abstraction?—?but instead of making things reusable, it just made everything more repetitive. There were methods like readXFromCsv(), readYFromCsv(), readZFromCsv()—each doing almost the same thing, just for different types of data.

At first glance, it looked like an abstraction. But in reality, it was just copy-pasting with slightly different method names. A proper abstraction would have been a single readFromCsv<T>() generic method that handled different cases dynamically. Instead, the code had three separate implementations that all needed to be maintained, tested, and updated individually.

This kind of “half-baked abstraction” is common. Developers start with the right intention?—?organizing code to be cleaner?—?but without a clear vision for reusability, the result is just unnecessary duplication with an illusion of structure.

Good abstractions are built with a clear, valid future in mind?—?not just for the sake of abstraction itself. Don’t abstract just because guidelines say so; abstract because it truly makes sense. The reality is, most over-engineered systems aren’t the result of bad intentions but of people hesitating to challenge existing structures. But if we know a change will make life easier, shouldn’t we have the courage to make?it?

Stay Curious. Adios ??

This article was originally written on Medium.

要查看或添加评论,请登录

Hiruthic .S.S的更多文章

社区洞察

其他会员也浏览了