In a comment on an earlier post Jon Eaves expressed concern that refactoring is being over-used as a verb. In particular, the line between refactoring and rearchitecting (or rewriting) was being blurred, and refactoring was being used as a label for any activity where you go back and do things right the second time. You know something? Jon’s right.
Refactoring, as defined by Martin Fowler, is a very specific term, based on a equally specific term from mathematics. Refactoring is about small, “behaviour preserving” incremental and safe steps. Refactoring is not an excuse to go back and “fill in the blanks” in your application.
Let’s give some concrete examples on what is not refactoring. None of the following would be considered refactoring activities:
- “Improving” (aka adding) error handling.
- Adding logging
- Cramming in yet another feature
- Enhancing the test coverage (though this one comes close)
- Playing minesweeper while the boss isn’t looking
Refactoring is about “improving the design of existing code”. Improving, in this context, means to make more understandable and/or more flexible. These could all be considered refactoring activities:
- Breaking a large method into smaller, more focused methods.
- Renaming variables and parameters to be more meaningful.
- Moving a responsibility from one class to another (more appropriate) one.
- Creating an interface, based on the methods in one class, then making that class implement the new interface.
Notice I said these could be refactoring activities. A large part of what determines if they actually are is how you go about them. Refactoring activities, just to re-iterate, are about small and safe steps, preferably reversible ones. If you have to think about if it’s going to work, it’s no longer a refactoring activity.
So how does this distinguish refactoring from re-architecting or redesigning? Well, refactoring is done at a keyboard, on real code. Re-architecting, however, is best done at a whiteboard (or the nearest pub). Re-architecting involves the bigger picture, and working out where you want to be next week/month/year. Refactoring is one of the techniques you might use to help you get there.
Redesign is a term that covers any time you are reconsidering a design decision. As coding is a design activity, even at the typing stage, redesign certainly covers refactoring. After all, it’s a little hard to improve a design if you don’t redesign it a little. However, in the normal context, “redesign” means to toss away the old solution and come up with a new one, more or less from scratch. If you do this at a whiteboard, it’s probably okay, similar to the re-architecting exercise, and you could still use refactoring to get you there. If you do it at the keyboard, it’s not refactoring.
Re-writing is like redesign, but it’s only done at the keyboard. Rewriting is usually a headache of hurt, but it can often lead you to a better place by leaving all your inertia behind. Kind of like selling up and moving to Bangalore. 😉
In practice, you end up mixing these a bit. Refactoring should be part of the daily process a developer uses, and the lines get blurred when you look at it that way. For example:
- Noticing that you need to add support for a second type of widget in your business logic is a design activity
- Extracting a new interface class from your existing widget, renaming your existing widget in the process, is a refactoring exercise.
- Replacing all pertinent references to your widget class with the new interface is a refactoring exercise
- Building the second widget, and adding it to the application, is a design activity.
But what happens if you build the two widgets first, and notice the commonality later? Well, it’s a refactoring exercise, probably centred around the Replace Conditional With Polymorphism refactoring. But from the outside it might look a lot like a re-write; certainly (relatively) huge chunks of code are going to be blasted to the ether. But whatever way you cut it, writing the second widget is not a refactoring exercise.
Refactoring is more about keeping things simple and flexible than it is about getting things right. Getting things right often involves adding new capabilities, or redesigning large sections of an app. Keeping it flexible just makes it that much easier. Thus, refactoring is best seen as an enabling activity.
You know, if I didn’t write these late at night, maybe they’d be a bit more coherent. 😉 If you want to know more about refactoring, go and read Fowler’s book.