Debug It: Book Review
David Agans’ ‘Debugging’ is the best debugging book that I’ve read so I was intrigued to see that there was another book being written on the subject.
Paul Butcher offered me a copy of the book to review so I was keen to see whether it was more like ‘Debugging’ or ‘Release It’ as Ted Neward suggests.
Debug It by Paul Butcher
Much like Krzysztof Kozmic I found that a lot of the ideas early on in the book were similar to what I’ve been taught by my ThoughtWorks colleagues over the last 3 1⁄2 years.
I do think it’s really good seeing these ideas in words though because it’s quite easy to forget about the best way to approach problems in the heat of the moment and the approaches suggested by Paul certainly aren’t done everywhere in my experience.
These were some of my favourite parts of the book:
- When chasing a bug Butcher suggests that a useful technique to use is to try and disprove your theory of why the problem has happened. Too often we come up with a theory and just adapt any data to fit our thinking. This is also known as confirmation bias. In his talk 'Pimp my architecture' Dan North suggests a similar approach more generally when working out how to tackle any problem. Each person has to take the other person's argument and then fight for that to be used instead. I quite like this idea - certainly something to try out.
- When discussing the need to refactor code as we go along, the author points out that if the code we want to change doesn't have any tests around it then we need to write some to provide us with a safety net.
Remember, however, that refactoring crucially depends upon the support of an extensive suite of automated tests. Without tests, you’re not refactoring. You’re hacking.Hamlet D'Arcy makes a similar point but perhaps more forcibly in a really good blog post and Michael Feathers' 'Working Effectively With Legacy Code' covers the topic in much more detail.
- One tip which seems obvious but is still one I've tripped up on many times is to go through the list of changes that we've made before checking in! It's incredibly easy to forget about some seemingly insignificant change that we made before checking it in and perhaps breaking our application unexpectedly. Somewhat tied in with this is the idea of checking in small changes more frequently and only changing one thing at a time which I wrote about previously.
- I like that Butcher puts a lot of emphasis on ensuring that we actually know what's going wrong before we attempt to fix anything.
Without ﬁrst understanding the true root cause of the bug, we are outside the realms of software engineering and delving instead into voodoo programming or programming by coincidence.This is particularly true when addressing performance problems where he rightly suggests that we should look to profile the code before making a premature optimisation. He also suggests using the debugger so that we can get a good idea about what the code is actually doing when it's running. While I think this is useful I feel that the need to use the debugger in this way frequently might suggest that our code is difficult to reason about which could well be something to address.
- A couple of other cool suggestions are to call on team mates to help us out if we're getting stuck trying to fix a bug and if that's not possible then to either write out the problem or talk to the rubber duck.
If you don’t have someone to play the role of cardboard cutout, all is not necessarily lost. Try scribbling down a narrative of the problem on paper or perhaps composing an email to a friend. The trick is not to censor yourself — just like a writer would.I don't think the importance of communicating with team mates can be underestimated and Butcher points out that if we notice a bad pattern in the code than it's no good just going through and changing it everywhere. We need to talk with the rest of the team to decide whether we can get an agreement on the way we'll develop code going forwards.
- The only idea I disagreed with is that of putting assertions into the code which I feel adds clutter to our code even though it makes it fail faster than would otherwise be the case. From my experience if we write good enough unit tests and have good logging in our code then the assertions aren't needed.