Practical .NET

Why I Hate Best Practices

Best practices and principles aren't rules. They're guides to the judgement of the programmer. Sometimes we forget that.

I was at a client's site, and the team I was part of was reviewing some code I'd written. One of the programmers at the review pointed to a piece of my code and commented, "You shouldn't do that." When I asked why I shouldn't do that, the response was, "It violates the X best practice."

I didn't find that answer satisfactory. I had written the code to solve or avoid some sort of problem. Therefore, the correct answer to my question wasn't, "It violates the X best practice." The correct answer would have been either, "It will lead to this unfortunate result or to this problem down the line, which is worse than the problem you're solving," or, "Your code doesn't solve the problem. All it does is move the problem around -- and not in a good way." If the developer had wanted, he could've added, "That's the reason we have the X best practice."

At some point, for this programmer, "best practices" or "principles," had stopped being "best practices" or "principles." Instead, they had become rules to be rigidly applied in every situation.

The Real Definition of a Best Practice

The definition of a best practice (from Wikipedia) is: "a method or technique that has consistently shown results superior to those achieved with other means." The term "consistently" is a powerful one, but it isn't the same thing as "always."

Principles and best practices allow us to understand particular classes of problems and then to avoid those problems. The reason they're called "principles" or "best practices" (and not "rules") is precisely because the people who invented these practices and principles did not want them blindly applied: They recognized that the problems we're solving are too complicated to be handled by applying rules.

This "world without rules" is the one we, as developers, live in. Back in the late 1980s every article I read on the future of programming heralded the coming of "Software Engineering" when software development would become a discipline instead of a craft. In this new age we would feed the requirements into one end of a process and get working applications out the other end. I won't belabor the alimentary nature of that metaphor (and its output) but I will point out that, 30 years later, we're still practicing a craft that hasn't yet evolved into a discipline (and, by the way, when real engineers build a bridge, they may carefully calculate their tolerances but they always add in some additional "buffer").

I've also seen the damage that rigidly applying a best practice can create. There was a time in my consulting career when the most common problem my clients had was that their reports took too long to run. Invariably, it turned out that my client was running their reports against a database in third normal form and their report, as a result, had to join together half a dozen or more tables.

If only a transaction's worth of rows had been involved, this wouldn't have been a problem. But with a report processing hundreds or thousands of rows, the database engine was overwhelmed. Whoever had taken the reporting database to third normal form hadn't understood the problem third normal form solves: Third normal form drastically simplifies updates. In a reporting database where updates consist of inserting rows every night, simplifying updates isn't an issue. In a reporting database, first normal form is sufficient.

Justifying Best Practices

I don't think I'm ignorant about why developers do advocate for best practices. I do realize that just because, right now, we can't imagine a problem doesn't mean there won't be a problem. Developers who want to use some principle or best practice often stress that our inability to imagine a problem might just be telling us about our ability to imagine the future and nothing about the actual likelihood of having a problem. They want to apply the best practice to protect us from problems we haven't imagined.

And I do sympathize with that view (even if I don't agree with it). I came into this craft at the tail end of the structured programming wars when the "goto" statement was banished as a poor practice. The claim of the programmers who wanted to continue to use the "goto" statement was that some problems were better solved with the statement than without it.

One very intelligent columnist (whose name I have, sadly, forgotten) conceded that there might be a class of problems where using the "goto" statement was a better choice than the best practice of structured programming. However, that columnist went on to say the burden was on the programmer who wanted to use the "goto" statement to provide a demonstration that structured programming would not provide as good a solution as the "goto" solution.

I can see that those advocating for a best practice might feel they're in the same position. From that point of view, it's my responsibility to demonstrate that the best solution in this case doesn't involve the best practice. And, quite frankly, I'm willing to do that.

But I think that those who, back in the day, advocated for structured programming were in a better position than those who, currently, advocate for the blind application of "best" practices. The advocates for structured programming had mathematical proofs that every programming problem could be solved with less complexity using three or four structures. Even among the programming practices and principles I do hold dear, I don't know of even one that rises to that level of proof.

For example, as fond as I am of the Single Responsibility Principle, I wouldn't make it a rule because I don't think we have a very good definition of what a "single responsibility" is (certainly not a mathematical one). While I value clarity in my code more than efficiency, I have rewritten some "really obvious code" into more obscure code to fix a performance problem. And I'm not sorry about that, either, because (to quote Adam Turner) I believe that "Performance has no competition." But I also believe that "Fast enough is good enough" and I won't optimize some obvious code into obscurity unless there are actual complaints about performance.

So, for me, the responsibility for applying a principle or practice still lies on the shoulder of the person advocating for it. I know the problem I'm solving. Before someone can get me to alter my code, they have to know the problem their change will solve or present. I think that's only fair. Moreover, in the absence of that explanation, simply invoking a best practice isn't going to convince me to change my code.