I mentioned this book in an earlier blog, and I’ve started to read it. (I was somewhere around 2/3 through Martin Fowler’s Refactoring, and in the weeds of arcane refactoring patterns when I decided to switch out) I’m maybe 70 pages in, and I have to say Working Effectively With Legacy Code thus far seems quite good. It’s actually a great companion to the refactoring book, and to the design patterns that I keep trying to get back to so that they really sink in (through reading the Heads Up book last time I made a concerted effort at patterns, though I might give the GoF book a go as it is the canonical choice.)
Unlike the patterns, and even more than the refactoring book, this book really gets at how to approach a messy codebase. Rather than just talking about refactoring, it really discusses them in context, usually in the context of separating concerns enough to test. At this point in the book at least, testing seems to be the short-term goal, making the assumption that you probably don’t have tests covering your legacy code. Fair assumption to make. So, it doesn’t focus on making the code easier to read, more maintainable, or elegant. It actually focuses on smashing apart your concerns, by whatever means necessary, so that you can get stuff under test, and *then* make stuff pretty and maintainable. The chapter I just read focused on finding what it referred to as “seams”-places where you can change the behavior of the code to make it testable *without* messing with the code under test in a significant way. for instance, if you’re already passing in a class to use in your operation (Dependency Injection) you’re golden. But Feathers suggests much more “wily” seams, such as overriding included libraries with your own wrapper libraries during compilation to introduce hooks for testing. Whew. that could get ugly… but then, you’re trying to reform legacy code from a test-unfriendly state, it’s probably not going to be pretty. Anyway, that’s a fair bit different from the refactoring book, as that tends to discuss tests as an assumption that you have before doing sometimes significant changes.
The book also has some chapters ahead of me that seem refreshingly realistic. These are from memory so don’t quote me, but there are chapters titled things like “I can’t get my code into a test framework!” and “I don’t even understand my code enough to change it!” Working on a complex, deteriorated codebase is a programming challenge, but also a morale problem. It’ really easy to throw up your hands and say “this code base cannot be saved! It needs to be totally rewritten, and since that won’t get paid for, we’re screwed!” … OK, frankly, this IS sometimes true, and I do think it is important to recognize when that’s what you are really dealing with-and to recognize that’s a high bar. The vast majority of the time, you’re facing some code that’s okay, but could be much, much better. The transition will be tough, and involve a lot of rewriting and duplication, but you know it’ll pay off. Do you do it? Well, it depends, of course. But the answer should not be determined, as it so often is, by pondering the work involved and deciding that it feels to exhausting to even contemplate. This book thus far seems to be pretty good at illustrating a straightforward path to get to somewhere better, and get over the intimidation of all that badness.