Working with legacy code

Tamy Nagy
Nerdeller
Published in
4 min readJul 18, 2023

When you first hear the expression “legacy code”, you may think decades old of FORTRAN codebases that are still being maintained today. But the reality is, you don’t have to go that far to come across legacy code.

What is legacy code?

In simple terms, any code you have no knowledge about is legacy code. This makes it quite a subjective term, but here we are. Truth is, any code you are not familiar with can be hard to change, you can break things in the process, even alter functionalities by accident — as you have no deep understanding of the codebase, requirements and features.

The codebase my team is working on is quite robust and complex. Our tech stack is Java and Angular, so we are not using any outdated languages, and we are working hard on maintaining it to the highest standards. It is quite a beauty if you ask me. But if I were to drop it in front of you with a feature request, it would probably take days for you to be able to pinpoint where to even start — and you would probably end up making a mess anyway.

That is legacy code.

How to work with legacy code?

Every time you onboard to an ongoing project, you are working with legacy code. It is not something to be scared of, but rather something to be aware of. Even the most thorough onboarding process will not teach you the deep understanding you need for that codebase to not be a legacy code anymore.

With complex systems, the onboarding can take up to 6 months before you can confidently navigate around, and even then, some parts — mostly the stable parts that are never or rarely changed — will still be a black box for you.

It does not mean you should not touch anything for the time being. But it does mean you need to work twice as hard and be extra careful of your every step. As a rule, you should never go rouge on changes, refactors, or anything for that matter — but when working with legacy code, you really need to minimize your impact.

1. Communicate

So you got your first task assigned to you, and you may even think you know where to start? That’s great — but before you do anything more than creating a new branch, talk to your senior, tech lead, other technical supervisor. Make sure you identified the task at hand and the packages, classes, modules involved in the code correctly.

2. Write tests

Check out your new branch, and run all the existing tests. You want to see the status of all tests, make notes of failing tests in other parts of the code before you even did anything.

Next, see if there are any tests for the related sections, and if there are, check if they pass. If there are failing tests, fix them or ask help fixing them. If there are no tests, you are in for a fun ride: you will have to write them. That is your very first step, before making any change in the code.

If your task is to fix a bug, at this step write at least one — preferably multiple — test that reproduces the bug.

3. Make your changes

Once you set up your safety net of tests, you can start working on your task. From here on out, the development is no different than working on non-legacy code. Make your changes, make sure the tests still pass. Don’t forget to cover all your changes with tests as well.

If you did it right, your tests will keep you safe even in the most confusing or messy legacy environments.

4. Refactor

Yes, you read that right. Refactoring is a great way to get familiar with a legacy code, and it is quite safe if you do it right. In this case by refactoring I mean very small improvements:

  • Are there any functions that are way too big? Try and make them smaller.
  • Are there any variables that has weird, misleading, not-so-obvious names? Rename them.
  • Are there any magic strings? Create constants.

You do not have to go big here — a tiny bit of improvement can go a long way. Just make sure your tests still pass when you are done.

5. Run all the tests

Once you are finished and all the related tests in the targeted section pass, run all the tests again. You need to be sure that all the tests that passed before you started working still pass.

Note: in a well maintained, healthy codebase there should be little to no chance that your changes in one section would break anything in an unrelated section — but do not assume anything, play on the safe side, especially when working with legacy code!

And that is it, you are done!

Congratulations! That scary piece of legacy code is not so scary and not legacy any more!

--

--