Archive for the ‘Book Club’ tag
My colleague David Santoro has started up a technical book club at the client we’re working at in Wales and the book choice for the first session was Chapter 7 – Achieving Object Oriented Design – of Growing Object Oriented Software, guided by tests written by Steve Freeman and Nat Pryce.
In this chapter they cover various approaches for driving towards object oriented code including techniques to find new objects and a detailed description of TDD and how we can approach this in a way that allows us to drive out new behaviour effectively.
These are some of my thoughts and our discussion of the chapter:
- I quite liked the quote that the authors open the chapter with:
In matters of style, swim with the current; in matters of principle, stand like a rock.
I think we often end up spending a lot of time arguing about style when a lot of the time keeping to core principles is more important if we’re to keep our state in a maintainable state. I suppose it’s a bit of an abstract quote but it seems a useful one to keep in mind.
- One suggestion that the authors make is to organise our code into layers – an implementation layer where have our different objects (which Martin Fowler refers to as the push button API) and then a declarative layer on top of that i.e. a domain specific language.
On the projects I’ve worked on I don’t recall us doing this except for in test code where we would often end up writing DSLish code to describe how the application was supposed to work. I suppose this is just a logical next step.
- Somewhat related to this the authors point out that following a TDD approach ensures that we have to specify the ‘what’ of what we want to achieve before we specify the ‘how’. In this case the test describes what we want to achieve and the production code is the implementation of that.
They also emphasise the importance of ensuring our tests are understandable by limiting their scope. From my experience we can often get away with using very minimal test data in most of our unit tests and if we need to write a lot of setup code for each test then we’ve probably done something wrong somewhere.
Anwar pointed out that if we’re finding it difficult to test what we want to from one level then it can make sense to try and test that from further up the stack. While this is certainly true I think we need to be careful to ensure that we’re not just doing that because we don’t want to work out how to make our code easier to test further down.
- I first realised how useful value objects could be after seeing a talk by Dan Bergh Johnsson at QCon in London last year and the authors describe several ways that we can try and get more of these types of objects in our code.
- Breaking out – if code’s becoming too complicated we might split the responsibility of a large object into several smaller ones. I find that the key here is to focus on making incremental improvements to this type of code. It can often be a big job to get the design of these types of objects as we want them and since we might not get the time to do that, just making the smallest improvement we can think of repeatedly can be quite useful. Having said that I still find it quite difficult to do.
- Budding off – to mark a domain concept in the code we might create an object that wraps a field or has no fields at all. I find this approach is the hardest to introduce as people often see it as adding pointless code when we could just use a primitive instead. This is the area of micro types and I think there’s probably a measure of judgement required here to determine in which situations we get benefit from taking this approach.
- Bundling up – if we see a group of values being used together then we might bundle them together into a type. I find that it’s easier to do this when it’s groups of primitives that you’re bringing together. I don’t find it as easy to spot when groups of objects are being used together and a concept is probably missing.
- While I’ve been doing TDD for a few years now I don’t think I’ve yet totally grasped the idea of pulling interfaces into existence to the extent that the authors describe while writing tests:
We think of this as “on-demand” design: we “pull” interfaces and their imple- mentations into existence from the needs of the client, rather than “pushing” out the features that we think a class should provide.
Liz Keogh refers to this as Pixie Driven Development and I think following this approach would help us to end up with meaningful interfaces containing groups of functionality rather than seemingly random groups of methods which seem somewhat related.
It’s certainly an area I need to spend more time practicing on.
In the last Sydney book club that I attended before I moved back to the UK we discussed Chapters 12 and 13 of Michael Feathers’ ‘Working Effectively With Legacy Code‘
Chapter 12 – I Need to Make Many Changes in One Area. Do I Have to Break Dependencies for All the Class Involved?
One of the ideas suggested in this chapter is that when writing tests we should try and write these as close to the change point as possible. Ideally we want to write a test directly against the method that we’re changing but sometimes that isn’t possible.
In this case Feathers suggests writing a test at the closest interception point (place to detect effects) and then changing the code at the change point to ensure that the test fails as expected. Tony Pitluga describes this approach in more detail in his post about gaining confidence before refactoring.
When working out where we need to write our tests, Feathers suggests that we need to look for pinch points i.e. methods from which we can detect changes in other methods in a class.
Feathers has a nice analogy where he compares this approach to ‘walking several steps into a forest and drawing a line, saying “I own all of this area”.’
We can then work with the code in that area of the code base with some degree of safety until we’ve got the code into a better state at which point we might decide the pinch point tests are no longer needed.
Chapter 13 – I Need to Make a Change, but I Don’t Know What Tests to Write
Feather suggests writing characterisation tests – tests to document what the system currently does – for the parts of the code base that we’re currently working on.
This is the approach that Dave encouraged on the last project I worked on – trying to write tests for code that we’re not currently working on is a bit risky since we’re not really sure what the behaviour is supposed to be. In addition we don’t get much benefit from them since we’re not changing anything in that area.
Feathers also points out that we shouldn’t try to fix any ‘bugs’ that we come across while writing these tests – we should instead raise them and see if anything needs to be done. I remember watching an Uncle Bob presentation where he described how he had ‘fixed a bug’ which actually broke all dependent systems which relied on the bug being there. This is the situation we’re trying to avoid!
Another approach suggested if we’re having difficulty testing a large chunk of code is to refactor it into smaller methods and then test directly against those instead. I think this works well as a short term approach until we can test more easily from elsewhere.
In our latest technical book club we discussed chapter 11 – ‘I Need to Make a Change. What Methods Should I Test?’ – of Michael Feathers’ ‘Working Effectively With Legacy Code‘.
In this chapter Feathers covers some techniques which allow us to work out which parts of the code we need to write tests around when we make changes.
These are some of my thoughts and our discussion of the chapter:
- Feathers starts off the chapter by introducing the idea of effect sketching which I’ve been trying out recently both on the projects I’ve been working on and with the Unity dependency injection container.
The idea is that we create a diagram which shows the effect that changing different fields and methods will have on the rest of the class and then based on this we can see where we need to create a safety net of tests for any given change.
It seems like this type of diagram would also be quite useful for identifying when a class has more than one responsibility because you would end up with several mini unconnected effect sketches within the main one.
- Feathers suggests that we should look to write characterisation tests around legacy code. These are written a little differently to TDD’s tests because we make the assertion match what the code is currently doing. The idea is to document what the system is doing now. We might come across ‘bugs’ while doing this but we wouldn’t necessarily change the tests to verify how the code ‘should’ be until we find out what the effect of doing that would be.
We want to write enough of these tests that we feel confident that we have a good enough safety net to allow us to change the code.
- There are some interesting ideas about encapsulation towards the end of the chapter where Feathers considers the trade off between ensuring test coverage and encapsulation.
Breaking encapsulation can make reasoning about our code harder, but it can make it easier if we end up with good explanatory tests afterward.
Encapsulation and test coverage aren’t always at odds, but when they are, I bias towards test coverage. Often it can help me get more encapsulation later.
Encapsulation isn’t an end in itself; it is a tool for understanding.
I find this is sometimes quite a big barrier to break down because people are often reluctant to change code to make it more testable. That’s sometimes a valid concern but with legacy code not so much.
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
The cleanest solution for that second point is to move those methods out into their own class where we could test against them directly. A smaller step to take is to make the method protected and then create a test version of the class from which we can call the protected method directly.
Feathers also talks about the danger of using reflection to allow us to test this kind of code – it might allow us to get tests around the code but we’re not making the code any better and we may not notice quite how bad the code has got. We are just delaying the inevitable.
There’s a tool in .NET land called TypeMock which allows you to test pretty much anything but I wonder whether we would run into the same problems that Feathers describes above.
- 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.
In our latest technical book club we discussed chapter 9 – ‘I Can’t Get This Class Into A Test Harness’ – of Michael Feather’s ‘Working Effectively With Legacy Code‘.
This chapter goes through various problems that we might have getting a class under test and then suggests different techniques to get around those problems.
These are some of my thoughts and our discussion of the chapter:
- One approach that Feathers describes when dealing with constructors which take in a lot of values is to just pass in nulls for the parameters that we don’t care about.
While I think this is a useful strategy it’s useful to keep in mind that the need to do this is often an indication that the class is doing too much and we probably need to look at breaking that class out into two smaller ones.
Another useful bit of advice Feathers gives is to try and get the code under test instead of discussing all the reasons why we won’t be able to do so:
The best way to see if you will have trouble instantiating a class in a test harness is to just try to do it. Write a test case and attempt to create an object in it. The compiler will tell you what you need to make it really work.
I think this advice is applicable to most aspects of software development. A lot of time is spent debating approaches when it would be far better just to try something out and see what happens.
- Several patterns are described for dealing with singletons in our code and Matt also pointed out the mono state pattern which Uncle Bob outlined as being a step on the way to getting rid of them.
- The sub class and override pattern is described for handling several of the problems we might encounter. The idea here is to get the code into a position where the code which is making it difficult to test a class is all in one protected method which we can then override in a sub class and replace with a fake/stub version of the method.
I’ve previously fallen into the trap of thinking that this is a pattern we should be aiming for when designing code from scratch. In particular it seems to happen a lot in ASP.NET MVC controllers when working out how to test code in ‘OnActionExecuting’ and similar methods.
I now believe it is another indicator that we are too highly coupled to a concrete implementation which has side effects and we might be better off looking for an abstraction that allows us to break that.
- Feathers makes another really telling comment towards the end of the chapter when discussing how we use language features to try and enforce certain things in our code:
In the end, it all comes down to responsible design and coding
This reminded me of his ‘Design Sense‘ presentation where he covers similar ground and it’s very true. No matter what language features we have it’s down to us to use them sensibly in the systems we write.
In our latest technical book club we discussed chapter 8 – ‘How do I add a feature?’ – of Michael Feather’s ‘Working Effectively With Legacy Code‘.
This chapter covers Test Driven Development and a technique I hadn’t come across before called Programming By Difference.
These are some of my thoughts and our discussion of the chapter:
- In the section on TDD Feathers mentions the copy/paste/refactor pattern which I wrote about a few days ago. Cam pointed out that this technique allows us to get to the green bar more quickly after which we can decide how to clean up the code. It seems like perhaps this could be added to Kent Beck’s ‘Green Bar Patterns’ that he describes in ‘Test Driven Development by Example‘.
I’ve noticed a few times recently that delaying our desire to remove duplication until we can properly see where the duplication lies might be a better strategy than prematurely removing duplication and creating a meaningless abstraction which can be difficult to remove.
- From the examples in the book, programming by difference is used to describe an approach where we create a sub class and override some aspect of the super class. It allows us to quickly add new features although it does increase the complexity of the system since we have to add a new class to achieve this.
The next step after this is to refactor the code into a state where the new class’ behaviour is moved elsewhere or the new class is shaped into something that makes more sense.
Feathers also points out that while programming by difference may initially lead to our code being in worse shape it can also allow us to see new abstractions which we can then work towards.
- I like the term ‘normalised hierarchy‘ with respect to the way that we create inheritance hierarchies. Feathers suggests that we should look to create a hierarchy where no class has more than one implementation of a method. i.e. if a class has a concrete implementation of a method then that shouldn’t be overriden.
- Towards the end of the chapter Feathers asks whether it is overkill to create a particular class which is just acting like a properties collection at the time. We discussed this and Cam pointed out that we seem to either end up with ‘complex interactions and simple objects’ or ‘more complicated objects and simple interactions’.
From my observations it seems that we err on the side of not creating enough objects but as Naresh Jain points out it is possible to go too far the other way and end up creating objects just for the sake of it.
Michael Feathers recently linked to a paper titled ‘Testable Java‘ that he’s currently working on which covers some of the ideas from the book but with examples in Java. Worth a look.
In our latest technical book club we covered chapters 6 & 7 – ‘I Don’t Have Much Time And I Have To Change It’ and ‘It Takes Forever To Make A Change’ – of Michael Feathers’ ‘Working Effectively With Legacy
The first chapter discusses various different techniques that we can use to add in new code to a legacy code base. These include:
- Sprout method – create a new method for our new functionality and make a call to it from existing code.
- Sprout class – create a new class for our new functionality and call to that class from existing code.
- Wrap method – rename an existing method; create a new method with the old one’s name; add in the new functionality in the new method & then delegate to the newly named existing method.
- Wrap class – create a new class which takes in the old one in its constructor and then delegates to the original for most methods but also implements new functionality. Typically the decorator pattern.
The second chapter discusses some common problems we may experience while trying to make changes.
These are some of my thoughts and our discussion of these chapters:
- The thing that stood out for me in our discussion was the realisation that applying any of these techniques is probably going to make the code worse in the short term but hopefully lead us to a situation where we can make it better. If we use the ‘sprout class’ technique, for example, then we will end up with a new class which just does our new bit of functionality. Our code is therefore in an inconsistent state.
I would actually prefer to leave the code in an inconsistent state if we are driving to a better solution although I have worked with colleagues who prefer to keep things consistent instead. I can certainly see why you might want to do this on a short running project where there may not be time to make all the changes that you’d like to.
- Tom also pointed out that we need to remember that what we are doing is not design – that can come later on when the code is testable. Using these techniques is an alternative to rewriting the code which often doesn’t work out as well as we’d hope.
- I quite liked the following observation:
Typically, changes cluster in systems. If you are changing it today, chances are, you’ll have a change close by pretty soon
On the projects I’ve worked on there are often lots of areas in the code base that require refactoring but we tend to focus on the area that we’re currently working on as that tends to give us the biggest pay back for the time spent.
Having said that I quite like Fabio’s idea of finding how various items of technical debt fall in terms of the pain they’re causing and the effort it costs to fix them. I wonder if the code we’re working on now would be more likely to fall into the high ‘pain’ areas of that type of matrix.
- Cam pointed out that with the sprout method and sprout class techniques it’s quite cool that Feathers suggests driving their API by making a call to them the from existing method. That way we can see what values the new method will need to take in based on how it will actually be used.
While discussing this Alex pointed out something I hadn’t quite grasped – the techniques described are useful for minimising the amount of change to the original method as well as making the new pieces of code easier to test.
It’s really easy to make mistakes when coding and when there is no safety net to save us we should look to avoid tinkering with that code too much until we’ve created one!
In our latest technical book club we discussed chapters 3,4 and 5 of Michael Feathers’ ‘Working Effectively With Legacy Code‘ – ‘Sensing and Separation’, ‘The Seam Model’ and ‘Tools’.
These are some of my thoughts from our discussion of these chapters:
- Feathers suggests two reasons why we break dependencies when trying to get tests in place – sensing and separation. The former involves the breaking of dependencies in order to get access to the values computed in our code and the latter is necessary so that we can get our code into a test harness to start with.
In my time coding professionally I have experienced difficulties with the former than the latter. I have certainly written code which is bordering impossible to test but it seems like maybe writing code which is difficult to sense against is less problematic than code which we struggle to get into a test harness.
- I really like the idea of seams and enabling points to describe how we can alter the way that our code works by making changes in other places.
Most of the enabling points in the code I’ve worked on are object seams but Halvard and I did make use of a link seam when we wanted to override the behaviour of a specific class in a 3rd party library. We were able to do this by including our own class with the same class signature earlier in the application’s class path.
Ahrum described a time when he had to do something similar to get rid of some noisy warning messages which one of the dependencies was emitting. He was able to verify that nothing important was going on in that particular class before overriding the behaviour with the same trick.
- Dave pointed out that it’s useful to remember that a test is also a client of an object in particular reference to Feathers pointing out that software doesn’t seem to be designed to be easily testable. From what I’ve seen the best way to make code easily testable is to design in that testability when we’re writing it. It’s much more difficult and time consuming to try and do that later on.
- We had some discussion around big tests in terms of the size of test fixtures and individual tests. The consensus seemed to be that when we have an important class where we care a lot about the edge cases then we’ll probably write a large number of tests. On the other hand if our individual test methods are big – which usually means there’s lots of setup required – then it might indicate that a method or class is doing too much.
- The problems in code that these two chapters come generally happen because we are doing too much in single classes instead of separating the responsibilities. Ahrum pointed out that if we had lots of small classes we would have to solve the problem about how to organise these classes effectively instead.
On the projects I’ve worked on we tend to end up with packages which contain a huge number of classes but I haven’t noticed it as being particularly painful so far. Ahrum suggested an alternative approach to grouping objects by the layer they reside in would be to group them by feature instead. I haven’t done this before but it’d be interesting to see if it would make it easier to manage our code.
We’ve decided to go back to reading a book in our technical book club after a few months of discussing different papers and the chosen book is Michael Feathers’ ‘Working Effectively With Legacy Code‘.
We started off by reading the first two chapters titled ‘Changing Software’ and ‘Working with Feedback’ and these are some of my thoughts and our discussion of the chapters:
- Early on Feathers talks about the need to change software in order to add features and fix bugs and while it is certainly necessary to make some changes to code in order to do this we discussed whether there is ever a time that we might look to keep the number of changes we’re making to a minimum.
Tom suggested that if we have good enough tests then we shouldn’t be fearful of making changes at any time. I think we’d look to be more careful about making changes around the time of a release because we don’t have a lot of time to recover if we make a mistake. Perhaps that only suggests that we don’t have good enough tests though!
- Something which I’ve noticed recently is that we often end up with transitionary refactorings in our code base which are attempts at refactorings which haven’t quite been completed yet. I think this is somewhat inevitable if we are making incremental changes to improve the quality of the code base.
The problem with this is that it is sometimes it is not obvious where that refactoring is going and if someone other than the original authors has to work with the code then they can easily drive it in a different direction.
While we were discussing this it reminded me of an idea we read in ‘An agile approach to a legacy system‘. The authors suggest that whenever there is a big refactoring to make the whole team only works on that until it is completed. It would be interesting to see how well this approach would work with a bigger team.
- I really like the definition of unit tests that Feathers uses – tests that give us ‘localised feedback and ‘run fast‘. I wrote a post last year where I tried to break this down further but I think Feathers’ guideline is useful to keep in mind when writing these tests.
It’s easy to end up relying on functional tests which undoubtably have their place but don’t provide the rapid feedback that we need to work effectively.
- We also discussed the need to think twice before creating a technical debt card or adding a ‘TODO’ comment to a piece of code. More often than not these just end up being ignored so it makes sense to check whether you can make the change when you see the problem where possible.
I find TODO comments a symptom of this – a colleague of mine once said that he was annoyed by TODOs, that they’re a statement of ‘I can’t be bothered doing this, I want YOU TODO this”.
It’s certainly not always possible to fix things immediately but my current thinking is it probably makes sense to note that down somewhere that’s not in the code and get back to it as soon as possible. Having said that I was reading Mario Fusco’s entry in ‘97 things every programmer should know‘ earlier and he recommends putting ‘TODO’ comments into the code base to identify areas of code to come back to later. Perhaps it just depends on the team.
- I think the following observation is quite astute:
Breaking down a big class into pieces can be pretty involved work unless you do it a couple of times a week. When you do, it becomes routine. You get better at figuring out what can break and what can’t, and it is much easier to do.
In addition if we don’t do this type of refactoring then those classes increase in size and it becomes even more difficult to do in future.
Tom also pointed out that the more we practice the better we become at identifying good and bad code which allows us to better focus our attention on where we need to make improvements.
In our latest book club we discussed J.B. Rainsberger’s presentation from Agile 2009 titled ‘Integration tests are a scam‘.
These are some of my thoughts and our discussion of the video:
- While talking about how to write interaction tests he suggests that we should only be looking to create interfaces for Domain Driven Design services. If we find ourselves wanting to create interfaces for entities or value objects then we probably have a service wanting to get out. We should try to extract that responsibility out into a service.
I’m intrigued as to how repositories and factories would fit into this picture as I’m not sure whether they count as services, entities or value types. I’ve worked on code bases where we’ve created interfaces for them but I don’t know if that means they would be services or that we did something wrong.
There also seem to be varying schools of thought on whether or not we should tests these types of things directly or whether we should just make use of them in our code and judge their correctness that way.
- Rainsberger’s main gripe seems to be with tests which cover more than one interesting behaviour and he identifies the slow feedback and complexity of test setup as being undesired consequences of this approach.
My feeling is that he was mainly referring to tests written directly from the UI although several colleagues suggested that tests where we call the code directly while using several real objects had the characteristics of the integration tests that Rainsberger dislikes. Ayende is having some success with what he coins ‘system oriented tests‘ which sound similar to the latter so there might be something in this approach.
- Rainsberger’s solution for testing our systems thoroughly is to make use of contract and interaction tests – the former testing the real implementation of services and the latter the way that our objects work together with each other. Essentially making use of mocking as far as I understand.
He also suggests the need for a tool which would be able to indicate that every interaction test we write has a corresponding contract test which sounds quite similar to the NSynthesis tool that a couple of my colleagues have worked on. This tool only tests that we do have a contract test for each mock rather than testing with the exact parameters used in our interaction tests as Rainsberger describes. If I understand this correctly then that would seem to result in a lot of tests!
It is perhaps useful as a rule of thumb to test the happy path of pieces of functionality through integration tests and try and test the edge cases from tests that sit further down.
- I like the idea that acceptance tests are supposed to be clarifying requirements and not testing correctness although it seems to be really easy to cross the line where they do end up verifying the correctness of our application.
Rainsberger has an interesting post on his blog where he goes through the feedback he received from the talk.
I’m not sure if I totally understand contract tests at the moment – there is a post on Rainsberger’s blog which explains it a bit more and my colleague Danilo Sato wrote a comment on a post I wrote about using generic abstract classes for testing suggesting that this approach is similar to the one Rainsberger is advocating.