I’ve been thinking lately about the question of how to decide what’s a good programming practice and what’s not.
One way of looking at this is that it’s all just subjective opinion. Just do whatever works for you. You might call this the “anything goes” principle.
The problem with the Anything Goes Principle is that it doesn’t solve any meaningful problems. At best it works as a way to sometimes get strangers to stop arguing on the internet. It certainly doesn’t solve a debate between two team members in an organization. The Anything Goes Principle is simply a way to agree to disagree, not a way to resolve a disagreement.
Another way to approach the question is what you might call the “consensus principle” or the “best practice principle”. This principle says that whatever the prevailing best practice in the industry is is the right answer. But this method is easily debunked. There have been many instances in history where the consensus view in a certain field is just plain wrong. As the saying goes, “What’s popular is not always right”. The truth can’t be discovered via popularity contest.
Here’s what I think is the real key to recognizing a good programming practice: an explanation which stands up to rigorous criticism and which is sufficiently specific that it couldn’t be used to defend any other principle.
Let’s work with an example. It’s a very uncontroversial principle in programming that, in general, clear and accurate variable names, even if they may be long, are better than short, cryptic variable names. This principle has a strong explanation behind it. Clear variable names are, by definition, self-explanatory. When a name is clear, the reader can learn its meaning directly from the name itself rather than having to infer the meaning by studying the surrounding context. In terms of time and cognitive strain, it’s cheaper to learn the meaning of a variable by simply reading the name than by studying the surrounding context. This explanation is, I think, very hard to refute.
This principle even has an exception that proves the rule. There are times when a one-letter variable name is actually better than a long-and-clear name. The explanation for this is that when the scope of a variable is very small and the original name of the variable is not particularly short, the repetition of the long variable name can actually present enough noise in the code that the long-variable version is harder to understand than the short-variable version.
And by the way I want to note that the argument isn’t that the proponent of this rule personally finds certain code easier to understand. The argument is that a typical programmer would find the code easier to understand, since “a typical programmer” is the likely audience for the code, not specifically the proponent of the rule. So the rule could not be refuted by the argument of “well I personally think short variable names are easy enough to understand”. The argument would have to be “I think short variable names are easy enough for the typical programmer to understand”. It’s the difference between a subjective argument and an objective one.
Here’s an example of a poor explanation. A certain article about service objects claims that “Services are easy and fast to test since they are small Ruby objects that have been separated from their environment.” This explanation is weak partly because it could equally be applied to many other practices. The quality of being small and “separated from their environment” (in other words, loosely coupled from dependencies) is not unique to service objects. Furthermore, the quality of being small isn’t inherent to what a service object supposedly is. I’ve seen plenty of gargantuan service objects. And for that matter, loose coupling isn’t an inherent property of service objects either, and I’ve also seen plenty of service objects with tight coupling to their dependencies. My personal distastes for service objects aside, these explanations for the merits of service objects are objectively bad.
If a certain programming practice can address all the criticism it’s subjected to with specific and objective explanations, then it’s probably a good one. If not, it’s probably a bad one. And while everyone is of course entitled to their own subjective opinion, much of the quality of various programming practices is actually a matter of objectivity. At least that’s what I think.
Great post, thanks for sharing. I totally agree with it.
Another argument I particularly find anoying is when you present good arguments but the response is ”but the rest of the project’s code was done differently so we will continue this way”.
What’s your opinion on continuous refactoring vs big refactors tickets (accumulated in the backlog)?
Regards