Working Effectively with Legacy Code: The Best & Worst

[Working Effectively With Legacy Code, 2004, Michael C. Feathers][1] 3/5 [Stars](

When I first read this book, I was quite disappointed. I’d expected a book that follows the title, but Feathers turns this notion on its head before the book even begins. He says, “legacy code is simply code without tests. … It doesn’t matter how well written it is; it doesn’t matter how pretty or object-oriented or well-encapsulated it is. With tests,1 we can change the behavior of our code quickly and verifiably. Without them, we really don’t know if our code is getting better or worse” (p xvi).

I didn’t agree with that when I first read it, and I don’t agree with it now, but the entire book is predicated upon this assumption. Feathers encourages doing anything – mangling code, breaking encapsulation, making too complex code even more complex – just to get code under test. On reflection, this is actually a good book about unit testing anything – even those things you thought were impossible.

[[An alternate cover for the book: 'Unit Test Anything: A Guide for Java, C++, and C']][2]

A hypothetical alternate cover

But it’s not a book about working effectively with legacy code.

I wrote last week that I think this definition of legacy code as code without tests is a subset of a larger, more encompassing definition. I also have to take issue with the idea that unit tests are the only way to determine code quality. There are a lot of different ways of doing this, and their suitability depends on your situation: static analysis, spot code reviews, pair programming, code metrics, automated system and integration tests, randomized tests, hell; even manual tests. I love unit tests and I love TDD, but it’s no silver bullet, it’s not the One True Way.

Outside expectations from the title, this is exactly the book that I would expect from someone of Feathers’ background. Feathers was developer and maintainer of CppUnit, the C++ port of JUnit. He’s also been a consultant with Object Mentor for several years, with a focus in legacy systems. Working Effectively with Legacy Code is clearly written by a very smart guy with a lot of success working with legacy systems and by someone who is an expert at unit testing and refactoring.

“The book is highly entertaining and comes across as a conversation with a really sharp, really patient guru developer. Often, it’s a chore to slog through code-heavy books. But Feathers manages to keep my attention with interesting stories, loads of examples, and well-written text.” – J.J. Langr

“The high level goal of the book is show you how to write good unit tests for code that wasn’t designed with unit tests in mind.” – Kevin

The Best

Seams. Seams allow you to change part of the behavior of existing code without changing that code itself. With them, you can add features or alter the behavior enough to test a method. Different types of seams (preprocessing, link, and object) allow you to get in and alter different parts of the code, and each has its own tradeoffs. Thinking in terms of seams makes you recognize these opportunities, or enabling points.

Effect/Feature Sketches. I was immediately drawn to these two techniques for understanding code. Effect sketches help you see the impact of things by drawing out what what they impact. This helps you find a method further down the line that will still let you check the behavior of the first method. Feature sketches are a way of seeing the responsibilities in a class by drawing out the relationships between functions and the member functions or member variables they use.

Scratch Refactoring. This reminds me a lot of experiments – prototyping. But while experiments are usually done in simplified, quick environments outside the code base, scratch refactoring is about just branching the code, refactoring a bunch to see what’s possible, then throwing out the changes and keeping only the lessons. I had never thought of doing this, and I’m using it more now. It’s hard to avoid the prototyping trap (“Looks like you’ve already got it working, let’s just use that”) because it seems like such a big step forward to have gotten it where it is in the refactoring.

”We Feel Overwhelmed”. (p 319) After twenty-three chapters of talking about working with existing code, Feathers has a brilliant two page pep talk. It’s here that his “sharp, really patient guru developer” voice is strongest.

The Worst

Low construction quality. So it’s strange to comment on the construction of the book, but it matters. My copy is falling apart, and I’ve only read it once. The glue on the cover and keeping the page groups together is almost completely gone. My boss had a copy of the book but stopped reading it because it was missing a chapter and had duplicate pages.

Simple book examples that don’t scale. This is a common problem for all software books, but it makes it especially hard when you talk about dealing with huge classes and monster methods. The examples methods are only a page or two long, when my monster methods would double the size of the book. I’m not sure how some of the techniques scale. I tried to use a feature sketch on a huge class of our own, so big that I had to write a script to find all the relationships. But all it told me was that I had a big, giant mess on my hands.

You, and everyone on your team, and all your bosses have to agree: you cannot work without unit tests. It’s certainly not a given that you all agree, or that you can easily sell them on it. This is not really something that Feathers is concerned with, for all that it’s the foundation of the book.

But still…

Writing unit tests for existing code is still important, and I think Working Effectively with Legacy Code is a good book if you want to start using TDD on the legacy areas of your code. I think what I would really love to see is a book of case studies about teams which have done well with legacy code. Case studies are really good for thinking about “how do you approach this situation?” and legacy systems present a lot of situations that are beyond what we know how to deal with.

This slide deck from Orbit One Internet Solutions condenses the book into a 35-slide powerpoint. One from Feathers (I think?) describes the ‘steps’ of working with legacy code using an example. Michael Feathers has a website and a blog of his own, updated a half dozen times a year, and is on twitter.

  1. A side note here from me: he means unit tests, not just any tests. Good unit tests are quick, descriptive, and local. Tests that run for minutes or hours don’t let you change code quickly. 

This entry was posted in Book Reviews and tagged , , , , , , , , . Bookmark the permalink. Both comments and trackbacks are currently closed.