Clean Code Without Dogma: What Actually Matters
Clean Code became a religion. Here's which principles have real ROI, which are cargo-culted rules, and how to push back on dogmatic code reviews.
You're in a code review and someone rejects your PR because a function is over twenty lines long. Not because it's too complex, not because it's hard to test — just because it's over twenty lines. The rule got memorized, context got ignored, and now you're going to spend the afternoon splitting a perfectly readable function into three incoherent pieces.
Clean Code became a religion. And like all religions, it has followers who apply the commandments without understanding the theology.
Why "Clean Code" turned dogmatic
Robert Martin's book came out in 2008. Good book — real insights on naming, separation of concerns, test structure. The problem isn't the book. The problem is that the rules got detached from their context and ended up in PRs, linters, and code standards as absolute truths.
"Functions should do one thing." True — but what's "one thing"? Depends on what level of abstraction you're operating at. A process_payment function that validates the card, debits the account, and sends the confirmation email might be doing "one thing" — processing a payment — depending on where it sits in the system.
"Functions should be at most X lines." Arbitrary number. A fifty-line function that's a well-named sequence of validations is more readable than five ten-line functions you have to jump between to follow the flow.
"No comments — the code should be self-documenting." This is the most dangerous one. Self-documenting code is a legitimate goal, but there are classes of knowledge that code simply can't express: business decisions, deliberate trade-offs, regulatory context. "We're using MD5 here because the acquirer's legacy system doesn't support SHA-256 yet" is a comment that saves hours of debugging. Deleting that in the name of clean code is sabotage.
What actually reduces bugs and maintenance cost
When you look at what causes real production incidents and maintenance problems over time, the patterns that consistently appear are different ones.
Names that lie. A variable called data that holds a user object, a function called get_user that also persists to the database — those are real problems. Honest naming is the clean code principle with the best ROI. It's not about long names or short names; it's about names that match what the thing actually does.
Shared state without discipline. More than function size, mutable state scattered across the system is what makes code impossible to reason about. A small function that modifies global state is infinitely more dangerous than a large function that operates on local data.
Implicit coupling. When two parts of the system depend on each other without that dependency being explicit — through magic constants, through conventions that only live in the original author's head, through hidden side effects. This is the kind of coupling that makes a simple change blow up in three unexpected places.
Missing invariants. Code that allows impossible states — an Order that can exist without items, a User with a null email months after go-live. Using the type system to make invalid states unrepresentable is one of the cheapest and most underrated investments in code quality.
The rules worth actually following
Not all clean code guidelines are useless. Some have real grounding and hold up even outside the original context.
SRP applied at the right level. Single Responsibility Principle matters — but at the module and class level, not necessarily at the level of a twenty-line function. A service class that handles payments shouldn't also send marketing emails. That's a real SRP violation, with real coupling consequences.
Dependency inversion. Code that depends on abstractions instead of concrete implementations is genuinely more testable and more flexible. Not because it looks good — because you can swap PostgreSQL for SQLite in tests without touching business logic.
Tests as specification. Not the 80% coverage rule, but the principle that well-written tests document expected behavior. A test with a good name is executable documentation. That has real value regardless of coverage metrics.
Review by reading cost, not appearance. The right question isn't "does this code look clean?" but "how long does it take someone new to understand what this does and why?" That question has an empirical answer — you can measure it.
When the rule hurts more than it helps
There are specific contexts where mechanically applying clean code produces worse results.
Performance-critical code. Sometimes the readable version is an order of magnitude slower. A manual loop with direct buffer access is harder to read and seventeen times faster. If that code runs ten million times per second, the readable version isn't an option. Document the why, don't refactor for aesthetics.
Glue code and migration scripts. Code that will run once and get deleted doesn't need the same guarantees as code that will be maintained for years. Spending two hours extracting helpers in a migration script that runs tomorrow and gets thrown away is real waste.
Prototypes and experiments. If you're validating a product hypothesis, the code that matters is what lets you iterate fast — not what's production-ready. The mistake is keeping that pattern after the experiment becomes a feature. That's when the investment in quality pays off.
What to do with dogmatic code reviews
If you're on a team where rules get applied mechanically, the problem isn't technical — it's a communication problem about what the rules are for.
The question that unlocked code reviews for me: "what concrete problem does this change solve?" If someone wants to split a thirty-line function, the answer can't be "because functions should be at most twenty lines." The answer needs to be "because this block has a separate responsibility that will need to be reused" or "because this block can't be tested in isolation the way it is."
If there's no concrete answer, the rule is being applied by inertia, not judgment.
When I want a clean diff before submitting a PR — no forgotten debug logs, no dead code, no misleading variable names — I use the Text Diff Checker to look over changes before opening. Doesn't replace judgment, but it helps you see what you're actually delivering with some distance from your own code.
Frequently asked questions
Is Clean Code still worth reading in 2025?
Yes, with context. Read it as a book of principles with dated examples, not as a rule manual. The chapters on naming and testing are still relevant. The Java examples from 2008 and the numeric rules (X lines per function) can be ignored without loss.
Is SOLID the same as clean code?
SOLID is a separate set of object-oriented design principles, though Uncle Bob's books cover both. SRP and DIP have clear practical application. OCP (Open/Closed) and LSP (Liskov) depend heavily on context — applied mechanically in duck-typed languages or functional systems, they produce more bureaucracy than benefit.
How do I convince the team to stop applying rules mechanically?
Don't try to convince with opinion — show it with an example. The next time a rule gets applied in a code review without concrete justification, ask: "what problem does this solve in practice?" Most people can't defend rules when they can't articulate the problem the rule is solving.
Is there a linter that applies these ideas in a non-dogmatic way?
Linters are inherently rule-based, so they have a ceiling. What you can do is configure them for what has real ROI: inconsistent naming, very high cyclomatic complexity (not a magic number, but a threshold the team has calibrated), circular dependencies. And disable the rules that generate more false positives than real problems.
Clean code is readability under real maintenance cost
The question that matters isn't "does this code follow the rules?" It's: "will the next developer who touches this understand what's happening, why these decisions were made, and be able to modify it without introducing bugs?"
If the answer is yes, the code is clean enough — regardless of lines per function or number of comments. If the answer is no, no linter or methodology fixes that: you need judgment, not another rule to memorize.
- 01 What DevOps Actually Is Beyond the Tools DevOps isn't a pipeline or a job title. It's shared ownership between the people who write code and the people who run it in production — and why most teams get it wrong.
- 02 VPS, VPC, and Dedicated Server: What's the Difference and When to Use Each VPS, VPC, and dedicated server appear side by side on every hosting comparison page — but they mean different things. Here's where the money goes and how to decide.