Agile FAQs
  About   Slides   Home  

 
Managed Chaos
Naresh Jain's Random Thoughts on Software Development and Adventure Sports
     
`
 
RSS Feed
Recent Thoughts
Tags
Recent Comments

Confronting the Fear of Legacy Code

When faced with Legacy Code, I’ve found 3 possible options to deal with them:

  • Leave it alone for now: Very rarely used, code seems to work fine.
  • Piecemeal Refactoring: When its difficult to understand what the code does and how it does what it does. Its time for safe, slow and cumbersome refactoring process.
  • Rewrite: When its clear what the code does, but it very difficult to understand how it does what it does, it time to rescue the code by rewriting it from scratch. This can be applied at various levels (whole code base, single module, class or method).

To Rewrite or to Refactor?

One can easily spend hours or days trying to refactor some code, when clearly (in retrospect) rewriting the code would be a better option. Sometimes you decide its better to rewrite the code and end up implementing something that does not work in all situations or we miss out something important. Unfortunately there is no clear guideline when I would choose to refactor code v/s rewrite the code. The key to me is, if I understand what the code does not necessarily how it does what it does, then its time to rewrite the code.

Rewriting code: Play it safe

The analogy I use is, rewriting code is like building bridges. You know that the bridge helps you get from point A to point B. It might be very complicated and risky to use the bridge any more. But that does not mean you’ll go and blow the bridge apart. Instead you would slowing start building a new bridge along side. When the new bridge is ready, you would divert a sample traffic on this bridge and see if it actually works. If it does, then you migrate all the traffic to the new bridge and blow the old bridge apart.

I use the very same technique when rewriting code. During the process, I might leave the code working but in a much more messier (worse) state. During CodeChef TechTalks in Bangalore, Sai told me that he refers to this as an “Expand and Contract” cycle. You are temporarily expanding your code base so that you can come back and clean it up.

When I’m rewriting code, I find black-box style automated tests very helpful. If you don’t have tests, it might be worth investing the time to write a few.

Where to begin Refactoring Code

  • Outside-In: Start from a higher-level and refactor (delve) into the crux
  • Inside-Out: Start refactoring the crux and work your way out

At times its difficult to identify the crux and I spend some time exploring (via refactoring) before I can choose an approach. Tests can be a great probe to understand the code.

When refactoring legacy code, I usually use the Scaffolding Technique to break the Catch 22 situation (To refactor we need tests, to write tests we need to refactor). Scaffolding tests don’t necessarily have to be UI tests, I’ve used Unit tests as scaffolding tests as well.The key thing is they are temporary and meant to help you get started.

Thanks to the folks @ the Legacy Code BoF @ CodeChef TechTalks in Bangalore who prompted me to write this blog.

  • wic

    I recently had the misfortune of having to deal with a huge amount (1 Mloc) of legacy c#-code. Mind you, the code was not older than a few years. I did some statistics on it and found that 90% of the code lines were duplicates, copy-pasted from other parts of the system. That is, only 10% were pure, pristine code, the rest was duplicates.

    Not only that but the code itself were a complete mess with no structure of any kind. Every method was ‘public static’ and even the same constants were defined in several places (with different values sometimes!). There were c#-files with close to 20 thousands lines and on top of that, several thousand stored procs with an average of say thousand lines each. Some folks even thought the code was auto generated when they saw it.

    Needless to say, the system was extremely fragile, buggy and incredible slow. In only two years, it had amassed some 3 thousand (known) bugs, although that was only the tip of the iceberg. It was a huge never ending minefield littered with barbed wires, failed attempts and skulking, raving mad programmers constantly blowing up in your face — and I’m not only talking about the mines here

    In short, I have seen the place where evil programmers end up after they die, and it is not pretty. It was the definition of big-ball-of-mud from hell.

    I argued with management about this and claimed that we should rewrite it, instead of trying to refactor those 90% in a never ending death march. No use, it fell on deaf ears. We tried working around it using wrappers, external programs and adapter api:s. But we eventually had to integrate with it, and we failed due to there not being any api what so ever. Not one point of interaction, but thousands.

    Needles to say, I finally left the place, but I would argue that there were *no* way to refactor that mess.

  • wic

    I recently had the misfortune of having to deal with a huge amount (1 Mloc) of legacy c#-code. Mind you, the code was not older than a few years. I did some statistics on it and found that 90% of the code lines were duplicates, copy-pasted from other parts of the system. That is, only 10% were pure, pristine code, the rest was duplicates.

    Not only that but the code itself were a complete mess with no structure of any kind. Every method was ‘public static’ and even the same constants were defined in several places (with different values sometimes!). There were c#-files with close to 20 thousands lines and on top of that, several thousand stored procs with an average of say thousand lines each. Some folks even thought the code was auto generated when they saw it.

    Needless to say, the system was extremely fragile, buggy and incredible slow. In only two years, it had amassed some 3 thousand (known) bugs, although that was only the tip of the iceberg. It was a huge never ending minefield littered with barbed wires, failed attempts and skulking, raving mad programmers constantly blowing up in your face — and I’m not only talking about the mines here

    In short, I have seen the place where evil programmers end up after they die, and it is not pretty. It was the definition of big-ball-of-mud from hell.

    I argued with management about this and claimed that we should rewrite it, instead of trying to refactor those 90% in a never ending death march. No use, it fell on deaf ears. We tried working around it using wrappers, external programs and adapter api:s. But we eventually had to integrate with it, and we failed due to there not being any api what so ever. Not one point of interaction, but thousands.

    Needles to say, I finally left the place, but I would argue that there were *no* way to refactor that mess.

  • Peter Booth

    With 1MLoc, of which only 100k is not duplicate, you obviously have a challenge. Some points:

    1. Mike Feather’s book is invaluable and should be next to your computer at all times.
    2. refactoring without tests works best if you have refactoring tools – both IDE style automated refactorings, and architects tool like Structure101 from Headway. If you follow a discipline of maker change, commit, make change, commit you at least have deltas showing what you did.
    3. Sound slike a nightmarish place that you are well out of.

  • Peter Booth

    With 1MLoc, of which only 100k is not duplicate, you obviously have a challenge. Some points:

    1. Mike Feather’s book is invaluable and should be next to your computer at all times.
    2. refactoring without tests works best if you have refactoring tools – both IDE style automated refactorings, and architects tool like Structure101 from Headway. If you follow a discipline of maker change, commit, make change, commit you at least have deltas showing what you did.
    3. Sound slike a nightmarish place that you are well out of.

  • http://javadots.blogspot.com/2009/08/why-aircraft-carriers-are-not-agile.html Itay Maman

    Refactoring legacy code often feel like untying a knot. At the beginning it looks like one big mess and you don’t know where to begin. Then you find one loose end and you start untying from there.

    With legacy code I often look for one small piece which I can refactor. It can be top-level class, a low-level function, whatever. I refactor it and now things look a little bit clearer. I can now refactor something else. Pretty soon a coherent shape starts to emerge.

    (Of course, in 99% of the cases you need a test suite to keep you from making damage)

  • http://javadots.blogspot.com/2009/08/why-aircraft-carriers-are-not-agile.html Itay Maman

    Refactoring legacy code often feel like untying a knot. At the beginning it looks like one big mess and you don’t know where to begin. Then you find one loose end and you start untying from there.

    With legacy code I often look for one small piece which I can refactor. It can be top-level class, a low-level function, whatever. I refactor it and now things look a little bit clearer. I can now refactor something else. Pretty soon a coherent shape starts to emerge.

    (Of course, in 99% of the cases you need a test suite to keep you from making damage)


    Licensed under
Creative Commons License