In the foreword Robert Martin tells us that other patterns exist for preventing bad code, and this this book helps us reverse the rot, to “…turn systems that gradually degrade into systems that gradually improve.”
Since the provided definition of “Legacy code” describes “code without tests”, you can apply the approaches presented at any point in a project where you discover that the code does not have tests. And depending on the level of ‘rot’ you can pick and choose from the various techniques presented.
It goes far beyond other ‘unit testing’ books aiming to provide ways of allowing the coder to “confidently make changes to any code base” and certainly the book does a fantastic job of removing objections about “well that would be fine in theory, but not on my code base”. A 3 word summary of the presented approach reads “Cover and Modify”; cover code with tests, and then modify it.
I have written this book review late, since I first read the book about 2 years ago and have re-read it again a year ago and since then and dipped into it as required. A book like this needs to have code, it needs to have a technical focus and this one does - that does not mean that suddenly becomes out of reach of the non-technical - the code gets shown in context using small snippets surrounded by explanation. The book does not present pages and pages of code the code acts as further explanation and the supporting box outs and diagrams all help. I found this book very well presented and sectioned.
The ‘algorithm’ for code change that Michael Feathers presents early in the book has 5 points:
- Identify change Points
- Find Test Points
- Break Dependencies
- Write Tests
- Make Changes and Refactor
The chapters in the book either provide background on the thinking or general approach behind these points or, in the later chapters, specific mechanisms e.g. for ‘breaking dependencies’.
The ‘seam’ chapter - chapter 4 (freely available from InformIT - see link below)- describes one of the fundamental approaches that Michael uses; the identification of places “where you can alter behaviour in your program without editing in that place”.
And every ‘seam’ “has an enabling point, a place where you can make the decision to use one behaviour or another”
The small chapter describing this should seem fairly natural to testers. If testers have the experience of thinking through environments, working out what to split out and mock at different levels or replace with alternatives, or how to inject a monitoring mechanism into an existing app. Seeing the same thought processes applied to code helped me understand mocking and TDD better when I first read this chapter.
I learned a name for an approach to testing that I had adopted before but hadn’t identified as a special case - ‘characterisation tests’. Tests which represent the behaviour of the system “as is”. A concept that has served me well when doing ‘exploratory testing’ on applications I don’t know to first ‘learn’ the application through ‘characterisation testing’ and then perform specific ‘question’ oriented testing after this.
I generally treat legacy regression tests as ‘characterisation tests’ rather than as ‘real’ tests, meaning that they may tell me something about an ‘as is’ state of the application at some point in time, but they probably don’t ‘test’ the system in terms of asking any ‘questions’ about it. This provides me with a sense of doubt that I value.
But I digress. I get value from this book each time I read it. So it remains a computing book that I refer back to.
You can get a really good idea of the book’s contents below. I won’t attempt to summarise the book here because it does go into a lot of valuable detail and you need the book on your shelf. As simple as that really. Buy it.