Continuous refactoring vs software rewrite
“This code base is a mess, how did we get here?” “This user interface has no consistency, it feels like every feature is its own app.”
These are common cases of code rot, or application rot, where the initial version was delivered and the developers never looked back. It’s a hard thing to combat, because even while you iterate you have to do it at the same pace as new features are being added, otherwise it’s a slow rot that creeps in without you immediately noticing.
small incremental software iterations
Most iterations are not work you plan and estimate as a thing of itself. Sometimes you do when it’s a major refactor with clear business benefits, but not always is the benefit as immediate. Continuous small code refactoring or other tweaks/improvements to the software product are the best strategy to combat code rot and maintain the quality of the software product. Their immediate impact is relatively low, but their long-term impact is the difference between a good and a bad software product. You want these small but continuous increments because they are easier to integrate, get feedback on and they don’t pile up until it suddenly halts development of new features.
But how do I get the time to do all these iterations you talk about?
When the feature backlog is breathing down your neck, it might seem challenging to perform the required iterations to maintain and improve quality.
The good news is that small iterations are not something that is planned in a software project. But how is this good news? It means that it is your responsibility as a software developer to continuously apply these refactoring cycles while implementing the features. This also means that when you estimate work for a feature, you take into account some time for necessary refactors. It’s not something you express explicitly during estimation sessions, it’s just part of the work required to implement the feature. So this process is completely under your control. Of course, be sensitive about the time you spent on these refactors, because this process can be almost endless. So try to find a good balance between delivering new features and improving quality.
large software iterations
Larger iterations, such as a major upgrade of the framework you’re using or overhauling the UI, are things that should get planned in the software project. These are iterations that typically take more then a day (or even weeks, months) to implement. Given reasonable product management and customers, these should be rather easy to argument as to why they should get planned since they provide a clear benefit in terms of security, performance, user experience, stability, …
When to start from scratch and do a full software rewrite
“This legacy user interface is a usability hell and only works on Windows, this is costing us money.” “This legacy component doesn’t integrate well with our current stack, it’s a constant struggle.” “We are writing everything ourselves, while this other software ecosystem has all these libraries available.” “We’ve really underestimated the issues with this approach, let’s revise now before we sink in more time”
While you certainly don’t want a full rewrite of your software product every year, there’s a time when the current version of your software system has reached its end-of-life. While it’s still an important part of your organization, it’s costing more and more to maintain it and add new features. Users of the software are also feeling the negative impact in their day-to-day work. This means it’s probably time for a full rewrite. In general, this also means a new technology stack to make optimal use of this fresh start.
There might also be a time where your team has started a new project on a certain software stack, but it isn’t working out as expected. Instead of spending even more time into this stack, it might be better to start from scratch and apply what you’ve learned from the first try. This can sometimes mean throwing out months of work, but it is to the benefit of the product, team and customers. Certainly in projects with a tight budget or delivery date it’s important to shift quickly.
Craftsman tip: bad code quality should almost never be a reason to perform a full rewrite. If the team’s code quality practices lead to this situation then a full rewrite will almost certainly lead to the same situation again. Instead, align the team around some common code quality practices and then try to combine small and large iterations on the code base to gradually improve the quality and keep releasing new versions and improvements to end-users.
And finally there’s the R&D environment, where multiple full iterations of a software component are quite normal. Starting with a proof-of-concept in a software stack we’re it’s easy to quickly show the idea (iteration 1). From there, either the same software stack is used to build out the complete component or a completely new software stack is used that is more aimed for production use (iteration 2). After this first full iteration, several shortcomings are noticed (e.g. performance, flexibility, …) and the team tries to solve those in the current stack, but notices that they are reaching the limit of the stack. So finally they decide to do a full rewrite (iteration 3) in a new stack based on the knowledge they’ve gained through iteration 2.
This is a normal process if you’re developing something that is completely new to the team and tries to push the limits.
Note that actually none of these rewrites actually start “from scratch”. They all build on the previous iteration by taking along lessons learned and applying them to the new iteration.
Iterations are a critical part of delivering successful medium to large software projects, but provide even more benefit for long-running projects after their first version was delivered. This is when you’ll be able to gather valuable feedback (from users, metrics, …) while the software is being used in production. Feedback which can be used to iterate and make the software even better, while applying your own iterations as well on code that begs to be improved.
The biggest enemy of these iterations are projects with a fixed scope, budget, delivery date and without the option of a follow-up budget. But those kinds of projects warrant a complete article (or book even) of itself.