Book Club: Working Effectively With Legacy Code - Chapter 10 (Michael Feathers)
In our latest technical book club we discussed chapter 10 - ‘I Can’t Run This Method in a Test Harness’ - of Michael Feather’s ‘Working Effectively With Legacy Code’.
In this chapter Feathers outlines some of the problems we might have getting methods under test and then suggests some ways to get around those problems.
These are some of my thoughts and our discussion of the chapter:
- I quite like the idea of pragmatic refactoring that Feathers suggests early on in the chapter:
Ideally, it would be great to break it down into smaller classes, but we have to carefully consider whether we want to do that much refactoring right now. It would be great to do it, but whether we can depends on where we are in our release cycle, how much time we have, and all the associated risks.I think it's important to understand when hacking code in is going to hurt us and quite often I think the side effects of taking this approach are underestimated. Tom spoke of 'value fetishism' whereby we get so caught up trying to add 'business value' that we forget to keep the code in good stead for future work. I quite like the analogy that Alistair Cockburn uses of software development as a series of cooperative gamem and I think it's sometimes easy to forget in the rush to get some code out for a release that we have to make sure that we don't make our lives impossible for the next game/release by rushing code in without paying due attention.
- Feathers spends some time suggesting how we can test private methods - one way is to change the method to be public. There are a couple of reasons why we might not want to do that:
- The method is just a utility and isn't something that clients would care about. We have therefore made our API more noisy
- If a client calls the method then it could have an adverse affect on the results of other methods in the class
- I quite liked the skin and wrap the API pattern whereby we create our own interface for a tricky dependency. We then refer to the interface in our code instead of the concrete dependency and have a class which just delegates to the real dependency. We did this when trying to test file operations on a project I worked on a couple of years ago.