What is legacy code? Best practices for working with legacy code.
November 13, 2018

What Is Legacy Code: 8 Tips For Working With Legacy Code

Coding Best Practices
Static Analysis

Dealing with older code and code you didn't write can be a chore. But, unless you’re starting a project from scratch, it's inevitable. And that means you need a better way to work with it.

That is why we have included guidance that explains what is legacy code, best practices for working with it, and how static code analysis can help with refactoring legacy code.

What Is Legacy Code?

Legacy code is source code inherited from someone else or inherited from an older version of the software. It can also be any code that you don’t understand and that’s difficult to change.

Why Is Legacy Code a Challenge?

The biggest challenge with working with older or unfamiliar code maybe your assumptions about it.

You may think the code is bad. Whoever wrote it didn’t know what they were doing. You could have done a better job.

But the truth is, there's usually is a reason why the code is how it is. And, if you didn’t write it, you might not know that reason.

That’s why care needs to be taken when making improvements to the codebase. You can’t just put a quick fix on one area. There might be some dependencies you’re unaware of.

And that’s why it’s important to know when to maintain or to change it.

8 Tips for Working With Legacy Code

You can’t improve the inherited code overnight. But, you can take gradual steps to improve it.

Whether you’re just getting started — or you’ve been working on it for a while — here are eight tips that you should follow.

1. Test the Code

One way to understand the code is to create characterization tests and unit tests. You can also run a static analyzer over your code to identify potential problems.

This will help you understand what the code actually does. And it will reveal any potentially problematic areas. Once you understand the code, you can make changes with greater confidence.

2. Review Documentation

Reviewing documentation of the original requirements will help you understand where the code came from.

Having that documentation handy will help you improve the code — without compromising the system. Without this information, you could accidentally make changes that introduce undesirable behavior.

3. Only Rewrite Code When It’s Necessary

Rewriting an inherited codebase can be tempting. But it’s usually a mistake.

It takes too much time and too many programmers to rewrite everything. And even if you do it, rewriting code can introduce new bugs. Or it can remove hidden functionality.

4. Try Refactoring Legacy Code Instead

It’s better to try refactoring legacy rather than rewrite it. And, it’s best to do it gradually.

Refactoring is the process of changing the structure of the code — without changing its functionality.

This cleans the code and makes it easier to understand. It also eliminates potential errors.

When refactoring legacy code, it’s best to:

  • Refactor code that has unit tests — so you know what you have.
  • Start with the deepest point of your code — it will be easiest to refactor.
  • Test after refactoring — to make sure you didn’t break anything.
  • Have a safety net — e.g., Continuous Integration — so you can revert to a previous build.

5. Make Changes in Different Review Cycles

Don’t make too many changes at once. It’s a bad idea to refactor in the same review cycle as functional changes.

Plus, this makes it easier for code reviews. Isolated changes are much more obvious to the reviewer than a sea of changes.

6. Collaborate With Other Developers

You may not know the codebase very well. But some of your fellow developers probably do. It’s much faster to ask questions from those who know the codebase best.

So, if it’s possible, collaborate with someone who knows it better than you do. A second set of eyes on the code may help you understand it better.

7. Keep New Code Clean

There’s a way to avoid making the code more problematic. And that’s by ensuring new code is clean. It ought to be written to adhere to best practices.

You can’t control the quality of the inherited code. But you can make sure that the code you add is clean.

8. Do Further Research

Working with an inherited codebase gets easier with time. A junior developer may not understand why a codebase hasn’t been refactored (and may be keen to refactor it). But a senior developer will know when to leave it alone.

Learning more about the codebase will help you improve it.

A good starting point is this article by Michael C. Feathers, which contains some good examples of how to make changes to the codebase.

Another good source is “Refactoring: Improving the Design of Existing Code” by Martin Fowler. This book offers many tips for effectively refactoring legacy code.

Tools for Working With Legacy Code

You’ll always need to work with inherited code — or work around it. After all, the code is there for a reason. It works. And its results may be good enough that you can let known issues go.

There are good reasons for making changes to code, too. You might be adding a feature, fixing a bug, or improving design.

In a perfect world, you’d continually rewrite that older or unfamiliar code until it’s fully debugged. But chances are, that won’t be practical.

So, what you need to do is figure out what you can change — and leave the rest alone.

Static Code Analysis and Legacy Code

One way to do this is by using a static code analysis tool. You can set a baseline and then run analysis on the new code to make sure it’s clean. And you can suppress results from your codebase.

Helix QAC, for example, makes this very easy to do.

Analyze Legacy Code

Helix QAC can check your codebase against rules, typically from a coding standard. You’ll get diagnostics of violations. And you can prioritize them by severity. This means you can focus your attention on fixing the most error-riddled pieces first.

Explore coding standards >>

Set Baselines

You can also set your codebase as a baseline. Maybe the code is fine as-is, and you want to leave it alone. Setting a baseline means that the codebase won’t be pulled into your diagnostics. Instead, you can focus on finding issues in new code — and ensuring that’s clean.

An example of a baseline for legacy code in Helix QAC.
Helix QAC makes it easy to set baselines.

 

Use Suppressions

You can also use suppressions to create exceptions for your codebase. So, you can essentially dismiss violations in it. You might set your suppressions on specific rules or violations within a particular category.

An example of a baseline with suppressions for legacy code in Helix QAC.
Helix QAC lets you suppress diagnostics found in legacy codebases.

 

Ensure Compliance

In some cases, you may be reusing source code from one project to another. But, some weren’t developed with coding standards. And if you need to achieve compliance (such as with MISRA), this can create problems. By using a Perforce static code analyzer — like Helix QAC for C/C++ or Klocwork for C, C++, C#, and Java — it’s easy to see where the errors in your code are.

Improve Code With static analysis