A few years ago I ran into a tester at a conference that was moving away from testing work. He was working for a company that had their developers pairing for nearly every code change. What he described seemed like magic. He told me that two developers work on one change until it was done. When he said done, he actually meant done, as in ready to ship. Not some weird internal definition of the word that really means ready to hand this piece of work to some other group so they can do their thing in isolation.
I finally had the opportunity to get some experience in this environment and have some novice observations that I’d like to share.
My current client pairs about 95% of the time. There is one developer on call that is in and out of a pair depending on what is happening in production. And then there are leads that spend a little more time in meetings so they aren’t always available consistently to pair with another developer. Everyone else on the team is sitting at side by side desks sharing a VIM session or IDE.
The last couple of weeks of work for me have involved fairly major refactors. There is an area of our product that was written a while ago that we want to be more readable, maintainable, and performant. Everyone has bits of software exactly like this. You open up a file, start reading, and say “what on earth is this”. We are fixing that.
In the past when I have seen these major refactors, the developers either have a group planning meeting to talk about solutions or look up the ivory tower for advice from their architect. One solution is chosen, and then the developer moves forward in that direction. It might not be the optimal solution, or the right solution right now, but it is the one that got selected.
We did something different. We have a couple of developers that are crafts-people types, and have a very good understanding of the product domaine, but no architect to drive code in a particular direction. One of the leads, another developer and I worked on this change. We started by talking about options, and writing some tests and code to see what would happen. Test driving isn’t really related to pairing, but it is integral to this sort of work in my opinion. Our first few solutions *felt* wrong for a variety of reasons. Some were refactoring code out where it didn’t belong, some tests could have been at a better level in the technology stack, some code got written that we didn’t know how to test. Every bit of that exploratory solution building was backed out and gave us guidance on what we actually wanted to do with this change.
Once we decided on a path, we started with a test. The flow was a little test, a little product code, build a new container and explore the change. Writing the product code was probably the smallest time segment of the refactor. Code was sandwiched by discussion and exploration, and heavy testing. The change was ready to go to production once we merged with the head branch and did some cursory testing there.
This week and a half of work or so involved multiple teams, multiple starts on different solutions, and lots of collaborative testing and development, but it was one of the smoothest refactors I have worked on. I think this is heavily related to allowing developers build some code, and then fearlessly delete it in a way that I don’t see when people work independently on a specific path.