Legacy. The one word engineers cringe when they hear. Nobody wants to work with legacy code or legacy systems. And yet someone has to. Can we do something about it?
The evolution of software
Let’s look at the evolution of software. It all starts with an idea. After some market research and market fit, a small team is formed to develop an MVP. The MVP then gets a few real users, which sets the ball rolling for team expansion and accelerated feature development. And as new features are being shipped, old features are becoming what we call legacy, and the backlog in Jira is getting filled with Tech Debts that are never prioritized because We must develop this feature ASAP!.
Eventually, the code becomes very hard to maintain. Most of the original authors already left the company and new engineers with enthusiasm to make the code a better place are met with criticism such as
- This code is the core of the system, and any change there needs to be carefully reviewed by Amy’s team. But her team does not have time for it in this quarter.
- Nobody really knows what’s going on there. Dany was the last to work on it, but he now left for UniCo(rn) which raised gazillion dollars.
- Yeah, we can do that, but maybe in the next quarter. We really need you to work on Feature X for ThisBigClient.
- I’m in! Let’s create a ticket in Jira Backlog and prioritize it in our next grooming!
And hence, their passion and enthusiasm slowly dies, until one day they become the ones who say the above phrases.
Legacy is the place where companies go to die.
If you fear legacy — you are doomed to fail
Code is just a means to produce products. The harsh truth is that your code quality doesn’t really matter, as long is it produces the product that your customers are happy to pay for. And in a very competitive world we live right now, you don’t really have time to produce maintainable code. New startups don’t have time or resources to focus on code quality — they need to provide POC as fast as possible to acquire that one customer. Established companies already have customers who give zero concerns about your legacy code, and are mainly interested in features.
However, we are not in the 15th century, where you work as blacksmith your entire life, and the cost and time you will spend investing into your workshop will eventually pay for itself. In the modern world, people are not their companies. It’s very common for engineers to change jobs every 3 to 5 years. And investing in a “better code” will not benefit future you, because future you will work in a different company in few years. Same goes for your manager, his manager and your product manager. Even the most veteran people, who work for 10 or 15 years at the same place, will usually occupy a completely different position by the time you approach them to ask for help about the legacy they’ve written 9 years ago.
Because good companies will usually outlive their entire employees, legacy creates a big problem for them. If you want your company to be good, you must have 2 magic components:
- Ability for new employees to support and maintain your codebase without hunting for knowledge from veteran employees or those who already left
- Ability to innovate
FooBaz Automobiles Inc.
I like to provide analogies from other industries, and I’m somewhat enthusiastic about cars, so here is one. Let’s say you start a car company and you rush your small engineering team to develop an efficient engine. Once your engine has been developed and you’ve provided a first prototype of your car, you begin to work on customer requests: better seats, nicer dashboard, more safety features etc. However as time passes, your engine starts to show its age.
Your new enthusiastic employee proposes to redesign the engine, but he is met with criticism: the current engine fits in the chassis we are developing; the engine is a critical part of the car; very few people know how the engine works and it’s better not to touch it; we promised our customers a big screen with navigation etc. As time passes, Acme Automobiles Inc is founded, and your enthusiastic employees are moving there, so they can innovate on their engine design, which proves to be twice as cheap and efficient as yours. And so little by little your company is phased out from existence.
Legacy code is like a viral infection. If you leave it untreated, it will spread and infect your entire codebase.
Another side effect of legacy is what is known as “We can no longer develop new features in this codebase. It’s written in Ruby and it’s impossible to find any Ruby developers, so the Architects Council has come up with a decision to rewrite the software to Node.JS. We will call it V2“.
And while a rewrite sounds like a good idea from an engineering perspective, it’s a bad idea from a product perspective. There are many nuances you need to think about when doing v2.
- Are you going to hire an entirely new team to work on v2, or are you going to repurpose the existing team from v1 to v2?
- What is happening to v1? Are you deprecating it? Are you going to invest development time in it? What happens to customers of v1?
- How are you going to sell v2 to existing customers in v1? Nobody wants to move from a working product to a half-baked prototype with lacking feature parity.
V2s are great for engineers, especially those who are going to lead the development. You get to work with new technologies (usually), greenfield a product, the feature set is usually clear from the beginning (because you are essentially remaking an existing product, but in a maintainable way). In the end, after tears and blood, you get a new, somewhat maintainable, codebase with no legacy. But make no mistake, the life path of V2 will follow V1s - eventually it will become legacy. Because V2s are no more than a bandaid on the big “legacy infection” of your codebase.
Oh no! What can we do?!
Have no fear! Legacy fighter is here.
The truth is — you can’t avoid legacy. I don’t believe in problem prevention, especially in software engineering. Problem prevention is equal to magic crystal reading. But this is a topic for another post. Let’s for now agree that legacy is the byproduct of software development. And the same way as a mess in the kitchen is a byproduct of Shabbat dinner preparations — it needs to be taken care of as soon as possible, before it piles into something you can’t handle.
This means that you need to have tasks that are prioritized in your sprint (or whatever system you use) in which you can tackle regions of code that are prone to become legacy. You don’t just fill your backlog with “Improve X so that it will do Y“ tasks and never work on them. You need to dedicate time. Find a balance between features and tech debts. Every sprint should have, let’s say, 80% features development and 20% tech debts. This also needs to be understood by your (a) Engineering Manager and (b) Product Manager. It must be a rule. There should be no exceptions. No “but maybe in this sprint we can focus more on features since we really promised this client that it will happen”. It’s not your problem, as a software engineer, that your product manager makes promises he can’t fulfill. It’s his job to balance the management of the product. Your job is to balance development of the product. And part of the development is making sure that your code continues to live after you decide to go to a different company; it’s your job to make sure that new developers are not faced with oh no, this is a core functionality, we don’t touch that in our shire.
Apart from fixing legacy, you need to make sure legacy is identified. Legacy does not just appear out of nowhere. Legacy is a good code that was piled on with a bunch of quick fix for client and a patch to make it work in Explorer type of development. Every feature and bug fix is a potential to identify legacy. If something is hard to understand, hard to work with — you need to document it. You need to make sure it’s known as a problem to the team, engineering manager and product manager. They need to be aware of the fact that you’ve tried to implement X but encountered a code that you’ve had to debug with other developers, because this code is hard to understand. And once they are aware of it, you prioritize it and start to work on it.
It’s an endless cycle. And it’s a healthy cycle. It’s part of development. And there will be sprints when you have a lot of features and very few legacy code, and there will be sprints where you have a big refactor to do and hence, you freeze feature development.
Legacy is not a boogie man. You don’t need to be afraid of it. But if you let it grow, it will grow. And will eventually kill your product and maybe even your company.