I was recently talking to someone who had an old codebase that they just couldn’t work with anymore. So they rewrote it from scratch and within six months, the new code was just as bad as the old. They were no further ahead, despite having invested a significant amount of time and money. This is a common story and it doesn’t have to be this way.
When we write an application, we’re writing for two audiences at the same time. We’re writing code for the compiler and we’re also writing code for the future people who are going to maintain it. Each of these audiences needs different things from us.
The compiler needs the code to be precise. To describe what the computer should do in precise detail. The future people maintaining the code, need it to be easily readable and easily changeable. These two are very different1.
Experienced programmers tend to write code that satisfies both these audiences. The code will be correct and precise and also easily readable and maintainable. More junior programmers2 will write code that is great for the compiler but not for the other people who will have to maintain it.
So what is happening in the situation described above? We have an old codebase that’s been written in a way that is great for the compiler but that can’t be easily maintained. As we try to make changes to the code base, we go slower and slower and it becomes harder and more expensive to make any changes. So at some point we declare technical bankruptcy3 and we rewrite it. The problem though is that we haven’t taken the time to learn how to write maintainable code so when we write the brand new “green field” code, we make all the same mistakes that we’d made the first time, and in no time at all, we have a mess of unmaintainable code again.
How could we have done this differently?
A better approach would have been to deliberately improve the old codebase. Take the time to slowly refactor and redesign what we already had to make it more readable and maintainable. This takes time and can be painful in the short term but it ensures that we are learning how to write better code. These are lessons that will help us with everything we do in the future. Now, if we ever have to write a new codebase, we’ll be able to write maintainable code right from the beginning.
I’ve seen codebases thrown away less than two years after we started working on them because we let them rot so badly. I’ve also seen 10+ year old codebases that are amazingly clean and maintainable. The difference is the attention to maintainability. Do we pay deliberate attention to how easy it is to work with the code or do we just slap something together that works but that we can’t maintain?
Take the time to learn the skills - to be able to write code that other people can read and understand. The payoff is huge.
Does this mean that we should never rebuild from scratch? There are occasionally situations where there are business reasons for rebuilding. I know several companies where their life-blood applications were written for a platform that was no longer supported or where the vendor wanted to charge exorbitant amounts of money to keep using the platform. In these cases, a rewrite can make good business sense.
Even in these cases though, we want to have built the skills for maintainable code so that when we do write the new codebase, we’re writing clean, maintainable code that will set us up for future success.
Technical or Architectural Debt is the term we give to this code that satisfies the compiler (it works) but not the other programmers (it’s hard to read and slows us down). See also the difference between technical and architectural debt ↩
In fairness to junior programmers, formal education seems to be severely lacking with respect to writing maintainable code. They are taught to make the code correct and making it maintainable is an afterthought. It’s no wonder that students enter the workforce without the skills. ↩
Technical bankruptcy is when we’ve allowed the technical debt to accumulate so much that we give up and throw it all away. ↩