Tackling the Legacy Code

Boom! A big opportunity to shine just landed in your lap. It’s your big chance to show off those polished algorithmic and bug hunting skills that you’ve grown over the years by consuming liters and liters of caffeine. You’re a new member of an older team and in the first meeting, everyone agrees that the code from an earlier project will be used. Of course, you’ve never seen it, but ‘no biggy’, it’s only one Visual Studio solution… Oh right. That one solution has about 20 projects in it and only some of them are applications – the rest of them being libraries. You’re thinking, “Cool, the project was working before me, so changing it would probably be minimal, right…? Right…?” I think we can all hear the crickets in the background.

The article was written by Jelica Kapetina, the software engineer at HTEC Group

The power of documentation

First things first – you need to get familiar with the code. Nobody has time to sit next to you and explain every part of the code and what it does. So what is it that everyone in that situation desperately needs? No, it’s not Batman… The documentation, of course! Only when someone experiences involvement in a big ongoing project, can they appreciate the proper documentation. If you ever feel bored when writing all those technical designs and manuals, just have in mind that they save a lot of time when introducing someone new to the team. And not only that. Technical designs save a lot of implementation time, but that is an entirely different story now. What is important, is that you stick to the documentation and take good care of it. If you change something that was already working, update the documentation. If you add a new feature, update the documentation. If you make a release build for testing, update the documentation. Always update and write down everything that you do, or have plans to do in the future.

The legacy code style? Deal with it!

Like catching up to a huge pile of code isn’t enough, imagine the client saying how they want a different platform than the one that was used before. Someone will need to do all the porting in that case. Guess who’s being pointed at by a huge red neon arrow? Yes, you’ve guessed it. It’s going to be you. Congratulations! Prepare a pot of coffee, roll up the sleeves of your best shirt and let the porting begin! I bet you’re thinking that the port will be easy since all you’re doing is using #if/#def guards to change the behavior of the product based on the platform it is running on. That is perfectly fine, as long as the code being changed that way is platform-specific. But if you’re changing what features of the product are being enabled solely based on the platform, you are making a completely different product. The code should remain flexible, changing the flow only by configurable settings. That way you achieve platform independence and features are easily switchable between clients and their demands.

In that spirit, you try your best and separate different features by having if(client1)/else if(client2) statements, but there is a lot of ugly code, someone before you has written. Pointing fingers and running through the history of who checked in that line of code won’t do you any good. So let me break it to you – it’s your project now and you need to learn how to love it without any complaints. No matter how much you squint your eyes on it, no one is going to give you hours to change 10 000+ lines of code, just to have, well, a pretty code. Because really… Is it improving the product? If someone were to do a review of the code or add a feature, it would be difficult to follow one style and later on to jump onto a completely different style of coding. So if a function has every parameter in a different line, you should be writing it like that, too. Some consider it a downside of dealing with legacy code, but all you need to do is adapt your style to the existing one and you’ll be fine in no time.

Grab all your wits, clear your mind and start refactoring

Every one of us had situations that were difficult to manage and even seemed impossible to implement. When that schedule was breathing down our necks, we all implemented a quick and dirty solution at one point. Hey, it works, so don’t touch it anymore, right? Wrong. You try to add a new feature, but the existing code absolutely prevents you from doing it. What happens now? Can’t roll over and cry, because that won’t solve the problem. What you need to do is grab all your wits, clear your mind and start refactoring. First, you will design the approach, which would solve the blocking issue and also implement a more generic solution, so that you can add the planned and maybe upcoming features. Yes, it would take more time than what was your first estimate, but that is why there is a rule to give yourself some buffer time when estimating the tasks. You never know when stuff like this can come up. Let’s say you’re adding a feature in one part of the code and see a function there that can easily be made generic, but wasn’t. Take that extra time to refactor it, because it will be worthwhile and time-saving during the upcoming maintenance and bug fixing period. Don’t be afraid, because what is the worst thing that can happen? A bug? Let’s be honest, it won’t be the first and it won’t be the last one that you’ll solve. You’ve got this!

Show that code who’s the boss!

When you’re working with the legacy code, it feels like jumping into a pool of dark water, where you don’t see how deep the pool is or what junk is floating around. Maybe you’re one of the lucky ones, where the code has zero bugs and all the standards were followed up to the point. Or you could be one of those who inherit a project with zero documentation and full of ‘segmentation fault’ errors. I wish you to be among the first ones, but the reality is that you’ll be somewhere in the middle. So jump right in there and show that code who’s the boss. You are the programmer and you shape that code to fit your will. Be the coding Batman and hunt down those evil bugs. I wish you good luck!