Should we stick to old patterns or sacrifice consistency?
⛑️️ My First Aid Kit can help you rescue any codebase quickly and safely!
Consistency is great!
A consistent codebase is easier to work with because you get used to its patterns. Your brain creates shortcuts that help you read its code faster.
Working with Legacy Code… is a different story 😅
Code usually isn’t consistent in a legacy codebase. The older it gets, the more patterns you see emerge. They accumulate into layers. Sometimes you can even tell how old some piece of code is from what it looks as if it was a tree trunk.

It’s hard for a codebase to stay consistent
As time passes, new patterns emerge. New ways of solving problems become idiomatic. People learn these new ways and bring them back into the codebase.
That’s a good thing! It means the team keeps learning.
Not only the team learns, but the team changes. Over time, new developers onboard and old developers quit the project. The way the team works evolves with the people composing that team.
It’s a living system 🌱 #symmathesy
The understanding of the problem to solve evolves too. The team learns from the feedback it receives:
- from the users of the product, telling about the quality of the solution
- from the bugs and outages, telling about the wrong assumptions
If a product is successful, it will stay around for years, maybe decades. Therefore, it becomes harder and harder to maintain consistency within the system.
Preserving consistency has a cost
Think about all these React codebases that have been built with Classes Components for years, until Functional Components became the official way to go…
What do you do when you have been using Bluebird.js since 2014, but most of it could be replaced with native Promises nowadays?
What if you’ve built your product for a few years until you’ve finally found a product-market fit. Now you want to grow, but development is slowing down. What do you do when people like me told you it would be easier to maintain if you’ve had decoupled the storage mechanism from the business logic? 😅
Consistency is valuable. Evolving the way things are done is valuable. Having both, in the long run, has a cost.
It takes time to change from The Old Way to The New Way. In the meantime, the code is inconsistent, confusing. This cost can’t be neglected.
Most teams don’t have time to burn cycles to transition from pattern A to pattern B. They need to make a case for it. It’s hard to make convincing, tangible arguments when it’s all about the relative speed of navigating through the code…
That’s how you end up stuck with old practices that won’t change because “we don’t do this here”.
Read: ”… and it would cost too much to change the way we work”.
Preserve consistency vs. allow for progress?
Here’s the dilemma. Should you:
- Keep doing things the way it has always been done and hinder (probably) better ways of doing them?
- Change the way you work, but creating inconsistency across the codebase?
On a 20+ year-old legacy codebase, this isn’t an easy decision.
I do have an approach that balances the benefits of both paths AND minimizes the downsides. Read along…
Allow for changes, but clarify the standard
Let’s start with that: yes, I think you should evolve the ways things are done in a legacy system.
Of course a legacy system has inertia. It comes with a legacy culture. You can’t change things as fast as you would in a greenfield project.
Still, constantly pushing for improvements and change is the best thing you can do. It will take time, but time is on your side. Little improvements compound over time. You can massively transform the system if you keep slowly pushing in the right direction.
But first, you should make the direction clear.
Make standards explicit
In my experience, that’s what most teams are lacking.
Most practices are implicit and acquired across years of working on the system. That’s bad because you can’t efficiently change the ways things are done if it’s not clear how things are done in the first place.
Here’s how you can solve that:
- Start with a 1h brainstorming session with the engineering team. The goal is to collect in a single document what are the practices and patterns your team is using.
- Put that document in a place where it’s easy to find, read, and update.
Don’t aim for a perfect document. Timebox the time spent on this.
When collaborating (code reviews, pairing…), note the way how things are done. Refer to the document so everyone follows the same standards.
😉 #consistency
Team standards >> My standards
Team standards are more important than personal standards.
I prefer to put the exports at the top of my modules. I think it’s better for a few reasons. But that’s a personal taste. At work, I follow the conventions of our team instead of my personal style. It makes the code less surprising for anyone who has to maintain it.
In doubt, I can refer to the document to know what’s the way our team is doing things today. That is super helpful when working with a legacy system with inconsistent patterns.
But because of that, it may happen that decisions about team standards turn into endless debates. One solution: timebox.
Adopting a standard is more important than adopting the best one.
If you notice the discussion is going nowhere and there’s no consensus, have the Tech Lead decide. Start with that.
Some things are difficult to prove with pure debate. You’ll go faster by picking a way and THEN see if that creates new problems.
Whenever possible, automate
Some things don’t worth spending time and energy to manually manage them. Computers can automate work for you, use them. That will save you precious hours every week.
If you don’t have it already, I encourage you to automate 2 things:
- Code formatting. Use tools like Prettier to format the code automatically. Share the standard configuration in the source code. Make it run automatically on commit. Don’t make people think about it. The exact coding style doesn’t matter so much, as long as it’s consistent. You get used to it.
- Linting. Some rules can be enforced automatically, and you should do that. That is less optimal than code formatting (the feedback is slower), but it’s way more efficient than doing it manually.
Once these are automated, your coding standards document will only refer to things that can’t be. This is where things get interesting. You have more time to think about consistent approaches to solve problems, like Design Patterns.
Explicit standards will promote consistency across the codebase.
And that will help you work faster.
That’s for #consistency, but how do you adopt new ways of doing things?
…
…
…
By allowing changes! 😏
Change standards AND document the change
If you think there’s a better way to doing things, you should:
- Suggest to change things
- Keep following the documented standard in the meantime
It doesn’t take much: a short async discussion on a pull request, or a Slack thread could do. If the discussion takes long, I recommend having a synchronous meeting to discuss.
It can be ad-hoc, or you may dedicate a 30min meeting every 2 weeks to discuss the suggestions. It doesn’t have to take long to be efficient, but it should be frequent enough.
Alright! Say you decide on a new way of doing something, how do you preserve the sacred consistency?
Now we’re getting into the heart of the problem…
