C/C++ Users Journal February, 2005
Working Effectively with Legacy Code
Michael C. Feathers
Prentice-Hall PTR, 2005
434 pp., $44.99
ISBN 0131177052
Refactoring to Patterns
Joshua Kerievsky
Addison-Wesley, 2005
367 pp., $34.99
ISBN 0321213351
Find the Bug: A Book of Incorrect Programs
Adam Barr
Addison-Wesley, 2005
306 pp., $34.99
ISBN 0321223918
Every bandwagon that rolls by leaves two things behind it. The first is a hard-nosed skepticism that dismisses the innovation entirely because it didn't live up to the exaggerated claims of its most outspoken proponents. The second, however, is freshly minted common sense. "Of course we do it that way," people say, forgetting that five years before, they'd never heard of "that way." What remains may only be a fraction of the original grand design, but it is usually the part that actually worked.
Design patterns and extreme programming (XP) are two recent examples. Back in 1995, it didn't matter what your problem was: Someone would tell you that patterns were the solution. By 2002, when XP became the hot thing, patterns hadn't disappeared. Instead, they'd become something that most programmers took for granted, in part because they were now too busy arguing about pair programming to be fazed by terms like "singleton" and "decorator."
Today, three years later, most of the programmers I know have looked at XP and adopted all the bits they're ever going to. Pair programming, an on-site customer, and stand-up meetings? No thank you, but test-driven design, sure, I'll have some of that, and an extra helping of refactoring. It may not be what XP's creators had in mind, but heydoes anyone really mind that we got the Internet instead of the flying cars we were promised in the 1950s?
One of the signs that a revolution has been normalized is the appearance of second-generation books that describe how to apply ideas, rather than proselytizing them. This month's first two books both fall into this category. The first, Michael Feathers's Working Effectively With Legacy Code, is, quite simply, a great book. I've folded down more corners on it than on any other book I've read this year, and both my colleagues and my students are going to have to put up with me reciting bits to them for months to come.
Feathers defines legacy code as code that doesn't have tests. As he says, most programmers spend most of their time fixing bugs, porting to new platforms, and adding new featuresin short, changing existing code. If that code is exercised by unit tests, then changes can be made quickly and safely. If it isn't, they can't, so your first priority should be to get the code you're changing under test.
Simple, right? Except that most of us don't do it, or don't do it well, because we've never been shown how to do it systematically. That's where this book comes in. Want to know three different ways to inject a test into a C++ class without changing the code? They're here. Want to know which classes or methods to focus testing on? Read his discussion of pinch points. Need to break interclass dependencies in Java so that you can test one module without having to configure the entire application? That's in here, too, along with dozens of other useful bits of information.
Everything is illustrated with small examples, all of them clearly explained and to the point. There are lots of simple diagrams, and a short glossary; all that's missing is hype. If you program for a living, you really ought to read this book twice: once to learn how to do the things Feathers describes, and once more to learn how to avoid creating legacy code in the first place.
Joshua Kerievsky's Refactoring to Patterns is also a second-generation book. As the blurb on the back says, "This book introduces the theory and practice of pattern-directed refactorings: sequences of low-level refactoring that allow designers to safely move designs to, towards, or away from pattern implementations." In other words, once you're past the two forewords, the preface, and the three introductory chapters, this book is a catalog of techniques for transforming code written to one pattern (or no pattern at all) into another.
Like all catalogs, this book is a bit much to read end to end. I found I did better dipping into it to find particular things. For example, I recently decided to refactor some Python code that was littered with "if x is not None" tests. The book's index led me to page 301, "Introduce Null Object," which gave me a quick refresher on the Null Object pattern, and gave me some ideas about how to adapt my code to it. In doing so, it helped me more than either a patterns book or Fowler's "Refactoring" Bible would have on its own.
Finally this month is Adam Barr's Find the Bug, which presents a bunch of short programs in C, Python, Java, Perl, and assembly, and challenges you to find the bug in each. The programs themselves are pretty simplelinked list traversal, printing the month and day, and so onand the bugs range from simple to subtle.
I enjoyed it a lot (although my score was lower than I'd have liked). I plan to use some of his examples in interviews the next time I'm recruiting, and would really like to see several sequels. If you're hiring, teaching, or just want to see how sharp you really are, it's a pretty good investment.