When working with legacy code I usually start by classifying all modules of the system based on the urgency for rebuild. The classification helps making sure that no work is wasted improving details of code that will be discarded later.

I use four levels to classify the code:

Urgent Rebuild Frozen Maintain Non-legacy

The classification of different parts of the code is communicated to everyone on the team so that everyone knows the rules for the different parts of the system.



Urgent Rebuild

I use Urgent Rebuild with care, saving it for the most critical issues I find. The urgent rebuild category is usually saved for two types of problems. The first is security. A flawed authentication and authorization solution is a disaster waiting to happen. It has to be fixed. Now.

The second is core infrastructure. A logging utility that has an awkward API has to be fixed right away, before more code is made dependent on it.

Frozen

Any part of the system that works well for the user, but where the code is ugly, hairy and bites you in the ass is classified as frozen. From a user point of view it works, so don’t fix what ain’t broken.

On the other hand the ugly, hairy pile of mud that is the code driving the feature is not anything you want to touch. The solution is simple: Don’t touch the code, but defer rewriting until there is an actual need for updates from the users. When there is need to work on the code, it is ported over to a more modern technology and architecture.

When faced with reality, it is often hard to keep the code completely frozen. There might be a minor adjustment to a calculation, or to a text string somewhere that is simple to do and doesn’t justify a complete rewrite of the code. The team members have to discuss those edge cases, to make sure that the right decision on rewrite or changing frozen code is done.

Maintain

Code that is good enough to be kept, but doesn’t have the quality that you would expect of freshly written code is classified for maintenance. As long as there are no requests for changed functionality it is kept as it is. When there is a need to work on it, the technical debt in it should be reduced on the same time.

Non-legacy

The highest level that the code can reach is non legacy. Any new code written of course belongs in this category. Code that was once in maintenance but has been taken care of should be leveled up to non-legacy.

If the non legacy level is not clearly distinguishable from the other levels you might be lucky to have good code quality across the entire system (but then it’s not legacy any more). Unfortunately that is the rare case. Far more often there is such a pressed schedule that the new code written is as bad as the old one. Stay away from that. Make sure to keep focused on the different rules that are in effect for the different levels.

The frozen code is ugly and stinky, but that doesn’t justify that new code is written in the same way.