16 August 2005
I've recently picked up and read Martin Fowler's book, Refactoring: Improving the Design of Existing Code. It had been tempting me for a couple months, but I ended up waiting for a bookstore coupon and a couple gift cards before buying it.
The book is full of all the ideas in refactoring that you already know or mostly know plus expanded discussion of these seemingly simple ideas. The discussion effectively allayed my fear of changes, placed caution where it belongs, and all around boosted my confidence in these techniques.
Chapters 1 and 2 provide very introductory justifications and examples of refactoring, including "What should I tell my manager?".
Chapter 3 lists common Code Smells -- examples of code which doesn't feel right and needs to be refactored. It's great fun to read this chapter and identify names for all the problems you've seen in code of your own and others. More importantly, each code smell is accompanied by a list of possible refactorings which will help you eliminate it.
Chapter 4 gives you a quick little introduction to test-driven development, and its virtues when you're refactoring code. Unit tests are just one method to help build confidence that you've not broken anything. All the refactorings are presented as tiny steps after which you always run your tests. It helped me greatly to think about refactoring in small incremental steps instead of my previous "rip it out and recode until it compiles again" techniques.
The largest chunk of the book, Chapters 5-11, is the catalog of refactorings. The catalog provides methodical steps for safely applying each refactoring when needed. Many of the refactorings are simple, but I've always been reluctant to bother with those small changes. I quickly recognized the value of simple changes (like renaming things). Seeing the steps laid out, I could feel much more comfortable applying them when I used to shy away from it.
Many refactorings, such as eliminating temporary variables, felt like good ideas previously, but I didn't have the experience to know for certain. The detailed discussions relate years of experience and fill in the gaps in my own experience. I can confidently recommend or apply changes and know I'm headed in the right direction with each small step. It's also reassuring to know I can easily undo my changes if I find them inappropriate. I refactor much more, just as I read code, to capture my understanding as I go. Extracting methods with meaningful names is just one invaluable technique that I use as I try to understand a new piece of code. Before reading the book, I hadn't realized how valuable such changes could be. Using Eclipse and its automatic refactorings makes this especially easy.
Chapter 12 discusses a few of the larger refactorings that can take months of applying the small refactorings.
Chapters 13-15 provide a conclusion to everything. William Opdyke provides some real-world views of refactoring, concerns, and implications. There's lengthy discussion of implementing automatic refactorings in tools, which seems quite out-of-date with the advent of most these things in Eclipse and other IDEs. It seemed that in 1999, when the book was published, only Smalltalk had a reasonable refactoring browser.
This book sits well with the other classic references on my book shelf, such as the GoF Design Patterns.