If you work anywhere near the delivery end of the software industry, you’ll have heard people talk about “best practices” a lot. There’s a whole lot of techniques and processes that have become tradition over the years - the format of commit messages, code review, various forms of automated testing, conventions specific to various programming languages, and popular design patterns.
But are these best practices actually best? Are they even good at all? Are they the product of actual scientific studies on their effect on productivity, or at least the result of hard-earned lessons, or are they simply traditions, blindly copied and believed to be good?
Best practices or good practices
Calling a practice “best” is a bold claim. It implies - no, outright states, then perhaps rolls that back and claims it’s hyperbole if challenged - that there cannot possibly be any improvement. This is unfortunate, as it discourages attempts to improve the practices. Most modern software teams use some kind of regular “retrospective” to look at how the team works, identify problems, and agree on solutions. Indeed, doing so is a best practice! A common sentiment expressed in them is that the team should adopt more “best practices” in order to reap their benefits, but it’s rare to challenge the best practices themselves in such meetings. Any such discussion is usually phrased as debating how the best practices are applied here, tweaking minor details, but the best practice itself is rarely challenged or evolved.
Best practices are widely believed to be good, but the widely-known reason for the benefit of any practice is quoted as an article of faith; it’s rarely questioned. Does code review actually increase the quality of code produced? Have we checked? If it does, is the improvement justified by the team velocity costs of requiring code review before changes can be released and the psychological costs?
The outcome of such an analysis needn’t even be “code review is bad”. After all, it became a best practice for a good reason. Ideally, the outcome will be “Code review actually has these benefits and these costs”, which can then lead to a discussion of how to maximise the benefits while reducing the costs - ideally by considering how it fits into other parts of how the team works, rather than in isolation.
But… surely the great minds of our ancestors did that when coming up with best practices in the first place? Aren’t they the results of loads of experience, and already optimised?
No! Because how well something worked in the past is as much a function of the dynamics of that team and the nature of the problem they faced as of the practice itself, and previous results are no guarantee of future performance!
Context is key
The second problem with blindly adopting best practices is that the utility of a practice is highly contextual. Many best practices arise from a particular case study that was publicised somewhere; the Agile movement was largely inspired by Extreme Programming, which came from a single project to build a payroll system. Agile tends to work much better on projects that are a database with a lot of user interface screens to perform operations on objects in the database, generate reports, etc than other kinds of software. The breaking of work down into minimal-sized chunks and developing them incrementally is more practical when there are fewer cross-cutting requirements that affect large swathes of the system. But because of its success in the kinds of systems that it works well in, Agile has become widely accepted as a best practice. But the vital information that is dropped as this lore is passed around is that it’s successful in certain kinds of projects and not in others. And the nature of the team itself matters tremendously, too - teams full of highly experienced practitioners working on a familiar problem domain have very different needs to teams with lots of new developers. Teams where the members largely have interchangeable skills have very different dynamics to ones composed of a highly heterogeneous group of specialists, and it’s a marvel that we assume the same processes for allocating work can be applied to both!
Part of the problem of context being ignored in evaluating best practices is that it discourages there being multiple best practices of a given type. It’s easy to get the impression that Extreme Programming evolved into Agile which evolved into Scrum, when the truth is more that each of these processes are what worked for different teams, and there simply happens to be a timeline where each team developing a method was able to learn from previous team’s results. Each of these approaches actually have their own strengths and weaknesses, rather than being a timeline of improving the best system; the hunger for a ‘one-size-fits-all’ solution masks the real need for bespoke solutions for different situations.
Dogma and box-ticking
Best practice often becomes dogma. Too often have I seen a new developer ask “Why do we do this?” and be told “It’s best practice”. Not only does this shut down the useful discussion of “why do we do this?” and stop the developer learning the meta-knowledge of the challenges of building software as a team, it tells them “If it’s best practice, you just do it; that’s the social expectation”. People feel nervous about questioning best practice, as knowing all the best practices and applying them faithfully is expected behaviour.
Sometimes this gets solidified into policies, procedures, contracts, and even laws. In a data storage project I worked on once, the client requested that all data be “encrypted at rest” (eg, when stored on disks) because it was a requirement from a standard their organisation needed to comply with in order to do business in their industry. We started to talk to them about how the decryption keys would be distributed to the software when it started - should there be a secure key server to handle that, or should administrators enter the key manually during system startup?
But the client wanted none of that complexity and effort. They told us to store the key alongside the encrypted data, so the software could read it during startup with no additional infrastructure or costs to them.
We explained that this would make the encryption useless - it would be like writing the code to an advanced bank vault in a post-it note on the door of the vault.
But they didn’t care if it actually provided any security: they cared that it ticked the box on their compliance checklist.
“Data is encrypted at rest” is a valid best practice. It protects against specific security problems, such as an attacker breaking into a datacentre and stealing the physical disks, or intercepting the old disks when they are replaced by new ones. But the value of it was lost when it became a requirement in a procedure. The requirement should have been “Data is protected from attackers gaining possession of the storage medium, such as by encrypting the data at rest”. Making the best practice become a requirement, divorcing it from the actual problem it tries to solve, made it worthless; and could actively harm security - somebody believing a system was secure against storage medium theft because it complied with the standard could easily make an inaccurate risk assessment on that basis, and divert insufficient resources to preventing media theft; and it can cause effort to be diverted needlessly to building encryption systems when they’re not needed because theft of the medium isn’t actually a risk in the situation at hand.
How can we use best practices effectively?
Best practices are the accumulated cultural wisdom of the software industry. How do we use that wisdom well to actually produce good outcomes?
The crucial thing is to understand that a best practice is an example of a thing that worked well for some teams working on some problems in the past.
Starting from that position, the conversation then needs to be “What best practices might be applicable to our situation? Let’s review them and see how we might be able to learn from them.” Maybe you can just apply a best practice that fits you well. Maybe you need to tailor one, or merge two, or even invent your own from scratch using the existing ones as inspiration. Debating them should be encouraged, and used as an opportunity to question the nature of the team and its problem domain, and for seasoned developers to tell new developers how these differences have shown themselves in projects they’ve worked on in the past, and what techniques worked well or badly in the past - and drive out any trace of dogma!
When a “best” practice is forced on the team, either by an external requirement or by a well-meaning but ignorant administration, you should try and divine the spirit as well as the letter of the requirement - and attempt to satisfy both, to get the actual benefit as well as ticking the box.
The real problem, perhaps, is the name. “Best practices” are rarely “best”!
Author
Tags: