Good code quite frequently comes under fire. Managers explicitly or implicitly pressure developers to cut corners in order to “move fast”.
And sadly, even programmers sometimes argue against writing good code. They say things like “it doesn’t always need to be perfect, because after all we need do to ship”.
These arguments sound reasonable on the surface but, as we’ll see, they contain subtle lies.
The biggest lie in many arguments against good code is that programmers spend too much time gold-polishing their code. To me, cautioning programmers against gold-polishing is kind of like, for example, cautioning Americans not to starve themselves and become too skinny. Sure, it’s a theoretical danger, but our in reality our problem is overwhelmingly the opposite one. Similarly, the problem in the software industry is not that we spend too much time writing good code, but that we spend too much time wrestling with bad code.
If you ever find yourself pressured to write sloppy code, my goal with this post is to arm you with some arguments you can use to push back.
Let’s start with what “good code” means to me.
What “good code” means
Good code is code that’s fast to work with. Good code is easy to understand and change. To me it’s nothing more than that.
If the code can be changed quickly and easily, then it’s good, by definition. If the code is slow and difficult to change then it’s bad. Any specific coding practices like short methods, clear names or anything else are just incidental. The only thing that matters is whether the code can be changed quickly and easily.
One reason I like this definition of good code is that it also ought to be appealing to everyone. Developers like code that’s quick and easy to change. Non-technical stakeholders also ought to like the idea of code that’s quick and easy to change.
People might not understand exactly what it means for code to be “high quality” or “good”, but they can certainly understand what it means to be able to work quickly.
Anytime you have to make a defense for writing good code, it seems smart to remind your “opponent” (who will hopefully become your ally) that your goal is to move fast.
Before we address some of the bad arguments for writing bad code in order to refute them, let’s first talk about some bad arguments for writing good code. It’s good to be aware of the bad arguments for your case so you can avoid trying to use them.
Weak arguments for writing good code
I think if we’re going to write good code, we should have a clear understanding of why we’re doing it. We should also be able to articulate to others exactly why we’re doing it.
The bad arguments I’ve heard for writing good code include things like “craftsmanship”, “professionalism” and “integrity”.
Saying something like “I write good code because it’s more professional to write good code” is a little bit of a copout. It doesn’t explain why it’s more professional to write good code.
Same with craftsmanship. You can say “I write good code because I believe in craftsmanship”. But that doesn’t explain what the benefits of craftsmanship supposedly are.
Such appeals are also selfish. They speak to what makes the programmer feel good, not to what benefits the business. These types of arguments are unlikely to be persuasive except perhaps to other programmers.
So when people pressure me to cut corners to get a job done quickly, I don’t ever push back with talk about craftsmanship or professionalism.
Weak arguments for writing bad code
Finally, here are some bad arguments for doing sloppy work and why I think each one is flawed.
“Perfect is the enemy of the good”
This is a good and useful saying for the cases to which it actually applies. For example, when you’re talking about project scope, “perfect is the enemy of the good” is a good saying to keep in mind. A bent toward perfectionism can eat up all your time and keep you from shipping something that’s good.
But with respect to code quality, “perfect is the enemy of the good” is almost always a false premise. Comically so, in fact.
The typical spectrum of possibilities for a coding change usually doesn’t range from “perfect” to merely “good”. Usually it ranges from “acceptable” to “nightmarish”. A more honest version of this saying would be “acceptable is the enemy of the nightmarish”.
Refutation: If someone tries to pull “perfect is the enemy of the good” on you, you can say, “Oh, don’t worry, I’m not trying to make it perfect, I’m just trying to make the code understandable enough so I can work with it.” This statement is hard to refute because it appears as though you’re agreeing with the other person. Plus no reasonable person would argue against making the code understandable enough to work with. What you’re saying is also true: you’re not trying to make the code perfect. You’re just trying to make it not nightmarish.
“Users don’t care about code”
This idea reflects a shallow, elementary level of thinking. Yes, obviously users don’t directly care about code. But bad code has negative consequences that eventually become obvious to users.
Bad code (again, by definition) is slower to work with than good code. When bad code is piled on top of other bad code, the slowdowns become exponential. Changes that should take a day take a week. Changes that should take a week take a month. Users definitely notice and care about this.
Bad code is also harder to keep bugs out of than good code. Code that’s hard to understand gives bugs safe places to hide. Users are obviously going to notice and care about bugs.
Refutation: If someone uses “users don’t care about code” on you, you may be working with someone whose critical thinking skills are so weak that the person is hopeless to try to persuade. You can of course try to point out that users don’t care directly about bad code, but users do care about the effects of bad code, like slow delivery and buggy software.
“Your company might go out of business”
Multiple times I’ve heard something along the lines of this: “If your company goes out of business, it doesn’t matter if the code was perfect.” This might sound on the surface like a slam-dunk argument against geekishly polishing code rather than maturely considering the larger business realities. But it’s not.
All that’s needed to destroy this argument is a reminder that good code is called good because it’s faster to work with. That’s why we call it “good”.
Refutation: Good code is called good because it’s faster to work with. Cutting corners only saves time in the very very short term.
“There’s no time” or “my manager made me do it” or “they did the best they could with the time they had”
These aren’t arguments for writing bad code but rather excuses for writing bad code.
No one is holding a gun to your head and making you write shitty code. You’re the steward of your codebase. It’s your responsibility, and no one else’s, to protect the quality of the codebase so that the codebase can continue to be fast to work with.
If you consciously choose to take on technical debt, you’ll almost certainly never be granted time to pay back that technical debt. Instead you’ll have to pay interest on that technical debt for the rest of your time with that codebase.
It’s easy for your boss to tell you to cut corners. Your boss doesn’t have to (directly) live with the consequences of poor coding choices. But eventually when the poor coding choices accumulate and bring development to a crawl, your boss will blame you, not himself.
Obviously it’s not always easy to fight back against pressure to cut corners. But I think developers could stand to fight back a little more than they do (even if it means being quietly insubordinate and writing good code anyway), and I think developers would benefit greatly from doing so. And so would their bosses and the organizations they work for.
My argument for writing good code
My argument for writing good code is very simple: code that’s easy to understand and change is faster to work with. Obviously that’s better.
I’ll also point out something that might not be obvious. Coding choices are multiplicative. The coding choices you make today have an influence over how easy the code will be to work with tomorrow, the next day, and every day after that. Same with the coding choices you make tomorrow. Each day’s choices multiply against every previous day’s choices.
The result is exponential. Poor coding choices every day lead to an exponential slowdown in productivity. Good coding choices unfortunately don’t lead to an exponential speedup, but they do at least avoid the exponential slowdown.
You can think of each day’s code additions as having a score. If you add code that has an “easy-to-change score” of 90%, and you do that three days in a row, then your cumulative score is 0.9^3 = 72.9%. If you add code that has an “easy-to-change score” of 40% three days in a row, then your cumulative score is 0.4^3 = 6.4% (!). This is why programmer productivity doesn’t vary by a factor of just 10X but more like infinityX. Bad code can eventually drive productivity down to something close to 0%.