Friday, 18 April 2008

Book Review: Working Effectively with Legacy Code by Michael C. Feathers

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:
  1. Identify change Points
  2. Find Test Points
  3. Break Dependencies
  4. Write Tests
  5. 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.
Related Links:

Friday, 11 April 2008

Book Review: JUnit Recipes by J. B. Rainsberger, Scott Stirling

' "Stop Debugging. Write a test instead" and here's how'. That seems to sum up the book. Wether you use TDD or not, JUnit Recipes helps you get more out of JUnit - perhaps it will help you stave off a move to TestNG?
Contents include 130+ 'solutions' for common tasks. If you check out the contents page then you can see what the authors cover.

People often want assurance from 'authorities' that they are doing the right thing so the book has discussions about 'how much' testing to do and 'how low' to go. 
So guidelines include:
  • "don't test it if it is too simple to break",
  • "don't test the platform"
  • "try the different techniques out and see which you prefer"
  • "test anything in which you do not already have confidence"
Hence guidelines rather than prescriptive practices. The book heavily encourages the reader to try it out and see how it works for you, and provides some alternative approaches.
You do have to work through some of the examples to understand them (or at least I did) and since it acts as a recipe book, you mainly consult it when you need to.
Unlike many cookbooks, Junit Recipes seems to move through in a logical order building on previous recipes so although it doesn't sell itself as a tutorial book you can work through it in that way.
At least you can probably read up to Chapter 6 sequentially, but thereafter the book worked best for me as a dip in and out when required recipe book (presumably the intended usage).
Many tidbits based on experience, of which I have only selected 4 that stood out for me on initial reading:
  • testing floating point values with tolerence levels
  • abstract test cases -
  • have JUnit automatically build test suites "return new TestSuite(MyNewTest.class);" (and other ways of automatically building suites)
  • suite or higher level setups rather than just at testCase level
I didn't know JUnit supported so many ways to build test suites. I found the discussions in Chapter 3 and 4 on how to organise your tests very useful.
Chapter 4 contains a discussion of data driven tests, a technique common to 'system testing' but I don't see used very often at the unit level and looking at the code provided I can see why - I had to go through this several times to get a handle on it and would still want the book in front of me if I tried to do it live. Coverage of the use of test data then increases in Chapter 5.
At Chapter 14 you can start reading sequentially again. So for a first read I would recommend 1-6. 14 -> to the end.
If you use JUnit as your test tool and if you do any of the 'things' covered in the contents list of recipes then I recommend getting hold of this book.
Useful links that have examples of usage in the book:
Related Links: