“I must not fear. Fear is the mind-killer. Fear is the little-death that brings total obliteration. I will face my fear. I will permit it to pass over me and through me. And when it has gone past I will turn the inner eye to see its path. Where the fear has gone there will be nothing. Only I will remain.”
― Frank Herbert, Dune
That iconic passage from Frank Herbert is something I think about when I encounter code that engineers are afraid to touch. When an engineering team is afraid to touch a piece of code then the software is no longer “soft.” Instead, current and future choices become constrained by decisions and mistakes of the past.
This fear will often lead teams to try to rewrite and replace the software rather than modify it. The results of this effort is almost always bad. Some of the problems you encounter during the Great Rewrite are:
- The legacy software is still running in production.
- It still gets bug fixes.
- It still gets new mission-critical features that have to be replicated in the new software.
- No one wants to cut over to the new software until it’s feature parable with the legacy software.
- Feature Parability is hindered by the inability to modify the old software.
- If the cutover happens before parability is achieved, I’ve seen people express that they’d rather go back to the old and busted system because at least it did what they needed it to.
- The planning and engineering techniques used to produce the first set of software–and the corresponding rigidity that led to the Great Rewrite–have not changed.
- The Great Rewrite will ultimately go through the same lifecycle and have to be rewritten again.
These problems multiply if the authors of The Great Rewrite are a different team than the one that maintains the existing system.
What’s the Alternative?
The alternative is to save your existing software. If you are afraid to change a piece of code, you need to take steps to remove that fear.
- Spend time with the code to understand it.
- Stand the system up in a test environment so that you can experiment with it to learn it’s edge-cases and wrinkles.
- Before making any change, cover the test environment with black-box automated tests that can verify behavior.
- If the tests cannot be fully automated (sadly the case with some old “Smart UI” style applications), then document the test cases and automate what you can.
- Analyze the error logs to make sure you understand the existing failures in the system as well as the rate at which they occur.
- Make the desired change to the system.
- At this point you will have to be careful. You will need to do a post-change analysis of the error logs to look for anomalous errors. The first log analysis is your baseline.
- Once you are confident in the change, cover it with as many automated tests as you can.
- Once you have great test coverage, aggressively refactor the code for clarity.
This process is time-consuming and expensive. For this teams people try to find shortcuts around it. Unfortunately, there are no shortcuts. The path of the Great Rewrite is even longer and more expensive. It just has better marketing.
But I Really Have to Rewrite!
There are times when a rewrite is unavoidable. Possible reasons might be:
- The technology that was used in the original software is no longer supported.
- It may also be old enough that it’s difficult to find people willing or able to support it–which amounts to the same thing.
- The component is small enough that a rewrite is virtually no risk.
- The component cannot be ported to the new infrastructure it is intended to run on (e.g., cloud, mobile, docker, etc).
In these cases, the process is the same as above–stand up a test environment. Wrap the old system in automated black-box acceptance tests. Limit yourself to targeting parity (no new features!) until the replacement is done.