(re-posting from private forum thread)
My response to this question was a bit of a gross generalization, and made several assumptions about the questioner; I hope I didn’t misinterpret what they were getting at. I *think* I got it right:
Because it’s not “rewriting things better”.
It’s “changing the implementation of things without changing the observable effects of the overall system, even if the system is BROKEN at the moment”.
By cutting out a much smaller problem than “rewriting things better”, you get a more powerful suite of techniques: there are complete processes which just don’t work if you allow yourself to spend time improving the code at the points where, instead, you are meant to merely “refactor”.
Damn useful technique – although I found it hard at first to get over the idea of leaving broken features broken: I felt guilty doing it. But it works, and eventually the guilt goes away, as you see that it really is the right thing to do (…in the appropriate situations, of course, and as part of the right process(es)…)
In the forum thread, I didn’t go into the details – you can google a lot of uses for refactoring.
There’s one great example I ALMOST wrote about last year, but didn’t get around to (I didn’t realise until now that I’d never posted it…Doh!): using refactoring with unit testing to convert an old code base to a new code base, but doing it with many many passes.
Brief summary of the parts that would be relevant here:
- Traditionally, with a horrendous mess of a codebase that needs converting, you’d either suck it down and spend many months (maybe many man-years) “converting” it – or else give up and rewrite it from scratch, one part at a time
- With Refactoring, you can rewrite it from scratch INSIDE the existing codebase, LESS than one part at a time, so that you get to use all the new code you’re creating immediately (instead of waiting for the complete system to be rebuilt-from-scratch)
- This works because Refactoring does NOT “fix” the code, it merely moves it around a bit, perhaps changes some minor subparts of it, often parts that have no effect on the overall system
- “no effect” means NO effect: no performance improvement, no change to the end-users
- …which allows you to use a particular Refactoring task in your schedule to merely “make the code slightly more amenable to be improved in the future; make it a bit less messy”
Yes, this shows no overall improvement in the system after each Refactoring pass – but you make those passes so EASY and so QUICK to do that one individual programmer can do literally HUNDREDS of them in a few weeks.
Traditionally, even doing just one “rewrite this small part of the system better” task would take months to even get started, because each time you think you’ve “fixed” it, you uncover another broken part, somewhere else in the system, somewhere that SHOULD be unrelated but sadly isn’t, that prevents your fix from working.
With refactoring you just shrug, smile, ignore it, and get on with making small incremental improvements every day, and go home happy in the knowledge you’ve at least achieved SOMETHING today, even if no-one else will see the result of it until you’ve achieved many more days of little somethings. But then they’ll be amazed, because in the limit – as the complexity of the codebase / number of refactorings tends towards large numbers – the sum total of small steps of refactoring quickly becomes net improvements to the code base that were literally IMPOSSIBLE with traditional software engineering: they would have taken so many man years, you’d never have finished them in the liftetime of the product you’re working on.
So. Just one example there, of how refactoring is a useful – and unique – tool, quite separate from “rewriting things better”.