You’ve got to meet your deadlines, you’ve got to fix the bug, you’ve got to ship the product.
But you’ve also got to think about the future: every bug you introduce now will have to be fixed later, using up even more time. And all those deprecated APIs, out-of-date dependencies, and old ways of doing things really shouldn’t be there.
So when do you clean up your code?
Do you do it now?
In this article I’ll go over a set of heuristics that will help you decide when to apply three kinds of fixes:
- Updating dependencies that are out-of-date and usages of deprecated APIs.
- Refactoring to fix bad abstractions.
- Miscellaneous Cleanups of anything else, from coding standard violations to awkward idioms.
Before you start building something in earnest, you might start with a prototype (or what Extreme Programming calls a “spike”). You’re not going to keep this code, you’re just exploring the problem and solution space to see what you can learn.
Given you’re going to throw away this code, there’s not much point in Updating or Miscellaneous Cleanups. And if you’re just trying to understand an existing API or technical issue, you won’t be doing much Refactoring wither.
On the other hand, if your goal with prototyping is to find the right abstraction, you will be doing lots of Refactoring.
- Updating: never.
- Refactoring: now if you’re trying to prototype an API or abstraction, otherwise never.
- Miscellaneous Cleanups: never.
When you’re starting a completely new project, the decisions you make will have a strong impact on the maintenance code going forward.
This is a great opportunity to start with the latest (working) dependencies, situation-specific best practices and maintainable code, and the best abstractions you can come up with. You probably won’t get them completely right, but it’s usually worth spending the time to try to get it as close as possible.
- Updating: now.
- Refactoring: now.
- Miscellaneous Cleanups: now.
You need to get a bug fix to users ASAP. While you might see problems along the way, but unless they’re relevant to this particular bug fix, it’s best to put them off until later.
Sometimes that might mean fixing the bug twice: once in a quick hacky way, and a second time after you’ve done the necessary cleanups.
- Updating: later.
- Refactoring: later.
- Miscellaneous Cleanups: later.
When you have a project in active development and you’re doing ongoing work, whether features or bug fixes, you have a great opportunity to incrementally clean up your code.
You don’t need to fix everything every time you touch the code. Instead, an ongoing cleanup of code you’re already touching will cumulatively keep your codebase in good shape. See Ron Jefferies’ excellent article for details.
- Updating: now, for code you’re touching.
- Refactoring: now, for code you’re touching.
- Miscellaneous Cleanups: now, for code you’re touching.
Eventually your project will be finished: not much new development is done, and mostly it just gets slightly tweaked every few months when something breaks or a drop-down menu needs an extra option.
Your goal at this point is to do the minimum work necessary to keep the project going. Refactoring and Miscellaneous Cleanups aren’t necessary, but Updates might be—dependencies can stop working, or need security updates. And jumping your dependencies 5 years ahead is often much harder than incrementally doing 5 dependency updates at yearly intervals.
So whenever you have to do fix a bug, you should update the dependencies—ideally to Long Term Support releases to reduce the need for API usage updates.
- Updating: now, ideally to Long Term Support releases.
- Refactoring: never.
- Miscellaneous Cleanups: never.
Software projects tend to ongoing processes, not one-off efforts. A cleanup now might save you time later—but if you have a deadline to meet now, it might be better to put it off even at the cost of slightly more work later on.
So takes this article only a starting point: as with any heuristic, there will be exceptions to the rule, and you need to be guided by your situation and your goals.