Every project I've worked on has been underscored by a sense of urgency and a high degree of pressure to deliver value quickly.
Frankly, I don't think I would enjoy my work very much if that were not the case. The feeling of "we're doing something amazing, it must be delivered YESTERDAY" is invigorating!
That being said, difficult experience has instilled in me the importance of balancing a healthy pressure to deliver new features now with bigger picture thinking. Things can get out of control quickly in a “get it done now” atmosphere, and it is common in such cases to skip the review and refinement part of the test driven development process, or worse, skip testing altogether.
This becomes expensive, fast. When developers stop running tests, start making mistakes, and clutter the system with untested or substandard solutions, problems happen. Everyone switches to critical bug fixing mode and stops delivering new functionality, the overall pace of development slows, and even the bug fixes take more time because of the overly complex or confusing code that was written in haste. It’s a textbook case of lose, lose, lose.
Taking the larger context of a system into account and refactoring code accordingly, as a regular part of a software practice is one of the surest ways I know to ensure consistent delivery schedules, avoid costly errors, and keep the total cost of ownership for an application predictable.
Simply put, refactoring is a calculated investment in the quality of a system, which helps to ensure that your application and your team can respond quickly to changing requirements and continually add value to your software project.
For legacy systems, however, refactoring can pose a different set of challenges. Often there are no tests, bad tests, or lost requirements. In many cases, the original engineers who created the application are no longer accessible, so finding answers to questions about why a certain approach was chosen becomes much more difficult.
To that end, here is a high level overview of the process we use for refactoring legacy code, with which we have had consistent and repeated success:
It is important to remember that improving an existing system is more like a marathon than a hundred yard dash.
In my experience, teams who have had the greatest level of success in maintaining and building upon legacy systems are those who make refactoring a regular part of their daily process. They take measured, incremental steps toward improving the software they deliver, never losing site of the larger scale goals of the project and the value proposition that drives it.
There is far more to this topic than either time or space allow for here, so see the links to resources below.
Always feel free to reach out to me, or anyone on the Obtiva team, if you could benefit from the insight or advice of someone who has suffered the pitfalls of a legacy system, lived through it, and learned how to succeed in even the worst legacy codebases.
Resources: