Skip to main content
2026-01-153 min read
Software Engineering

Clean Code Considered Harmful

The book Clean Code is one of the most recommended pieces of literature in our field. It’s held up as a sacred text, the definitive guide to writing good software. And that’s precisely the problem. What started as a well-intentioned set of heuristics has mutated into a dogmatic, quasi-religious movement that actively encourages bad software design.
The pursuit of "cleanliness" as prescribed by the book has become a cargo cult. Developers, armed with a checklist of rules, march through codebases, refactoring everything into a state of aesthetic purity while completely missing the point. The point is not to have small functions. The point is not to have clever names. The point is to have software that is easy to change. And the dogmatic application of "Clean Code" principles often makes software harder to change.

The Sin of Over-Abstraction

The most egregious sin committed in the name of Clean Code is the fetishization of abstraction, driven by a pathological fear of repetition (DRY - Don't Repeat Yourself). The Clean Code acolyte sees two lines of code that look vaguely similar and immediately reaches for a design pattern, creating a factory of factories, a strategy of strategies, a labyrinth of indirections that would make a seasoned architect weep.
The result? You want to understand what a simple button click does. You start in one file, which calls a method in another, which delegates to a service, which is an implementation of an interface, which is resolved by a dependency injection container. Five files later, you’ve completely lost the plot. The code is "clean" according to the rules—each function is tiny, each class has a single responsibility—but it’s also completely incomprehensible.
Error rendering diagram: Parse error on line 3:
...--> B{button.onClick()};      B --> C[C
-----------------------^
Expecting 'SQE', 'DOUBLECIRCLEEND', 'PE', '-)', 'STADIUMEND', 'SUBROUTINEEND', 'PIPE', 'CYLINDEREND', 'DIAMOND_STOP', 'TAGEND', 'TRAPEND', 'INVTRAPEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'PS'
graph TD
  subgraph "The 'Clean Code' Rabbit Hole"
      A[Developer: 'What does this button do?'] --> B{button.onClick()};
      B --> C[ClickHandler.handle()];
      C --> D[new ActionService().execute()];
      D --> E[ActionFactory.getAction('USER_CLICK')];
      E --> F[new UserClickAction(new ValidationStrategy())];
      F --> G[validator.validate(context)];
      G --> H[context.getPrincipal()...];
      H --> I[...];
      I --> J[Finally, the actual work: db.save(user)];
      J --> K[Developer: '...I need a drink.'];
  end

  style A fill:#cde4ff
  style K fill:#ffcdd2
This is not simplicity. This is complexity, scattered and hidden. A little bit of repetition, a slightly longer function that tells a coherent story from top to bottom, is infinitely more maintainable than a perfectly "clean" but fragmented mess.

The Fallacy of Infinitesimal Functions

"Functions should do one thing. They should do it well. They should do it only."
This is perhaps the most abused rule in the book. Taken to its logical extreme, it produces codebases with a terrifyingly high surface area. You end up with functions that are nothing more than a single line, wrapped in a name that is often longer than the code itself.
The problem is that "one thing" is a fractal. What is "one thing" at a high level is composed of many smaller "things" at a lower level. The art of programming is choosing the right level of abstraction to work at. Dogmatically breaking everything down into the smallest possible units doesn't reduce complexity; it just shuffles it around. It replaces a single, comprehensible narrative with a thousand tiny, disconnected snippets that the reader is forced to piece back together.
The cognitive overhead of navigating this fragmented landscape is immense. You can't just read the code; you have to become an archaeologist, digging through layers of function calls to uncover the original intent.

Naming Is Not a Substitute for Simplicity

Clean Code enthusiasts will tell you that the solution to the complexity they’ve created is naming. If you just name your twenty new classes and fifty new functions perfectly, the system will be self-documenting!
This is a fantasy. No amount of clever naming can salvage a system that is fundamentally over-engineered. In fact, it often makes it worse. The codebase develops its own baroque vocabulary, a private language that every new developer must learn. You have your UserRegistrationService, your UserRegistrationOrchestrator, your UserPersistenceStrategy, and your UserValidationHandler. They all sound important, but they obscure a simple truth: you’re just saving a user to a database.
💡
Pro Tip: If your class names sound like they were generated by a corporate buzzword API (EnterpriseDataOrchestrationStrategyFactory), you haven't made it self-documenting, you've made it self-important.
Good code doesn't need a dictionary to be understood. It's straightforward. It's direct. It solves the problem in the most obvious way possible.

Reclaiming "Clean"

It's time to reclaim the word "clean" from the dogmatists. Real clean code is not about adhering to a set of arbitrary aesthetic rules.
Real clean code is pragmatic. It recognizes that sometimes, a little repetition is better than a bad abstraction. Real clean code is humble. It doesn't try to predict the future with layers of unnecessary generalization. It solves today's problem in a way that makes it easy to solve tomorrow's. Real clean code is readable. It tells a story. It can be followed by a human, from start to finish, without requiring a debugger or a map. Real clean code is malleable. Its primary virtue is that it is easy to change.
Stop asking "Is it clean?" and start asking "Is it simple? Is it easy to change?" Stop worshipping at the altar of small functions and start appreciating the clarity of a straightforward narrative. The goal is not to write code that looks pretty in a textbook. The goal is to build systems that work, that last, and that don't make the next developer want to quit their job.
Syntax error in textmermaid version 11.6.0