Test Driven Development

There were six of us at the Lamb and Flag to discuss test driven development (TDD). I was joined by Miquel, Tom, David, Inigo and new boy Julian. The books chosen to kick off the discussion were two different books called “Test Driven Development”, the first by Kent Beck and the second by Dave Astels.

David revealed that he’d actually read a third book, Test Driven by Lasse Koskela. He said it was not a bad book but he wasn’t convinced by the part which talked about driving development through acceptance tests. The section on test driving the database was fine for simple applications, but in David’s experience it is not always simple to swap the database used in live with an in-memory database such as HSQL. Often the application will use stored procedures or other specific features of the target database. Inigo pointed out that if you have a requirement to support both Oracle and SQL Server, say, then using a third database would actually not be such a big step.

Inigo referred to a study by Microsoft which showed that TDD took 15-35% longer than traditional development but was 40-90% better in terms of bug counts.
He suggested that it is the fact that the tests are written at the same time as the code that is important, not the fact that tests come first. David suggested that you lose some advantages if you don’t follow the rules. Writing the tests first mean you always know where you are and that every feature should have a test. Tom said that be coded test-first when bug fixing, but found that doing true TDD was a bit tedious if followed to the letter. I mentioned Ping Pong programming, where a pair of developers play a game by adding a failing test and getting their partner to make it pass and add their own failing test. The idea is to try to write as little code as possible. There was some surprise that this was not mentioned in the books we had read.

We talked about the Kent Beck book. Inigo found it to be a little lightweight and quite philosophical while Miquel thought it was easy to read. Inigo thought it had extra sections that were not strictly needed in a book about TDD, for example the chapters on refactoring and patterns. However, he liked the design of the code that is explored in the book, which is a currency conversion application. Inigo had expected some interesting details of JUnit 4, but once he saw the copyright date he realised that this was not possible.

I found the Dave Astels book felt quite outdated. It is quite a few years old now, so many of the technologies such as JUnit and mocking have moved on quite significantly. It could also do with some typesetting love as it is not the most beautiful book to look at. I also felt that it was rather long – I couldn’t bring myself to read through the extended example which makes up most of the book. Julian (as a newcomer to the subject) did feel that it was good that it was so practical, unlike Kent Beck’s more theoretical approach. So perhaps it is the better of the two for someone new to this area.

We moved on to talking about different testing techniques. I mentioned Jumble, a mutation testing framework which I have described on my work blog. David talked about how he used Fuzzing in his previous job to find bugs in an XML parser. His experience was that it was best to have a smart fuzzer that understood XML as this was more likely to find bugs than just adding random noise to a file.

Inigo mentioned Hamcrest matchers and the use of assertThat in JUnit. It was generally agreed to be good for readability of code and error messages, but not so good with respect to IDE auto completion. David pointed out that JUnit 4 has this problem over JUnit 3 since the assertion methods need to be statically imported.

Finally Miquel asked about how to test JavaScript. Tom and David described Selenium/WebDriver as the best tool in this area.

Legacy Code and Testing

Just me, Steven and David turned up for this one. We were looking again at Michael Feathers’ book Dealing Effectively with Legacy Code.

Steven began by saying that he still thought it was a good book, with a poor title. This was the general consensus last time we discussed it. I’ve certainly picked up some techniques from it, in particular the idea of subclassing the class under test to stub out external dependencies. Steven said that originally he’d thought that there might be some overlap with Martin Fowler’s Refactoring, but having thought about it he decided that there wasn’t. Everywhere where this might happen, Michael Feathers references Martin Fowler. I suggested that this book was probably one of the most under-appreciated books in the area of refactoring and design.


A technique which I found interesting this time was “Scratch refactoring” which is refactoring just to learn about the code. Steven agreed but was slightly concerned that there would be a temptation to keep the refactored code rather than throw it away. (Remember, you have no tests for this…)

Another interesting technique was “Characterization Testing”, which is creating tests simply to document what some code does currently. This can then be used to allow refactoring to take place. These tests can subsequently be thrown away and replaced by proper unit tests once the code is in better shape. I suppose the danger is once again that this scaffolding will not get discarded.

Steven mentioned that the chapter on testing code that is all API calls was particularly relevant. He has this exact situation and had always thought that this code was not testable. Having read the book he may get it under test.

David (arriving a little late) said that he thought it was a brilliant book. The only problem is that he would prefer a small number of files to look at whereas with Java you tend to get something of an explosion of classes. Using dependency injection tends to exacerbate this. We moved on to discussing dependencies between packages and I gave Structure 101 a name check. I’ve used this at work to keep dependencies in check – a fact which I have blogged about.

We moved on to the idea of “Architecture as a story” which Michael Feathers discusses in Chapter 17. The idea is that if you can encapsulate the architecture as a story it makes it more likely that it will survive over time. Something like having an oral tradition in place of a document.

Finally, Steven said that he thought that this book was one he would aim to keep close by in future. So when he needed to get code under test he would be able to refer to it for help.

Meeting 17- Refactoring To Patterns

A decent turn out at the Lamb and Flag to discuss “Refactoring to Patterns” by Joshua Kerievsky. I was joined by Tom, Mick, Steven, Andy, Ursula and John.

We started out by discussing what Steven thought of the book, because he’d previously said that he wasn’t impressed by it. He explained that he’d found the books “Refactoring” and “Design Patterns” to be life-changing. When he heard about this book, he expected it to be in the same mould and ordered it before it was even published. But when it arrived it didn’t live up to the expectation. However, having looked at it again, he has now come to the conclusion that it does what it says on the tin. So it is a useful book after all.

We all agreed that it isn’t a book for dipping into. You need to concentrate on it and read a whole pattern in a single sitting. I found that it was not good for reading just before going to sleep. You think “I’ll have a quick read before turning out the light”, pick it up and start reading “Replace Composite with Polymorphic..” and don’t get much further.

I think it is a book to work through with colleagues, finding places to apply the patterns and seeing how the design turns out. Tom agreed and said that he liked to read the book in a different order to that given. He thought the best way was to ‘follow the smell’ and see how each smell could be removed by application of the refactoring.

Mick showed us his copy of the book, complete with many markers. He’d found lots of places in his current codebase where these refactorings would help. He thought that the main ‘take home message’ was that sometimes adding functionality the naive way and refactoring was better than trying to think of the perfect solution upfront. He also said that he had found some of the “Benefits and Liabilities” sections to be irritating because initially all of the liabilities seemed to be “it could be too complicated”. Later on he thought that the liabilities became more interesting.

Ursula said she thought it was like a travel guide. I liked this analogy. The section at the front is like the background information on the country and each refactoring is a different place. If you’re visiting a particular place, then the section in question could be very useful, if you’re not, then it isn’t going to be so interesting to read.

John said he found it very much focussed on object-oriented programming, which was not quite what he was expecting. This was mainly because “Design Patterns”, although strongly focussed on object-orientation, is about higher level design ideas. So you can get something out of it, even if you’re not working in OO. But this book is all about the nuts and bolts of working in an OO language. Since he has only dabbled in OO, he didn’t follow the book through.

There was some discussion about how or if you could automate some of the refactoring in this book. Mick mentioned Google’s “Singleton Detector” and I mentioned that I’d attended a half-day tutorial with the author, Joshua Kerievsky in which he’d given us some material that he’d developed while writing this book. It was called (slightly confusingly) “Patterns of Refactoring” because it described techniques he’d come up with while writing these patterns. These techniques came out of the constant improvements to the refactoring steps described. Quite often the first draft would leave the code broken and untestable for a long period. But over time he found ways to make small steps that kept the compiler and the test suite happy. Typically, I forgot to bring these notes with me, but there is a short article I wrote about it on the company blog.

This led Ursula to ask about how testing and refactoring fit together. There were some differing views. If you are doing small scale refactoring, then the tests will likely not need changing and are a good indication that nothing has been broken. With large scale refactoring, the tests are liable to need changing as you go along. In that case, it is helpful to have some higher level functional tests as backup to show that all is still well.

We then moved onto a discussion of how deprecation fits into the picture, particularly when doing refactoring in very large systems and where published interfaces are involved. Ursula described a system whereby a feature was scheduled to be removed at a given release and how this simplified matters.

Finally, we talked about my idea of alternating the discussion month by month between an agile book and a programming language. When I explained that it was more likely to be an older language (like Smalltalk or Lisp) or a more esoteric one (like Haskell or OCaml) there was more interest in the idea. Steven said he didn’t want to end up discussing PHP or the like. So it seemed like there was actually more enthusiasm than I thought for the idea….

First Meeting – Refactoring by Martin Fowler

We met in the “Far from the Madding Crowd” pub in Central Oxford. Since we weren’t quite sure who was who it took a few minutes for us to find our fellow Oxtremists. The copy of “Refactoring” lying on our table was the giveaway. We sat in the slightly quieter non-smoking section on the left hand side. Perhaps this should be our preferred location at future meetings? The following is what I noted down about our discussions on the book. Additional comments from those that attended would probably be useful to fill in anything I have missed.

We started off talking about how you go from thinking ‘This design would be better if…’ to actually running through a series of specific refactorings. I find that when I see the need for large changes in an area of code, my instinct is just to rip it up and put it back together in the correct form. I then rely on the unit tests to ensure that everything is still working as expected. I don’t think others had quite the same experience – maybe they’re more disciplined than me? Steven made a point that if you’re using Java you are generally quite spoilt by refactoring support in the IDEs. If you are using another language, such as C++ then you are more likely to follow the refactoring steps as outlined in this book because you have to do everything manually.
We then discussed whether the book was showing its age by saying that “In our current understanding of software development” we design and then we code (page xvi). It was agreed that perhaps in much of the development community that is still the prevailing attitude.

Looking through the example which makes up the bulk of the first chapter, we talked about the “Replace Temp with Query” refactoring (page 21). I suggested that this was a refactoring that I would be unlikely to think of. In the example given, a total is requested from another object and held in a temporary variable. It is then used twice. After the refactoring the object is asked twice for the total, which causes the calculation to be done twice. So there could be a performance penalty, although in this case it was liable to be tiny. The reason given for doing this refactoring was that temps make it hard to split up long methods, so we should consider removing them. I suggested that it could also aid readability. We all agreed that this refactoring wouldn’t be the obvious one to do.

Moving on to the section about when to refactor, we talked about the paragraph where Martin Fowler suggests refactoring when you find a bug (page 58). I found his take on this interesting. He says that if you get a bug in a certain area of code, “it’s a sign you need refactoring, because the code was not clear enough for you to see there was a bug”. Steven said that there was a possibility that people would have exactly the opposite attitude: “I don’t want to touch this buggy code as it’s obviously unstable!”

Looking at Chapter 4, which deals with testing and JUnit in particular, we all agreed that at the time this material was needed. Nowadays though, most Java programmers should be aware of JUnit, as it has moved well into the mainstream.

Talking about the book as a whole, Graeme commented that coming from his perspective, (a background that doesn’t include Java or C++) the book seemed to be back to front. He found the initial example in Java to be difficult to follow, whereas the subsequent material about Why, When and How you should refactor was easier to digest.

From this point on, the discussion moved onto general talk about software development and I stopped taking any notes.