On my never ending journey to becoming a software craftsman, I am once again faced with a fundamental question. To butcher knife or to scalpel?
One thing I don’t think I anticipated, though I probably should have, entering this field, was maintaining code that was written in the upwards of 10 years ago. I guess I always assumed I would be writing new code or at least working with the authors of existing code. This was woefully inaccurate.
I am often tasked with maintaining or adding to code that has been in existence for years and has been worked on by a list of other engineers. To make it more complex, coding standards and accepted department architectures have changed throughout the life of the existing code, so you end up with this soup of MVVM mixed with controls that do business logic from behind code.
There are many reasons that the code could need maintaining, software rot, low quality code, bugs, hacks etc. The main thing here is that there is a problem and you are the code janitor that they hired to fix it.
So is this it? Is this bleak existence the best that I can hope for? Am I destined to forever perpetuate the garbage practices of 20 different devs from the past? Of course not!
There is always room to grow and a chance to make things right. Similar to how many people think that since they haven’t yet started saving for retirement, why start now. I think many developers look at legacy code as a lost cause. When in reality every single time you touch the code you have the opportunity to make things a little better.
Preventative maintenance is a key. If you see something that is clearly garbage code, like a variable named R instead of Rentals, then fix it! Expand that name out. You just made your code that much easier to read and debug.
Another thing to keep in mind when updating existing code is eliminating duplication. This happens no matter where you are. If your company has ten different converters that change an epoch time to a DateTime then you have problems. Try and consolidate your duplicate code and you’ll be amazed how fast things start to clear up. Most importantly though, don’t write duplicate code to begin with!
So let’s assume you are working on some legacy code. You’re tasked with adding some new functionality to it and you have decided that you want to try and make things a little less…. Eye bleedy…. What is the first thing you do? Should you break out your butcher knife and start chopping away, or should you break out the scalpel and inject some love into this wretched thing?
If you’re working on a pet project, off of company time, then sure, by all means, chop the cancer out of your project. You will thank yourself in the long run. However, if you are on the clock this might be a little harder to answer. Not only are you spending the company’s money to fix something that’s already working (and earning money) but you’re also introducing new bugs into the system. The old code might be ugly, but if it’s in production then it’s been thoroughly tested by both your QA and the users. By writing new code you are almost guaranteed to be introducing new bugs into the product.
So then if we can’t chop it out, are we left with no solution? Just continue writing garbage? No, of course not. Break out your scalpel and get to work.
The trick to using a coding scalpel efficiently is leaving a small footprint on existing code. You want to abstract your new code into separate files that you control. There is two main reasons for this. First, by leaving a very tiny footprint on the existing code, then you know any bugs you introduce are limited to your code. It’s much easier for debugging. Second, you can use whatever coding practices you deem best.
Code abstraction is kind of a CIS 101 thing. If you’re working in this field you (hopefully) understand the reasoning and the power behind abstraction. It not only provides modularity but also makes your code infinitely easier to debug. Also I shouldn’t have to convince anyone that code reusability is key, especially in the business environment.
Finally, don’t forget to write your tests. If you’re not using Unit Tests then maybe this is the perfect opportunity to give it a go. Testing provides some peace of mind. It also allows leadership to verify correctness while avoiding regression tests. Think of every test that you write as one little investment seed you’ve planted into your codebase. As your code grows, so does the value of the tests you have written. They will keep you warm at night with the knowledge that your existing code wasn’t broken by new changes introduced.
Author: Anthony Russell
Professional .NET Developer