Clean Code by Robert Martin has sold millions of copies. It's assigned reading at bootcamps. It's the reference engineers cite in code reviews when they reject a PR.
It's also responsible for some of the most over-engineered, slow-to-ship codebases I've ever seen.
I'll say the quiet part out loud: clean code orthodoxy is a productivity killer dressed up as professionalism.
TL;DR: Clean Code orthodoxy treats abstraction and small functions as moral imperatives instead of engineering trade-offs, which is how teams end up with interfaces wrapping three lines of logic and three-hour PR reviews over naming while bugs sit in production. The actual question is never "does this violate SRP," it's "what does this abstraction cost versus what it buys right now." Ship the direct, readable version; add the abstraction later if duplication actually shows up. Pragmatic engineers can write clean code and fast, ugly, working code, and they know which one the moment calls for.
What the Cult Looks Like in Practice
When a team internalises clean code rules as moral imperatives rather than engineering tradeoffs, you get:
- Three-hour PR reviews debating variable names while a bug is in production
- Interfaces and abstract classes wrapping three lines of logic "for extensibility"
- Refactors that make code more "readable" but introduce new failure modes
- Engineers who feel morally superior for catching an impure function, while the feature ships two weeks late
Here's the pattern I've watched play out in real teams:
// What the clean code zealot writes:
// "Every function should do one thing"
// "Abstractions prevent duplication"
// "Functions should be < 10 lines"
interface DataTransformer<T, R> {
transform(input: T): R;
}
class OrderItemPriceExtractor implements DataTransformer<OrderItem, number> {
transform(item: OrderItem): number {
return this.extractPrice(item);
}
private extractPrice(item: OrderItem): number {
return item.price;
}
}
class OrderSubtotalCalculator {
constructor(private readonly extractor: DataTransformer<OrderItem, number>) {}
calculate(items: OrderItem[]): number {
return items.reduce((sum, item) => sum + this.extractor.transform(item), 0);
}
}
// What a pragmatic engineer writes:
function calculateSubtotal(items: OrderItem[]): number {
return items.reduce((sum, item) => sum + item.price, 0);
}The second version is objectively better. It's shorter, has zero indirection, is trivially testable, and does exactly what the name says. The first version is an architecture astronaut's flex.
The Actual Purpose of Code
The purpose of code is to solve problems reliably and allow future change. That's it.
Sometimes the cleanest solution to a problem is a 200-line function with clear comments and no abstraction. Sometimes a "dirty" hack is the right call because:
- It ships today and gets replaced in the next sprint
- The alternative is two days of refactoring to support a use case that may never come
- The dirty version is actually easier to understand without context
Pragmatic engineering means asking: what is the actual cost of this decision? Not "does this violate the single responsibility principle?"
The costs that actually matter:
| Decision: add abstraction layer | |
|---|---|
| Real cost | +2 files, +40 lines, 1 more indirection hop future readers need to trace through |
| Actual benefit | Reduces duplication IF this is called from 3+ places (which it isn't yet) |
| Verdict | Skip it. If the duplication actually appears, refactor then with real information. |
The Engineers I Respect
The engineers I respect most can write beautiful, clean code, and also write fast, ugly, working code when the situation calls for it. They know the difference.
The clean code cultists don't. For them, every function is an opportunity to demonstrate adherence to the doctrine. That's not engineering. It's performance.
Ship something that works. Refactor when the pain justifies the cost. Not before.
The code review that catches a real bug is worth ten code reviews that debate naming conventions.
Is your team spending more time on code aesthetics than on shipping?
This is one of the most common velocity killers I see on engineering teams. If you're leading a product that's slow to ship and you're not sure why, let's talk. Sometimes the problem is architecture. Sometimes it's this.
Hiring or have a project?
Let's build something that holds.
Full-stack engineering, system design, and legacy modernization. Available for freelance, contract, and full-time roles.