Don't Rely on Technical Rewrites to Pay Back Your Technical Debt
In the fast-paced world of software engineering, technical debt is an inevitable byproduct of tight deadlines and rapid innovation. While this metaphorical debt can be managed, it requires strategic foresight to prevent it from getting out of control. As once defined by Ward Cunningham’s, technical debt creates "interest" over time, manifesting as additional work that compounds if not addressed properly. Among the strategies to manage technical debt, refactoring and rewriting are the most common. But it's crucial to understand why relying on technical rewrites should not be a standard practice.
Understanding the impact of Refactoring and Rewriting
Refactoring is a process of improving the internal structure of an existing codebase without changing its external behavior. This method is integral to maintaining the health of the code and making it easier and cheaper to modify. Refactoring is a preferred strategy - especially in the agile world - as it entails making small, incremental improvements that do not disrupt the functionality of the software, thus posing lower risks.
Conversely, rewriting involves replacing a significant portion of the system with new code. This approach can seem like a quick fix but comes with high risks and costs. Rewrites are generally considered when a system is fundamentally flawed, the technology stack becomes obsolete, or the existing architecture can no longer support necessary enhancements. However, the risks associated with rewrites are substantial—they can consume considerable resources, lead to black hole projects, introduce new bugs, and potentially cause operational disruptions.
The Nature of Rewrite Decisions
Using rewrites for technical debt can be an explicit or implicit decision. While an explicit decision to use rewrites may not be the optimal strategy, it’s still a conscious one. An implicit decision, on the other hand, means that there is no strategy to manage technical debt and rewrites are used as a last resort.
The case against frequent Rewrites
To start with the conclusion: Rewrites should be the exception in managing technical debt, not the rule. The primary reasons are the high risk and significant investment they require.
The high risk stems from the 'known unknown,' because a large(r) scope is difficult or time-consuming to examine. And at the same time, a large scope is good for surprises (unknown unknown).
Higher investments require a long(er) commitment. Especially in dynamic environments (e.g. startup or scaleup) this is not always easy to guarantee and can lead to rewrites having to be aborted or ended hastily
Rewrites also demand extensive validation to ensure the new code replicates the old system's functionalities while supporting new requirements. They disrupt the normal flow of development, diverting resources from essential features or improvements that could propel a company's growth.
Moreover, the impacts on the soft side of a rewrite can be profound. They can lead to frustration and stress within software engineering teams, particularly if the commitment on the investment shrinks, the outcomes do not meet the expectations or fail to justify the resources invested.
Strategic debt management: Prioritizing Refactoring
To effectively manage technical debt, it is advisable to integrate refactoring into the regular development workflow continuously. Allocating time for refactoring during development cycles helps keep the codebase clean and minimizes the chances of it degrading to a point where a complete rewrite is necessary. (Using a pull principle like Scrum is beneficial as it makes it easier to ensure there is enough time.)
Rewrites, when deemed necessary, should be approached with caution. They should only be executed after thorough analysis and when it's clear that the benefits significantly outweigh the risks. Planning for rewrites should involve frequent reviews and incremental implementation, which helps isolate and manage risks better.
Long story short
Refactoring remains the safer and more efficient strategy for managing technical debt compared to rewriting. Frequent reliance on rewrites is a risky practice that can lead to increased costs, potential failures, and disruption. Therefore, software engineering teams should focus on maintaining and improving their code continuously through refactoring resorting to rewrites only when absolutely necessary.