I often find myself using a particular multiple-step refactoring pattern that I call 3-I (or III):
Isolate-Improve-Inline.
- Isolate: Pull a chunk of code away from a context (typically by Extract Local Variable, Extract Method, or Extract Class).
- Improve: Revise the isolated code or the context it came from.
- Inline: Put the isolated code back in the context.
Here’s an artificial example:
if (x+1 == a || x+1 == b) {
multi-line
messy
stuff
} ...
I can isolate the messy stuff with Extract Method:
// Original context:
if (x+1 == a || x+1 == b) {
doSomething();
} ...
// Extracted method:
doSomething() {
multi-line
messy
stuff
}
Now I can improve the extracted method:
doSomething() {
much cleaner stuff
}
and/or I can improve the original context:
let nextValue = x + 1
if (nextValue == a || nextValue == b) {
doSomething()
}
Finally, I can inline:
let nextValue = x + 1
if (nextValue == a || nextValue == b) {
much cleaner stuff
}
Being able to move code smoothly in and out lets me experiment safely. For example, I might extract a method, improve it a bit, then decide I’d be better off if I hadn’t extracted so much, and put it back to try again.
Tactical refactoring patterns string together a series of refactorings to safely accomplish a larger goal. Give this tactic a try, and keep your eyes open for other useful ones.
Want to learn other refactoring tactics? Check out Industrial Logic's Refactoring album!
Thanks to Joshua Kerievsky for feedback on an earlier draft.