I finished reading
Michael Feathers' book this week, and I am absolutely thrilled. This is my first book review on this blog, and I hope it gives a good idea of the book, so that people can make an informed decision on whether to spend their time reading it.
The book is about a programmer's worst nightmare: legacy code. I don't know a person that has never "inherited" an unfamiliar code base from another programmer. It really happens to everyone. Heck, even turning back to your own old projects might make you go "Gee, what was I thinking back then?".
First comes the definition of "legacy code". According to Mr. Feathers this is just code that you don't know how to change. You don't know if a change works, or breaks something else. Plain and simple, this is code with no test coverage. Forget documentation, forget "nice" design, if you don't have tests to run, then you are stuck in legacy land. I liked the definition, because I have seen many times that beauty is in the eye of the beholder. One's idea of pretty and simple design is another man's nightmare. When you need to change a legacy program, you need to modify or add behavior to it. There is no better way to know if you have kept the original behavior the same. Actually tests are the only way to know with a satisfactory degree of certainty.
The book teaches a disciplined method of introducing tests for old code, and then modifying it safely. It describes low-risk techniques of modifying the code, so that you can get any tests in place. This is what I liked best: you get to see some really ugly code, and it all gets tested, and refactored into something significantly better. The excuse of "my code base is so messy that I can't write any tests for it" does not work for me anymore. The text clearly identifies the root of all evil that makes testing hard: excessive dependencies in code. It provides the theoretical basis of identifying possible change points, and gives us reasoning tools that help when assessing what is the easiest thing to test that will provide us with the greatest value.
Michael Feathers has provided many examples of bad code patterns, and has shown possible ways of fixing them. You have a really messy code base? A procedural one, that has no structure? One that is all API calls, without any abstraction? Huge classes and methods that seem impossible to create in a test harness? Mr. Feathers has seen it all and can guide you through killing those monsters. What if you don't really have time to add tests for old behavior and make the code look better? Your manager wants that feature added right now! The
sprout method and
sprout class techniques allow you to implement a feature using test-driven development and make it work with the rest of the system. You don't pollute the existing code and you have a tiny oasis of tested code now. You just have to make sure that it grows over time!
The last part of the book is a very complete catalog of dependency breaking techniques. This is the most valuable part. It will show you how to eliminate or replace external dependencies, how to fake troublesome classes in your tests, how to test only that method without doing the socket operations or database calls it performs most of the time. The techniques are really ingenious and work best in object-oriented languages. Procedural languages like C have not been forgotten: you can do some thorough testing and refactoring there too.
The book is not limited to only one language. It contains examples in C++, C#, Java and C. I even saw a
Ruby example in there. It has a strictly hands-on approach, and drives you carefully through the mechanics of all changes. It has changed the way I look at legacy code, and I hope it will do so for anyone else that reads it. I highly recommend it!