Are your legacy applications a nightmare to work with and a pain to maintain?
Should we ask ourselves who died and why we inherited them?
It's easy to understand why starting a new system from scratch – what they call a greenfield project – is exciting and tempting for a developer. In a new project, there’s the possibility to learn new technologies, but I think what people love the most is the ‘authoriality’. We are all developers because we love to build things, and writing something from scratch, taking all the decisions, will appease our self-esteem.
On the other hand, working on a legacy application sounds like messing around with boring old code, which is hard to understand and harder to change. The technology will probably be obsolete and nobody cheers at the prospect of learning something already out of date. But the biggest problem is the risk of creating issues in production, making changes to some code we don't understand completely.
Finally, working on a legacy system can feel like a career dead end, trapping you in the work of keeping some old system alive while the people working on new systems get promoted.
But actually, I love working on legacy code. I would pick up a legacy project over a new greenfield one any day. But this article isn’t about my preferences; it’s about you and how to make your team appreciate working on legacy code.
Here I’m outlining the necessary conditions for enjoyable legacy code, before sharing how you can help your team fall in love with this kind of work.
The essential conditions for enjoyable legacy code work
There are two conditions I need to enjoy working on legacy code. The first is about the code itself. Bjarne Stroustrup once said: ‘"Legacy code" often differs from its suggested alternative by actually working and scaling.’) To qualify as legacy, an application has to be working in production and solve a critical function for the business, otherwise, we can assume they would have retired it already. Some big project that failed to meet some production requirement and has to be fixed doesn't qualify as legacy code in my opinion. It's probably better to rewrite it from scratch.
The second condition is about the process. I enjoy working on legacy code so far as I'm allowed to change it and ‘rejuvenate’ it. I can stand all the quirks they usually come with, because I know that we’ll remove them one at a time. I'm talking about things like weird setup sequences, half-forgotten technologies, overcomplicated configuration, and so on.
How to help your team fall in love with legacy code
Here I’m going to talk about how to teach and pass the love for legacy to the whole team. To play off Peter Drucker’s famous phrase, culture eats technology for breakfast. It doesn't matter how good you are at a technical level; what really matters in terms of results is the culture of the team and the company. So here are some hard-learned lessons for team leaders and engineering managers looking to spread the legacy love.
Let's start considering what I think are the two main drivers behind the general aversion towards legacy code: frustration and fear.
Counteracting frustration and fear
Frustration is often caused by the feeling of being unable to change something. Either because we are not allowed or because we don't know how.
Fear comes mainly from the potential damage that any bug can cause, and the lack of confidence we have in our changes. Legacy systems can be particularly obscure in how they work.
So in order to successfully work on legacy, we need to build teams where people feel empowered to change what they don't like, without fear of breaking things or being singled out if something goes sour.
No one should feel alone against the mountain of old code. It's important to transmit trust and full support to the team. Pairing, or even better regularly mobbing, helps folks gain confidence and the technical skills necessary to safely work with legacy applications.
Changing perceptions around legacy code
The next step is to change the perception: working on legacy can be exciting!
In reality, greenfield projects are much riskier than they’re usually perceived. According to some sources, the majority of new projects are either canceled or fail to meet requirements. This is pretty common in my experience as well. New projects are also prone to become death marches, where some hard deadlines become harder and harder to meet because of missing requirements, last-minute changes, untested technology, and so on.
On the other side, legacy projects have already survived many of these hurdles and they already have real users with solid requirements that can easily be verified. Moreover, as I mentioned earlier, old projects must provide some important value to the business, since they haven’t been retired.
For people passionate about programming, there’s no better way to learn software design than working on an aged codebase that you haven't written yourself. Any change will bring immediate feedback to confirm or disprove it. Instead, at the beginning of a new project any kind of design would work, so it will take a long time before you can learn from it.
Finally, let's consider that at the end of the day, all successful projects will become legacy at some point. Learning to improve legacy code will not only bring new interesting challenges, but it will teach you how to build better projects from scratch as well.
So, once you convince everybody that improving terrible code is the best thing that can ever happen, how can you ensure you’re working with legacy effectively as a team?
Working effectively with legacy tech as a team
Team culture is very important when it comes to successfully working with legacy tech. That’s why it's important to invest in having a group of people that work with auto-discipline, helping each other, knowledge sharing with pairing and mobbing sessions, and consistently using automatic tests, both to validate the design (test-driven) and to verify the system end to end (acceptance tests). There is really no need for cowboy developers in a legacy project.
Make sure your testing is relevant and accurate. Legacy code is a great place for your team to learn how to correctly write tests, and keep them fast and focused. It's also a great opportunity for them to gain experience on how to break ‘big ball of mud’ monoliths into smaller low coupled modules that can be released independently and continuously.
In conclusion, there are a few things that a team leader should keep in mind when preparing the team to work on a legacy project:
- Convey that working on legacy is not a career dead end. It's an important task and management will appreciate the effort required to rejuvenate the legacy project.
- Invest time in improving the infrastructure and the onboarding process before starting developing new features. Sometimes DevOps are more important than pure developers for making old projects easy to work with.
- Don't rely on policies alone to ensure quality and security. Make sure any relevant use case is covered by end-to-end automated tests that run at least before every release. Having a continuous release process does wonders to increase the confidence of not breaking things.
- Organize the development work with frequent mobbing sessions to share knowledge and collectively discuss the new design. Proof of concepts and explorations are best done solo in separate branches.
- Remember that people are much more important than technical decisions. Working effectively on legacy code starts with the culture of your team.
Good luck, and happy legacy coding!