DEV Community

Tyson Cung
Tyson Cung

Posted on

Why the Best Engineers Write "Ugly" Code

The most productive engineer I ever worked with wrote code that would make Clean Code purists physically ill. No abstractions where one would "obviously" go. Functions that were 80 lines long. Variable names that were borderline aggressive in their specificity. And her code shipped faster, broke less, and was easier to debug than anyone else's on the team.

The Clean Code Trap

Somewhere along the way, the industry confused "clean" with "good." We taught junior developers that short functions are better, abstractions are always worth it, and DRY (Don't Repeat Yourself) is a commandment, not a guideline.

The result? Codebases where understanding a single feature requires bouncing through 15 files. Where a simple data transformation passes through three layers of abstraction that each do almost nothing. Where the code is technically "clean" by every metric but impossible to follow when something breaks at 3 AM.

I've inherited codebases like this. The original author followed every rule in the book. The code was "beautiful." And it took me a week to understand what it actually did.

Pragmatic Code Wins

The engineers who consistently deliver — the ones who ship reliable systems and somehow always finish on time — write code that prioritizes readability over elegance. Their code tells you what it does by reading it top to bottom. No treasure hunts through inheritance hierarchies. No puzzle-solving to trace a function call through four levels of indirection.

A recent r/ExperiencedDevs thread put it perfectly: the goal of a senior engineer shouldn't be "Beautiful Code" — it should be "Minimal Code." Not minimal as in fewest characters, but minimal in unnecessary complexity. Every abstraction must earn its place.

Dan Abramov (co-creator of Redux, now at Bluesky) wrote about this years ago — the idea that sometimes duplicating code is cheaper than the wrong abstraction. The wrong abstraction creates coupling that's expensive to undo. Copy-pasting 10 lines? That's a five-second fix if requirements diverge later.

Abstractions Have a Cost Nobody Counts

Every abstraction layer you add has three hidden costs:

Cognitive load. A new developer joining the team has to understand the abstraction before they can understand the feature. If your abstraction doesn't map to a concept they already know, you've created a learning barrier.

Debug distance. When something breaks, how many files do you touch to trace the problem? Each layer of abstraction adds a hop. In a flat, "ugly" function, the bug is right there. In a beautifully abstracted system, you're playing hot-and-cold across a dozen modules.

Change resistance. Abstractions encode assumptions about how things work. When requirements change (and they will), the abstraction either bends to accommodate or becomes a straitjacket. I've watched teams spend more time refactoring abstractions than building features.

When Clean Code Rules Actually Hurt

DRY taken to extremes. Two functions share 5 lines of similar-but-not-identical logic. Someone extracts it into a shared utility with a parameter to handle the differences. Six months later, that utility has 8 parameters, handles 5 different cases, and nobody wants to touch it. The "duplication" was fine. The abstraction is now the problem.

Premature patterns. You've got one type of notification. Someone builds a NotificationFactory with a strategy pattern, a builder, and a plugin architecture — because "we might need different types later." You never do. Now you maintain an over-engineered mess for one notification type.

Tiny functions everywhere. Breaking a 50-line function into ten 5-line functions doesn't automatically make it clearer. If I have to jump between ten functions to understand a single workflow, you've traded one kind of complexity for another. Sometimes a longer function with clear comments is genuinely easier to follow.

What Good "Ugly" Code Looks Like

Good pragmatic code:

  • Is boring. No clever tricks. No "elegant" one-liners that require a PhD to parse. Just straightforward logic that does what it says.
  • Has obvious names. calculateMonthlyRevenueForActiveSubscriptions() beats calcRev(). Verbose? Sure. But you never need to look up what it does.
  • Keeps things local. The context you need to understand a piece of code should be in that piece of code, not scattered across the project.
  • Duplicates when it makes sense. Two similar functions that might diverge later? Keep them separate. Future-you will thank present-you.
  • Comments the "why," not the "what." The code says what it does. Comments explain the business reason, the edge case, the thing that isn't obvious.

Ship It, Then Clean It (Maybe)

The best engineers I've worked with share a philosophy: get it working, get it correct, get it fast — in that order. "Clean" is conspicuously absent from that list because clean is a means, not an end.

Code exists to solve problems. If your beautifully architected solution takes twice as long to build, costs more to maintain, and is harder to debug — but it follows all the rules in the book — is it actually better?

Write code that works. Write code that's readable. Write code you can debug at 3 AM when your brain is running at 40%. That's the real bar. Everything else is aesthetics.

Top comments (0)