Sep 10 2025 · 5 min read

Developers who understand UX

The shift I keep noticing

Something I've seen across most of the teams I've worked in: the frontend is quietly moving back toward people who can hold the user, the design, and the implementation in their head at the same time. Not a specialist in any one of those, but a generalist with taste. Someone who can read a Figma file, understand why a particular interaction matters, and then write the code that actually makes it feel that way.

This isn't a new role. It's an old one we rediscovered after about a decade of pretending the implementation didn't matter much as long as the feature shipped. Now everyone can ship. The tooling is good enough that getting something onto the screen is almost free, so the thing that separates one engineer from another stopped being whether they can build it. It's the how.

Craft lives in the code, not on top of it

The most common misconception I run into is that craft is a layer you add at the end, once the feature works. In my experience it's the other way round. The craft is in the hundreds of small decisions you make while you're still typing, most of which never reach a designer or a ticket.

Should the dropdown close when you click outside it, or only when you press Escape? If the API is slow, does the button stay pressed, show a spinner, or quietly disable itself? Does the form remember what you'd typed if you fat-finger the back button? None of these are really design decisions. There's no Figma frame for "what happens on the third second of loading." But they look like design decisions to the person using the thing, and the person making the call is whoever's writing the code, every single time, whether they notice they're making it or not.

That's the part you can't hand off. The designer doesn't write the click handler. The backend engineer doesn't pick the easing curve. By the time it reaches the code it's one person's call — and the quality of that call stays invisible until someone hits the unhappy path.

The silent default

Most of the bad UX I find in otherwise-good apps isn't a decision anyone made on purpose. It's the slow accumulation of defaults nobody stopped to question. onSubmit with no loading state. A fetch with no error path. A setTimeout standing in for actually thinking about the lifecycle.

A developer who understands UX still reaches for the default. They're not reinventing the button. But they pause before they keep it, ask whether the default is genuinely what the user needs here, and then either keep it or replace it. I've come round to thinking the pause is most of the job.

The handoff is where it breaks

Most teams run on a handoff. The designer makes a Figma, the engineer implements the Figma, and anything that wasn't in the Figma becomes a "bug" that nobody quite owns. That works fine for static screens. It falls apart the moment something needs to move.

The transition from the list to the detail view. The empty state when the API comes back with nothing. What the loading skeleton looks like on the third second versus the first. The keyboard shortcut nobody specced because nobody thought to. You can prototype motion in Figma now, which is genuinely useful, but you still can't ship it from there. The animation that ends up in front of the user is the one written in CSS or Motion, with whatever durations the engineer happened to land on, and if the designer wasn't sitting next to them when it got written, those durations are a guess. That's how a codebase fills up with transition: all 0.3s ease on a button that wanted 120ms: guesses dressed up as decisions.

The fix isn't a better handoff. It's not having one. When the person who understands the design is the same person writing the code, the loop collapses — the conversation that used to happen on a staging URL three days later happens in the file, while it's still being built.

Spotting one

You can't really advertise for this. "Design engineer" is too new and too contested a label to drop on a job board and trust the right people will self-select. What you can do is read the work.

Open someone's portfolio and actually use it. Hover the buttons. Resize the window to something stupid. Click into a deep link and refresh it. The tells are everywhere: the empty states they bothered to design, the focus rings they kept instead of stripping out, the way a press settles instead of snapping. None of those are features. They're evidence that the person writing the code stopped to think about the person on the other side of it.

The inverse is worth knowing too. A portfolio of beautiful Figma exports and nothing you can click. A GitHub of forks with no commits of their own. A case study that proudly ends at the wireframe. None of that makes someone a bad engineer, but it usually means they haven't yet had to live with the consequences of their own decisions, which is the part that builds the instinct.

How you actually become one

If you're a developer who wants to move in this direction, I don't think there's a course for it. The path that worked for me was almost boringly simple: build something real, then live with it long enough that its flaws become your problem.

Ship a side project, a tool, a writing site like this one. Then use it yourself, every day, for six months, and pay attention to whatever quietly annoys you. The fourth time the form forgets what you typed. The tenth time the search feels a beat too slow. Each of those is a small debt you're paying to your past self for not thinking it through the first time. So you fix one, then the next. Somewhere in that loop you stop catching the problems after they ship and start catching them while you type, and that shift is the one that actually matters.

Why it's worth being slow

From the outside, all of this can look like being slow. You'll spend an afternoon on a button another engineer would have shipped in ten minutes, and rewrite the same transition three times because the second attempt was close but not quite right. I've mostly made my peace with that, because the compounding is real even when you can't see it. A codebase that's been cared for this way has a different shape from one assembled out of defaults, and people feel that difference long before they can name it. The users feel it first. The next engineer feels it the moment they open the file.