The paradox of mocking
When we code from the outside-in in BDD, we start with the layer we know – the UI, often graphical – establish collaborators for the UI, establish collaborators for those classes, and work our way inwards until we run out of collaborators we haven’t coded.
We write examples (tests) for each unit of code, all the way down, and we usually express the collaborations with mocks.
The trouble is, we don’t really know how the class we’re about to code is going to use its collaborators. We can only guess. When I actually come to code the class, I often find that I want to use the collaborator in a different way to the way I expected. When I come to code the collaborator, I might find that it needs more information than its consuming class is giving it to do its job properly.
In this case, I have to back up and change the way that I’m expressing the collaboration in the examples. I change method names and signatures for my collaborator according to the things I’ve learnt from actually using it.
I’d rather do this – work out how I actually want to use a class, then change the descriptions – than be forced to conform to the guesswork that I made.
Yesterday, one of the development team said, “If you’re doing XP, you only have one pair on each story, so if you have four developers, you’ll have two stories in play. It doesn’t make any sense to try to limit it to one.”
I’ve heard some of the Kanban community talk about “swarming” a feature; getting a whole team of, say, 8 developers to take it on and complete it in a short time. I’ve also found that some of them prefer not to split up the features as finely as I do, into very thin vertical slices; instead, the teams work on something marketable.
This makes sense, if you’re going to parcel out chunks of code. The idea of slicing things horizontally goes against most of what I teach about how to write stories – and yet, it does allow a larger team to get something valuable out the door more quickly than BDD’s pure outside-in.
It turns out that guessing what might need to happen further down a stack isn’t much different to guessing what happens with a collaborator, before the class is actually written. Realising this has made me revisit my assumptions about the need to do pure outside-in work. So how can we do this and still call it BDD? How can we gain confidence that we’re writing software that really matters, and doing so efficiently?
I can remember occasions at Thoughtworks where we did this – particularly, finishing off features to hit deadlines at the Guardian. Some of the developers at my current client are also working this way, as are others in the industry. So, here are my suggestions for making this work.
BDD for swarms
- Use scenarios. Having a clear understanding of the feature and a set of scenarios to which the team can work to helps keep everyone focused on the actual behaviour needed. This means it’s less likely that pairs and individuals will write code “just in case”. If in doubt, YAGNI. The scenarios will tell you if you missed something, once all the chunks are integrated.
- Get something working. Start with the happy path or simplest scenario, and integrate this as soon as you can. This will provide a “backbone” for the rest of the scenarios. It also lets the team play through the different scenarios to test their work.
- Mock out collaborators. If you need other classes for end-to-end testing, knock up something really simple or use a mock to allow you to get some feedback. For instance, I make a smiley face appear on my Game of Life exercise when I click the button, just so that I can see that the GUI events are wired up. It takes about 5 minutes to do something like this. Name your simple classes in a way which makes it obvious, so that they don’t get mixed up with the production code and can be safely deleted later.
- Talk to the team. Conversation around what you’re doing will be crucial! If an interface has been defined at the boundary of the code, and you need to change it, go tell the other teams. They’ll be able to adapt to, or at least be aware of, the changes.
- The rest of the team is your customer. When it comes to the name of a method or the value that’s wanted from that method, the “upstream” team – closer to the outside – trump the downstream team. When it comes to the information that’s required to do the job, the downstream team win.
List pets = petStore.getPets(String name);
The upstream team can ask to change the
Set, or the name of the method to
getPetsByName. The downstream team can say, “Hey, we need the type of pet too; we’ve got a hamster, a rabbit and a kitten all called Snowy.”
- Prefer code that’s easy to use over code that’s easy to write. If you’re upstream, trust that the rest of your team will be able to solve the problem you’re about to set for them. Keep pushing the complexity down, and remember: Tell, don’t ask.
- Use examples to drive your code. When you code a module further down the stack without looking to see what’s going to use it, you’re indulging in guesswork. Write some examples of how you expect the consuming class to be using yours, then revisit them when you have more information.
- Write examples to help other people code. Ideally, the upstream team will provide examples of how they want the collaborator to behave to the downstream team. These examples can be built incrementally, as the upstream team come up with features.
- Share code. If the teams check in before the code is finished, their scenarios will fail. If they check in examples which haven’t yet been coded, those examples will fail. This won’t be a problem if no one else is modifying the code base; however, if it’s a subset of a much larger team breaking the build can cause havoc, and the habit of keeping builds green is a good one. Try distributed version control, which will allow a team to check in on USB keys or a temporary space until the code works. (There are techniques for getting, say, Mercurial, to work alongside, say, Subversion – mostly by making each system ignore the other). You could also pass around patch files to keep the code in sync.
- Delete unused code. If at all possible, check the code as it’s being integrated and delete anything which isn’t actually being used or going to be used. This might include things like database columns, layers of abstraction which aren’t actually valuable, etc.
- Look for quick feedback. If you haven’t integrated your code within a few hours, it’s probably wrong. Making the assumption that it’s wrong should help you want to integrate it more frequently.
- The more, the merrier! Look over each other’s shoulders as you pass! There’s nothing wrong with tripling or quadrupling instead of pairing, if it means that a pair is more likely to write the right software later.
Eric Willeke responded to my post with his own perspective on swarming. I very much like the idea of having the skeleton (the simplest scenario?) ready in time for the rest of the team to get on board.