The Right Attitude to Deal with Legacy Code
If you’re like the majority of software developers working for a company, you probably have to deal with legacy code sometimes. Well, maybe you don’t because you’re working on a brand new project with few people. But chances are you do.
I have faced legacy code many times, and it comes in various flavors. I also know quite a few people who have had to deal with it. Over the years, I’ve had the time to experience how it feels to work with legacy code, and I have watched developers express their feelings about it. As you’re probably aware, no one is very happy when they have to deal with unclear or otherwise questionable old code.
It seems to me that there are several ways of approaching legacy code.
In future posts on Fluent C++, I will discuss the various practical approaches as well as the technical aspects of dealing with legacy code. Together, we’ll explore how to handle legacy code, as it is sometimes both hard to understand and cruelly lacking in expressiveness.
But before this, it seems important to me to pause and reflect about what attitude and mindset is the most effective when facing legacy code, or any other non-expressive code, for that matter.
The Natural Reaction: Who the F*** Wrote This
When navigating legacy code we sometimes stumble upon things we don't understand. A first natural—primal—reaction is to decide that:
- This code is a pile of crap.
- The person who wrote it had no idea what he was doing.
- We would have done such a better job.
- I’m way better than this, so maybe I should find a place that deserves my skills.
Have you ever felt this way when staring at code you didn’t understand? I've seen many people react this way. I myself have felt this primal instinct, but early in my career as a developer I made the conscious decision to act differently. Because even if I believe that this reaction is absolutely normal, it is also undeniably primal. By primal, I mean the sort of primitive emotion that puts you in a state of irrationality, wherein you respond to difficulty with rage and fight or flight response. Primal is good for surviving in the wild, but, as a branch off the human race, we software developers ought to abandon this attitude and put on our rational hats.
Being rational is what we are paid to do, after all.
Note that I'm not saying that the impulse to react is always wrong. Maybe a particular piece of code is crap, written by someone who wasn't qualified, and you should be somewhere else (although believing that somewhere else is a better place to code may be an illusion).
What I want to do is show you another way to look at this situation, which I hope will make you view it differently, rationally, and hopefully positively most of the time. This certainly has helped me become more efficient and more content in my day-to-day coding.
The Rational Approach: Seeing Legacy Code for What It Really Is
I think it is important to recognize that legacy code is not the enemy.
In fact, in most cases, we're here thanks to legacy code. The early stages of a given project were where it started to grow, capture clients, build up financial interest, and establish a brand that inspired customers. All of this was done with code that may happen to still be around today and that still performs the functionalities that your customers liked you for in the first place. This is legacy code. As its name states, this is your legacy. Without it you would probably not even be getting paid today.
Now let’s be super rational, and put ourselves in the shoes of the person that wrote that code.
Legacy code is often relatively (sometimes very) old. Back in the time it was written, do you think its author knew as much as we do today? Did he know the best practices that we have slowly put together over the years as a development community, or the direction the language (C++11, 14, 17 for example) would take? When this code was written, did you know as much as you do today? Some pieces of code were written while some of us were still in college.
What’s even more humbling is thinking about how we would have solved the problem that a piece of legacy code was trying to solve. When you glance over it, you can see things that seem absurd, and you are tempted to nurture a feeling of superiority, by believing you would have done better if you had been given the chance.
Maybe you would have, but often when we actually try to solve a problem within all the technical or functional constraints that surround it, we realize that there are things that prevent us from doing a simple design, which we hadn’t seen initially. You never know until you actually try it.
If you’re still being rational, you realize the image of this dumb guy who wrote this ridiculous code often doesn't make sense. Legacy code becomes tangled and difficult to understand because of an accumulation of fixes, made by many people, who sometimes never knew each other.
The first version of the code may have made some sense, but perhaps it didn’t express its intention well. The following developer may have understood it a bit differently, adding a fix that wasn’t quite in line with what the code was designed for. Multiple emendations made by many people over many years make up legacy code.
Such code started out by not being expressive enough, and each additional fix made it lose more consistency. This is one of the reasons why I think expressiveness is such an important characteristic in determining the success of a codebase (head over to this post for more insight into writing expressive code).
Therefore, the code you see today that made you—primally—want to hit someone with a club over their head doesn’t have one culprit. To be really fair, you would have to go find many people, some of them off doing other projects, and gently tap each head with your club, over which you’ve placed a cushion. This way, you would spread your punishing blow out equitably. Alternatively, you could pick someone at random to bash, but there is no way that could be called fair.
Finally, let’s ask ourselves the dreadful following question: haven’t we written legacy or non-expressive code ourselves?
When you look at code you’ve written a while ago, do you always perfectly understand it and even find it pretty? I certainly don’t. When looking back over old code we’ve written, we probably don’t remember all the details about the problem the code was meant to solve or the context behind how we wrote it, which makes it that much harder to understand.
In contrast, whenever we write new code, we are very focused on the problem we’re solving, and we have all the elements of the context, functional or technical, in mind. However, as time goes by, we may forget these things for our newer codes as well. It’s something of a cycle unless we break it by writing better, more expressive code.
And by practicing writing more expressive code, and mastering aspects of the code’s language and design along the way, we get better. As one excellent C++ developer in my company once said: if you look at code you wrote six months ago and don’t find it could be improved, it means you haven’t learned anything in six months—and that is the worst you can get.
The Efficient Approach: Taking Responsibility
Now that I’ve shown you a way to see legacy code differently, what is the most efficient state of mind to have in approaching it?
First, don’t complain if you don’t intend to improve the code. Complaining for the sake of it is just making noise. And this noise is detrimental for you and for your co-workers because it creates negative vibes within yourself and in your office space. Moaning puts you in the position of a victim and not in a position of an actor. And this attitude is contagious, particularly towards the less experienced people on the team.
So when you’ve got new developers around you, or if you are the manager of green developers, you should choose to model a good attitude for them. It’s like watching your language around kids so that they dont get a bad vocabulary. And if you’re reading this article towards the beginning of your career in development, please, choose the right attitude NOW.
What’s the right attitude, then? I was lucky to learn it very early in my career from my fantastic manager, Patrice Dalesme. A few weeks after I came in, Patrice gave us the following piece of advice: consider that the code you’re working on is your code. Even if you haven’t written it yourself, and regardless of how good or bad you think it is, this is your code, and you have responsibility over it. (For the record, I thank Patrice for this, even though I can’t say it’s the only thing I will retain, as he gave me so many precious pieces of advice.)
This piece of advice really shifted my view on the codeline. It was no longer something some far-away group had written, which I could criticize to show how smart I was. It was my code, and I was determined to make the most out of it. I came out of that meeting motivated to do whatever was in my power to understand the code, improve it, and create business value out of it. Several years later, I’m still just as motivated to do so.
Even if you can’t change the past and how code was written, you have the absolute power to control your attitude. Whether it is in your efficiency as a developer or in your happiness as a person in day-to-day life, choosing the right attitude really makes a difference.