Back to blog

Clean Code Is a Lie

Why the pursuit of "clean code" is often counterproductive, and what actually matters.

Every developer has a different definition of "clean code." Ask ten engineers what it means, and you'll get twelve answers. That's the first sign something is wrong with the concept.

Don't get me wrong — I care about code quality. I care deeply. But the industry's obsession with "clean code" as a virtue in itself has done more harm than good. It's become an excuse for bike-shedding, over-abstraction, and spending three days renaming variables instead of shipping features.

The abstraction trap

The most common mistake I see in codebases that worship "clean code" is premature abstraction. Someone writes a function that does one thing. Then they notice a second function does something similar. So they create a shared abstraction to handle both cases.

Six months later, that abstraction handles fourteen cases with a configuration object that has thirty-two optional properties. Nobody understands it. Everyone is afraid to touch it. The "clean" solution became the messiest part of the codebase.

Three similar functions are better than one incomprehensible abstraction. Duplication is cheaper than the wrong abstraction.

What actually matters

Instead of "clean code," I optimize for these things:

  • Deletability. Can I remove this code without breaking everything? Loosely coupled modules are easier to work with than tightly "clean" ones.
  • Readability at the call site. I don't care if the implementation is ugly if calling the function is obvious. The interface matters more than the internals.
  • Behavior under failure. What happens when things go wrong? A well-tested error path is worth more than a beautifully named function.
  • Time to change. How long does it take a new developer to modify this code? That's the real measure of quality.

The refactoring treadmill

I've seen teams spend entire sprints "cleaning up" code that was working fine. They rename things, extract classes, add layers of indirection — and at the end of it, the software does exactly what it did before, but now it's in six files instead of two.

Refactoring is valuable when it's driven by a need. You refactor because you need to add a feature and the current structure makes it hard. You don't refactor because the code doesn't match some platonic ideal of cleanliness.

Ship code that works

The best code I've ever written wasn't the cleanest. It was the code that shipped on time, handled edge cases, had good tests, and was easy for the next person to modify. Some of it was ugly. All of it worked.

Stop chasing clean. Chase correct, maintainable, and shippable. Those are the things that actually matter.