I have this problem. I can't stop myself from refactoring existing code that works but is, in my opinion (and perhaps objectively), badly designed or contains other "code smells". This can have a significant negative effect on my immediate productivity. But ultimately will be a big maintenance boon.
If you also suffer from this "affliction", how do you restrain yourself? Or at least manage the refactoring to avoid having to alter large chunks of existing code in order to make it maintainable for the long term.
I used to refactor code whenever I came across something I didn't like, but not anymore. I found from experience that it's just not worth it. There are better things you could spend your time on.
The main reason I don't refactor anymore is the risk of introducing a new bug. The worse the old code is, the higher the chance that you're going to make a mistake. For example, the old code might have an unintended side effect. That could be considered a coding error, and you'd remove it in your rewrite. However, code that calls into your rewritten function may be relying on that side effect.
I work on a lot of really ugly legacy code that's mostly uncommented and for which there are no specs. The code just does what it does, and no one can really say why. They just know it seems to work. As horrible as it is, this code does it's job, so it's best to just leave it alone.
That said, I do believe bad code should be rewritten. I just don't think that programmers should do this kind of thing on their own. It should be treated as a project, with defined scope, timelines, test plans, etc., just like implementation of a new feature.
I have suffered from this in the past, and I micromanage my 'bad' good habit.
Basically, I do the following:
In all honesty, that 'major' refactoring never really happens often -- usually if I need to do that, it's already been tasked anyhow. Still, the few times I've done that, it's come in handy. Ideal if you can do a branch for it, and just keep integrating changes.
For the smaller stuff, I'll often keep those changes local in my 'main' branch, and run with them locally for a while. The moment that anything I'm working on touches those files, I then check the whole change in -- our process currently includes a 'buddy check' system before check-ins, so usually it's stuff that'd clear peer review anyhow.
Anyways. Might be more of a brain dump than you cared for, but hopefully it helps.
I won't say I 'suffer' from this affliction but... I hear you brother!
I do think we need to leave the code in a better state than when we left it. So your pursuit is noble. Let's call it 'refactoritis'.
I'm assuming that we all agree on the benefits of refactoring and that it sort of depends on the code as to how necessary it is... To the crux of the question then...
One way I restrain myself, is that I try to feel safe in the knowledge that it's ripe for fixing. And I know how to fix it. And rather than completely restrain myself, I just do one step, like 'Extract Method'. And leave the next 'round' of fixing for later (perhaps we should call this 'second helpings' or 'dessert' if you're sure it's the last step). Then stick a big TODO on it, so you can find it again. And clarify what still needs to be done.
Thanks for the interesting question. It makes me wonder whether we need a 'Refactorors Anonymous' group where we can sit around in a circle and share our problems and war stories.
The following Boy Scout rule applies very good to (bad) code and design:
Leave the campground cleaner than you found it!
Before you start refactoring you need to have comprehensive unit tests for it, and nobody likes to write unit tests :)
Are you habitually refactoring code written by others, or code that you wrote six months ago while you were in a different kind of 'zone' ? If your answer is the latter, its very good that you don't paint or make sculptures for a living ... you'd be arrested for breaking into people's homes to 'finish' your works long after they were purchased.
I am a BIG fan of doxygen , which allows me to stick a simple:
Then, I tell doxygen to generate to-do lists based on my comments. This helps to ensure functions that smell like feet don't get forgotten.
I look back on stuff that I did even two months ago and say "Ick, what the heck was I thinking ... I should do it this way ... ", which results in never actually getting a consumable out the door.
If its other people's code that you consistently re-factor, try to ask yourself if doing so actually improves the code. If you are able to re-factor a function, its pretty obvious that you understand the function .. so unless you get some (more than trivial) benefit from re-writing it, slap a comment above it and come back later.
After you are used to all of the code and have given some thought to how to make things more coherent .. then dive in. Otherwise, you'll end up re-factoring your previous re-factoring (what a vicious cycle that took years to perfect!).
So, unless its inline, or used all over the place .. try to avoid messing with it unless you really need to. Later, come back and hit your TODO list in one swoop .. when doing so is your only immediate goal.