From
http://www.purpletech.com/xp/bootstrap.txt See also
RefactoringTrumpsYagni
There are basically two ways to do a refactoring with fairly large scope. The first way I call "Nose Job" - in order to do a nose job, the plastic surgeon first breaks the nose, then reassembles all the broken bits into the new design. So the Nose Job Refactoring means, first change
all the method signature(s) to match the new design, then compile and see what breaks, and fix all the broken callers. If you're lucky, and the refactoring is straightforward enough, then once it compiles, all tests will pass and you're done.
(In this case, the Nose Job would change
all methods in Library that take a parameter "String email" to "User user", then walk through
all the calling code and clean up.)
Unfortunately, this only seems to work about half the time. The other half, even once you change all the callers, some
UnitTests fail. If you're lucky, you can easily fix these, but if not, you have to roll back
all your changes (sob) and do the more laborious, incremental, Martin Fowler Approved kind of refactoring: change one signature, fix all callers, pass all tests, check in, repeat.
The reason Nose Jobs are preferable is that you can get into a Flow state walking through a file and changing things to the new design everywhere. In the Incremental refactoring, you're often in a file changing one caller, and you see a line of code calling a different method the wrong way, and you just
itch to clean that up too, and you
know it would take just one second... But you have to control yourself, since you know that that one just might be the evil caller
where the semantics changed enough to cause a test to break.
(What do I mean by causing a test to break semantically? In one case, an XPath expression failed to find a match, and it wasn't a simple thing like accidentally forgetting to change out.print(user) to out.print(user.getEmail()) (leading to "expected:<
[email protected]> but was:<polonius.User@43772329>"), but a non-obvious bug.)
--
AlexChaffee
Fowler/Beck talk about the temptation to do this kind of thing in
RefactoringImprovingTheDesignOfExistingCode. I used to do it a lot myself. Now, whenever I find myself in a
NoseJobRefactoring, I kick myself. It still happens, sometimes. But less and less often. In general, I have found that the time I lose in splitting into lots of small refactorings is more than outweighed by the time I lose when nose jobs go wrong. Not a pretty sight. -- Anon
In the bad case,
NoseJobRefactoring becomes
RefactoringHell. -- Anon
JimShore has a similar analogy on his
HomePage, but with solving Rubik's cube instead of fixing noses. I rather like it, but I can't think of a suitable pair of names. --
MatthewAstley
I recently avoided the consequences of doing a
NoseJobRefactoring by using a good refactoring IDE, in my case
IntellijIdea for Java. The
ChangeMethodSignature feature saved me a lot of time. Not every language has refactoring tools, but if you're working in one that does (such as Java or
SmallTalk), I highly recommend using one. -- ??
CategoryRefactoring