If you ask ten different people what legacy code means, you’ll get ten different answers. Let’s start by looking at what legacy code is not:
- It’s not code from the system you had before SAP—the legacy system. You don’t use that code anymore, so that code cannot possibly be what we’re talking about here.
- It’s not procedural code. It turns out any sort of code can be legacy code—you could have object-oriented code that is legacy code and procedural code that is not.
The actual definition of legacy code, at least as used by authors like Paul Hardy among others, is very simple indeed—it is code without automated unit tests. This definition comes from American IT author Michael Feathers (more on him later). Eli Lopian, CEO of Typemock, has a different definition of legacy code as “code that developers are afraid to change.” There is no disparity between the two definitions at all, for reasons that will become clear very shortly.
Now, take a look at the Z code (also known as custom code) in your SAP system. Are there any automated unit tests at all? For most people, the answer will be a resounding “No!” and thus another definition could be “legacy code is all the custom code in my SAP system, including the code I wrote yesterday.”
Now that you know what legacy code is, and that most (if not all) of your code is legacy code, why is this a bad thing?
In his book, Working Effectively with Legacy Code, Michael Feathers has two things to say on the matter:
Code without tests is bad code. It doesn’t matter how well-written it is; it doesn’t matter how pretty or object-oriented or well-encapsulated it is. With tests, we can change the behavior of our code quickly and verifiably. Without them, we really don’t know if our code is getting better or worse.
Most of the fear involved in making changes to large code bases is fear of introducing subtle bugs; fear of changing things inadvertently. With tests, you can make things better with impunity. To me, the difference is so critical, it overwhelms any other distinction.
The normal situation with a huge legacy code program is that you’re terrified to make a change because you know in your heart that, when you make a new change, something else will break, and you don’t know what. Generally, 99% of development work is changing existing programs, and the biggest problem with changing existing programs is breaking something totally unrelated to the change. If a program does 500 things, and you make it do 501 things, how do you know which of the existing 500 things you might have broken as a result? Testing all 500 things manually is something no one wants to do, and so the testing doesn’t happen at all.
In the same vein, you hesitate to clean up old code because you’re too scared it will break something. As an example of cleaning up, let’s say you run an extended syntax check, which tells you that an entire routine is never called statically. You look at that routine, and even if you study the code for hours, you still have no idea what it does. What you should do is delete it, but you’re too scared. What if it is called dynamically? What if it does something important? So, you end up letting it be, and that means no code ever gets removed from a big program, even when the need for a particular routine went away 10 years ago. So, the program just gets bigger and bigger forever, with more and more code to remediate at upgrade time.
To make matters worse, the sort of huge monolithic applications written in legacy code tend to be business critical. The more business critical something is, the more requests for change it will have had over the years. So, the bigger and more complex the program has become, and after 20 years, it is a nightmare beyond the comprehension of any human being.
Your job is to make the latest change. Since no automated tests exist, you must adopt what Michael Feathers calls the edit and pray approach. You make your change; you can be fairly sure that your latest change works, but no one in the universe knows what you may have broken in the process.
The testers say that everything works, but have they only tested the latest change? Even if they say they’ve done some regression testing also, have they really? Even if they did, was it enough?
Your latest change goes into production at 3 a.m. Monday morning, a change to a program your organization literally cannot survive without. If that program stops working for 10 minutes, it is a disaster. If it doesn’t work for the entire day, you’re going to be looking for another job.
So, you go to bed on Sunday night before the change goes live the next morning, and you’re lying awake all night in a cold sweat, praying that everything works OK. And this happens every week forever. Your life doesn’t have to be like this. And yet, this problem is so widespread a proven methodology exists for fixing it.
To learn more about this methodology, check out Paul Hardy’s E-Bite listed below.
Editor’s note: This post has been adapted from a section of the e-book Refactoring Legacy ABAP Code by Paul Hardy.