The Ten Commandments of Maintaining Legacy Code
Maintaining legacy code is a major part of software engineering. Learn how to do it well.
Hey all! Happy Friday! I hope everyone is having a lovely day / week.
Maintaining legacy code has a bad rep. People groan about the crappy code they have to maintain. The spaghetti of methods and APIs. They dream of the day when they can work on a modern and fresh system.
I spent most of my career working on legacy code. You will too. I'll explain why that is, and what can be done about it. Since I mistakenly wrote the article in the form of a list (I really do find lists easier to read), I decided to be more creative with the phrasing. They're now commandments. How fun is that.
Commandment One: Thou shalt not complain about the code.
Like evolution, code lives through a process of selection.
When a product doesn't meet customer needs, the code goes away.
When the code doesn't scale / perform effectively / costs too much, the code goes away.
In only one situation does code get old. When a product is successful, and the code is good enough to achieve that value.
This means that instead of legacy code being a sign of failure, it's a sign of success. It means that this combination of product and code delivers enough value to warrant the code aging.
"We just took over this system. It's terrible! A technical debt nightmare."
Many engineers speak about legacy code in derogatory ways. They frequently suggest that the system is ugly due to the previous engineers being lazy, or not allocating enough time for maintenance.
Your co-workers are humans, almost always with good intentions. When you assume that they were lazy (instead of busy, overworked, tired, junior), you insult them.
Systems are a reflection of the humans who spent time building them, and insulting a system indirectly insults a set of your co-workers. When I was running teams, I regularly reminded people that we don't know the steps which created our current situation.
You can and should factually recognize issues with your system that you need to address. "This method does not follow the API structure that other methods follow." However, you should firmly avoid (and push back against) judgements about the system, "Was this API written by an idiot?!" Not ok.
Be a good co-worker, and respect what came before.
Commandment Two: Thou shalt not permit tight schedules to ruin your system.
Your team is on a tight schedule. I mean, join the crowd. When aren't people on a tight schedule? For various reasons, you feel pressure to get something done cheaply.
Mini-thread: How do you push back on unrealistic deadlines and false urgency? or balance having a life with busting your ass on an ambitious project? or argue for quality over shot-cuts? You have to time travel ...
— Colm MacCárthaigh (@colmmacc) August 27, 2018
Perhaps it's a business emergency to get a feature out quickly. Perhaps you'll get a huge bonus if it's launched on time. Perhaps your team estimated the work poorly. Perhaps they didn't estimate the work poorly, but the scope increased.
In 99% of cases, you can't let these tight schedules dictate the quality of your system. In particular, you can't let them dictate that your system will be harder to maintain and harder to update in the future.
"In the current system, that change would take 6 weeks. But if we just hacked it up, we could probably do it in 2 weeks."
No. That's never an option. Don't provide that option.
You can skip features. You can launch later. You can pull in more engineers. However, making your job harder in the future shouldn't be an option.
What about those 1% cases of an emergency feature you urgently require because otherwise you'll be sued out of business? You immediately schedule "fix this garbage ASAP" on your team's schedule for next sprint, and absolutely don't allow anything to move it.
Commandment Three: Thou shalt not put orphan features in your system.
Every system was designed to accept certain types of new features. You build a project management system, and it's relatively easy to add a "QA finished date" next to the "Design due date" because it's a minor change, fitting the existing model of the system. Easy.
But what happens when company leadership decides (let's say for legitimate reasons) that they need to give external customers visibility to some project statuses?
Uh oh. That wasn't anticipated. In fact, your project management system has a basic assumption that only internal employees would ever access it.
This is not a simple change. For example, the "modified by" field scattered through the entire system is an employee ID.
You decide to hack the change into your existing system. This is a common choice for teams, when they're unable to push back on the product requirement.
They'll modify the system in the least destructive way possible to get their existing task management system to be able to share with external customers. Perhaps they'll create an "external customer employee ID", which will make the system believe that someone external is an employee. As a side note, this type of hacking is one of the common ways people mistakenly create security holes in their systems.
Why would people choose this "shove it in" option?
When you have a hammer, everything looks like a nail. If your team maintains the project management system, you're heavily tempted to use it to accomplish the task.
Horrible explanation, but sometimes leaders hack product features into their system (which don't fit) to justify why they should continue owning it. In this case, the manager of the project management system might be excited to own some requirements for external customers. Even if it makes no sense.