When ‘Clean Code’ Hampers Application Performance
“Many programming ‘best practices’ taught today are performance disasters waiting to happen,” warned Seattle-based programmer Casey Muratori on his educational web site, sparking a debate in the programming community. Some agreed, some disagreed, but lively online discussions ensued, with programmers around the web revisiting or defending long-held assumptions about best practices.
To hype a $9-a-month series of videos on YouTube titled “Performance-Aware Programming,” Muratori shared a free “bonus video” specifically focused on the performance penalty of so-called “clean code” practices, or the long list of well-established rules of not doing things in a certain way. These practices don’t always help the performance of the resulting application, Muratori argued. The ensuing conversation raised the question of what criterion should be used for measuring the effectiveness of code…
Here are a few of the downsides Muratori found to some currently-accepted best practices of writing code:
Making a Switch
For cleaner code, programmers are often urged to avoid code blocks that list out each possible fork that the flow could take, like the switch statements in C where every possible value for a variable creates a separately-coded case. It’s a very common target for criticism among clean code advocates:
- Programmer Arnold Abraham warns that switch statements are “unhandy and bloat your code.”
- Clean Code advocate Robert C. Martin calls the proliferation of switch statements “a common problem in software systems,” pointing out it’s easy to miss a case when changing code, leading to fragile systems. (And more importantly, that the results of each fork-in-the-flow tend to be hidden in lower-level modules.)
- The “Refactoring Guru” site argues that avoiding switch statements will improve your “code organization.”
So Muratori put this to the test — using a common example from clean code advocates. In his video, he creates a function that calculates the area of four shapes. The “clean code” way involves four tidy class definitions to encapsulate area-calculating code for each different shape. Muratori compares its performance to one where a single function offers a line of code for each of the four possible shapes. The results? Muratori’s performance tests show a 1.44x speedup.
But there’s another advantage, Muratori explained in the video. “When your code is organized by operation, rather than by type, it’s straightforward to observe and pull out common patterns.” Compare this to how some clean code advocates even tuck the code for individual classes into separate files.
“The more complex you make the problem, the more these ideas harm your performance” — Casey Muratori
In this example, calculating the area of the four shapes will always involve multiplying a width by a height, though sometimes with a shape-specific multiplier like pi for a circle or one-half for the triangle. That’s much easier to spot when all four calculations appear next to each other in adjacent lines of code — making it easier to then swap in a speedy lookup table for the one thing that differs across all four cases.
“It’s not only much faster, it’s also much less semantically complex,” Muratori argued in the video. “It’s less tokens, less operations, less lines of code.”
And now Muratori’s benchmarks show a 10x improvement in speed…
“The more complex you make the problem, the more these ideas harm your performance,” Muratori wrote. “When you try to scale up ‘clean’ techniques to real objects with many properties, you will suffer these pervasive performance penalties everywhere in your code….”
And Muratori believes it’s more than just an academic question. “If your code runs on a server ‘in the cloud’, your monthly bill is directly proportional to your software’s performance,” noted his introductory blog post. “The math is simple: the slower your software, the more server time (or servers in general) you have to buy….”
The video series provides more examples — but for Muratori, the ultimate conclusion is clear. “For a certain segment of the computing industry, the answer to ‘why is software so slow’ is in large part ‘because of “clean” code’. The ideas underlying the ‘clean’ code methodology are almost all horrible for performance, and you shouldn’t do them….”
In response to a question from the New Stack, Muratori said he believes clean code advocates don’t truly understand how CPUs work — and don’t recognize “the magnitude of the performance costs of their ideas…”
Getting a Reaction
Not everyone agrees. When Muratori’s post was discussed on Hacker News, it attracted 739 upvotes — and 907 comments — but with some commenters suggesting Muratori’s perspective was skewed from his work on game engine optimization.
Graphics programmer Daniel Kvick also works on game optimization and noted that its ongoing focus on GPU optimization “is a whole different beast” from CPU optimization. And developer Jonathan Dickinson argued that game developers “have the luxury of starting from near-scratch every once in a while… I’m guessing that things wouldn’t be so clear-cut if he was given a 10-year-old codebase to iterate on.”
But software engineer Joshua Rumbut appreciated Muratori’s flexibility on what are usually rigid rules for programmers. “One of the nice things about some of the clean code concepts he uses is that (as he shows) you can tactically step back from them in key, performance critical areas and reap these wins.” And web programmer Hasen Judi expressed a more general dissatisfaction with those concepts.
“I’ve never seen a codebase that is written with ‘clean code’ principles in mind that is also maintainable and easy to develop on top of.”
Muratori told The New Stack that “Some of the response was concerning because of how many dissenting opinions appeared to be based on factual errors, but overall I was encouraged by the surprisingly large number of people who dislike ‘clean code’ and want to do something about it. That perhaps bodes well for the future…”
Muratori posted the complete text of his detailed response online — and also engaged in a long but congenial two-part debate on GitHub with Robert C. Martin, author of the 2009 book Clean Code: A Handbook of Agile Software Craftsmanship. Martin conceded the “Clean Code” examples cited by Muratori “are not efficient at the nanosecond level” — but then questions whether that’s really relevant.
“Long ago this would have been generally important. We worried about the cost of function call overhead and indirection. We even unwound loops if we could. This was especially true in embedded real-time environments. But the kinds of environments where that kind of parsimony is important are nowadays few and far between.”
But Muratori summed up his philosophy in a recent interview on a YouTube channel called ThePrimeTime. “In addition to optimizing code, we can also pessimize code. We can do things that make it harder for the CPU to run it, for no real reason… Because of some other weird metrics that I don’t necessarily know where they come from — like clean code — that I don’t feel like anyone ever proved really made anyone more productive, but I can prove they make the CPU less productive, so it seems like a bad trade.”
So what happens now? “The response to the video has actually been rather encouraging,” Muratori told the New Stack.
“I have received a huge number of ‘thank you’ notes from people who disagree with ‘clean code’ principles not just because of their poor performance, but because they do not deliver the supposed benefits in practice (readability, maintainability, etc.)”