Refactoring is important enough to be treated as a development activity in its own right and should not be shoe-horned in on the quiet along with other tasks
This post is partly an attempt to atone for my own sins (and apologise to @stevejalim), partly a public aide memoire to prevent me from doing it again.
In 20 years of software development, I've never seen a 'clean' codebase; I'm not sure they even exist, and like to think that if you cracked open Windows it would be full of "can't work out what's going on here, let it blow up and see if anyone complains" style comments. As a result of this, refactoring is a vital part of the development process. It's like cleaning up after yourself in the real world - and in the same way, it's much better done little and often than in a single gigantic spring-clean.
The problem, and the focus of this post, is when you are tempted to do it all the time, as part of your everyday work. Refactoring can, by its very nature, turn into a 'pulling-a-thread' activity, where changing the signature of a single method becomes rebuilding an entire application. The temptation to refactor can subsequently disrupt development if not handled with care. The result of this incidental refactoring is something like this:
- Pick up new feature from the backlog - estimate time one day
- Create new branch for said feature
- Write feature code, write tests
- See one tiny thing you don't like about previous code
- Start refactoring
…[one week later]…
- Finish rebuilding application
- Get sent to the 'cooler' by rest of team
By this point your feature branch, if merged, will kill everyone else in the team's productivity for three days whilst they attempt to work out why all their tests now fail.
One solution to this is to separate out discrete refactoring tasks / cards / backlog items [delete as appropriate]. Refactoring in this scenario should not result in any new features, or even bug fixes, but should be an activity in and of itself. That way, everyone knows what is expected, and the scope of the refactor can be contained.
An added advantage is that you can start to surface refactoring as work that needs to be done (rather than the dirty hidden secret that it is usually considered). As you build out features, and notice the odd 'bad code smell', create a new task to refactor, and stick on the backlog. Everyone can see it, and everyone will know where it's at.
And if you always have a few refactoring tasks in the pipeline you can be confident that you're doing something to prevent the Withnail washing-up situation.