The dangers of best practices

There are a lot of reasons we look to define ‘best practices’ around the way we develop software. The largest reason for me is so I can solve new and more interesting problems, I don’t want to repeatedly solve the same problem I had yesterday. However, ‘best practices’ isn’t a silver bullet and they can at times create new problems. I want to look at some of the problems I’ve seen first hand and possible ways to mitigate them.

Problems

There is no ‘best’

The world of software is a complex place where we have a vast array of solutions to even the simplest problems. It’s very difficult to pull individual solutions out as ‘best’, there are always trade-offs between solutions and the context that surrounds them. We can often say that ‘Solution A’ is better than ‘Solution B’ given our circumstances, but that doesn’t imply that ‘Solution A’ is the best solution. Under slightly different circumstances the reverse might be true. It’s rare to find solutions that are universally better than all other possible solutions.

For example, this document suggests the best way to deal with cross cutting concerns in a nodejs app is to package them as an NPM package - https://github.com/i0natan/nodebestpractices#-13-wrap-common-utilities-as-npm-packages.
While this isn't terrible advice, it fails to consider the context of how many nodejs services a team is running. At one service this is definitely not the best solution. At 5 services it could still be argued that duplication is better, in some circumstances. When you have hundreds of microservices it's more sound advice.

It’s yesterday’s ‘best’

As programmers our environment moves quickly, we have new programming languages, frameworks, tools, and libraries being released at a fast pace. On top of this the skills we have in a team is generally increasing, meaning the number of possible solutions we can imagine is increasing. When something becomes well defined (like best practices typically implies) it’s harder to modify and harder to keep pace with these changes. This same problem is the same problem we face elsewhere in programming - documentation not keeping pace with changes, architecture diagrams becoming out of date, etc. This isn’t to say we can’t evolve best practices at the same pace as our environment, but it requires dedicated effort and discipline.

Javascript and Infrastructure are two examples of software that moves quickly. Javascript to the point where it has become a joke - https://dayssincelastjavascriptframework.com/. For a long time Angular was considered the best client side framework, more recently React would have worn that crown, and now some might consider Vue that way. Infrastructure has been more recent with Docker and Kubernetes having a huge amounts of momentum, and frequently having new tools released.

It’s someone else’s ‘best’

It’s easy to read articles online about someone else’s solution to a problem. Often it’s easy to apply their solution to your problem, but we don’t always get the same outcomes as they claim. Sometimes you will, and if that’s you - congratulations, but it’s not always like this. One of the biggest examples of this is around agile software delivery. Applying someone else’s process to your team is unlikely to have the same outcomes.

The wrong mindset

One of the biggest issues I’ve seen is the mindset this seems to create in people. This mindset is a dogmatic view of the solution that has been defined as best. A dogmatic view that there will never be a better solution. Dogmatic views makes it harder to introduce change than it should be. Why this happens I’m not sure (maybe it’s down to psychology and our subtle interpretation of the word best); but I’ve seen it happen to more people than you’d think, often people who claim to be pragmatic and embrace change.

What can you do?

Best is the enemy of better

I’d like to give many people the benefit of the doubt and assume that when they say “best” they mean - “given the languages, frameworks, and tools available to the people in the team with their current knowledge and skills this is the best”. The issue is when someone else hears best, they might not have the same interpretation.

‘Better’ is a more pragmatic view of a solution. It is easy reason about a solution being ‘better’ than other solutions available. However, it doesn’t have the same long running implications.

Stop cargo culting

Stop blindly applying someone else’s solutions to your problems. Just stop. Spend your time understanding why that solution worked for someone else. As an example, I’ve heard companies claiming they want to implement Spotify’s “squads and guilds” model. Instead think about why this model might have worked for Spotify and how many iterations they might have been through. My interpretation is that it’s down to autonomy and communication - squads create cross-functional autonomous teams, guilds creates communication with people of similar skill sets or who might be solving similar problems in another team.

Examples over concrete implementations

For solved problems you want solutions and patterns to be easy to find, follow, and update. Pattern libraries are a great example of this when it comes to front-end code and why I would recommend building a pattern library before a component library. A pattern library is lightweight examples of how you could use something existing to solve your problem, component libraries are concrete implementations of these examples. Examples allow you to extend and change the pattern if it doesn’t quite fit your problem, concrete implementations are more difficult to do this. Only as patterns mature the concrete implementation become more valuable.

Inconsistency isn’t the devil

We often look to consistency as a great way to reduce mental overhead, it makes it easy to jump around different applications and onboard new team members. However, a strict need for consistency can block and discourage patterns being updated or replaced. For example, refactoring a codebase to use a new pattern, it’s unrealistic to try and update a pattern everywhere it is used immediately, for a period of time it’s often better to embrace this inconsistency for a period of time while the new pattern gets applied everywhere.

Though, even this view is dogmatic, there will always be more context to your problems and patterns and it’s up to you to make those tradeoffs; and there is no simple solution - https://markhneedham.com/blog/2010/05/05/consistency-in-the-code-base-and-incremental-refactoring/



Overall I like the promise of best practises. I want to spend my time thinking about solving more interesting problems. However, in reality we need to be vigilant they don’t create an environment where people don’t think at all. For me it comes down to pragmatism. Pragmatism to accept we’re not always going to have the best solution but we can continue to do better.