A while back I got the opportunity to do some coding together with a colleague of mine that works in North Andover. I am situated in Malmö, Sweden, myself so we had a time difference of six hours to overcome. Using tools like NUnit and FIT/Fitnesse we were able to get quite a good flow even if the circumstances under which we had to work were far from optimal.
A somewhat idealized day could look something like this for me:
When I got in to work I got the latest source, built it, and ran the suite of acceptance tests that we had created earlier. By doing that I got a really good overview of what had happened while I was away from the office. The currently failing acceptance test would act as a marker that showed me how far we were into development. I could also quite easily see the progress since the last day. What new tests were passing that weren’t passing yesterday? Were there any changes to the acceptance tests themselves because my colleague had found some changes in the way things ought to work?
When I had reviewed the changes to the acceptance tests, I could take a look at the NUnit tests that had been added or modified during the night. This gave me a good view of what classes had been modified, and in what way. The unit tests acted very well as more low level documentation on what behavior had been worked on during the night. Now I could do a review of the changes made and see if I could see some refactorings that would make things a bit easier to read and make changes to.
Next, I would turn to the currently failing acceptance test. By starting to look at the code that performed the actual test, I could quite easily get a feel for what needed to be done next – make the acceptance test go a little bit further. I could now go on and start developing the next step, using TDD, and hopefully I could make a complete acceptance test pass.
Around 3 pm CET, my colleague would get to work and we could talk a bit on the phone, or using mail, or IM. During this time we could have a quick design session or discuss some other issues that had come up. After that I could go home, and my colleague could take over for the night.
What struck me when doing this was how much communication the tests were able to facilitate, both the acceptance tests and the unit tests. When the other means of communication where crippled, the tests could make up for a lot more than I had expected.
The acceptance tests:
- Provided a progress bar of sorts on how we were doing.
- Gave enough details on what had been done so one could get a quick overview of what had been done since last time.
- Gave a starting point for today’s work. Start implementing the currently failing feature.
The unit tests:
- Provided the details on what had been done since last.
- Provided low level documentation on any new classes that had been created since last.
When most other forms of communication were limited, it dawned on me how much about communication testing really is. Yes, testing is about asserting that your code behaves properly. Yes, TDD is very much a way to get a good, loosely coupled design. But it is also very much about communication. It is therefore important to keep the tests readable and to the point.
I would also like to get the opportunity to try out some long distance pair programming at some point as well, and see how that goes.