Can pair programming be done in a way that is compatible with async communication?
Pair programming is described by the original c2 wiki as a process in which “two engineers participate in one development effort at one workstation”. It would seem the process is inherently synchronous, at least as originally described and practiced.
I experimented with pair programming at my first industrial programming job at Morgan Stanley. It was 2006-2008 and two fads were happening in parallel: “agile” software management techniques and “extreme programming”, with a particular emphasis on test-driven development with Java.
I occasionally found pair programming to be effective, but noticed my results varied wildly depending on the engineer I paired with and the problem we worked on. Some people really enjoyed the “brain swarming” of having two heads attack a problem. Other people found it cumbersome and interruptive. Some problems seemed so indivisible that it always ended up that one person drove, and the other person merely watched. In the end, I couldn’t really say whether I benefited from it, despite many hours of experimentation.
When I started my own startup as a fully distributed team, I noticed, about a year in, that I hadn’t done any pair programming with my teammates. Partly, this stemmed from the lack of comfort around tooling — it felt less easy to do it over Skype and chat than it would be in-person. But, I also realized that it was due to some of the work rules we created for our technical culture: we were aiming for asynchronous workflows, and pair programming seemed to be at odds with that.
Recently, I watched Rich Hickey’s excellent talk on software design, entitled “Design, Composition, and Performance”. He draws a parallel between software design, composition, and performance to the same terms used in music — namely, instrument design, score composition, and player performance.
He suggests at one point that pair programming, as traditionally done, doesn’t make much sense to him, in the same way two players playing the same instrument rarely makes sense. Instead, he suggests that the only way in which pair programming would work well is something closer to a “jam session” — where two players each play their own instrument, in parallel and feeding off the energy of each other.
I think he hit the nail on the head.
Indeed, the best “pair programming” sessions I ever had were not when we were staring at the same editor, but when we were working on the same problem that was decomposed into two subproblems that we could work on, in parallel, in separate editors. Designs of my colleague could then be easily borrowed, adapted, and re-applied to problems in my editor. And my colleague could quickly provide design feedback (and perhaps, real-world use) for constructs I wrote in my editor. A true programming “jam session”.
Let’s read that original definition of pair programming again: “two engineers participate in one development effort at one workstation”. Hickey suggests that perhaps the true purpose of the original practice is about stopping one of the engineers from typing into the editor, to give him or her the time and space to design. Maybe we are so obsessed with coding (“performance”), that we don’t typically create time for the other two equally important parts of software creation, “design” and “composition”. Maybe pair programming is not so much about a performance-enhancing technique, as much as it is a mechanism to create some time for the other person to focus on design/composition. That’s certainly an interesting thought.
I have similar thoughts about test-driven development. Though the stated purpose of TDD is to make more robust, bug-free code, I think the true purpose is to “create time for tests, which is often scheduled last and thus not at all”. Pair programming’s stated purpose may be “dual-brain code editing”, but its true purpose may be “create time for design, which is often not scheduled at all”.
I’ve gone >5 years without pair programming, and work with a team that mostly finds the technique bothersome and interruptive. Now I think I know why. On my team, we create plenty of time for design. Indeed, the whole async way of working is specifically about creating that kind of breathing room, while also creating time for focused performance in a state of flow.
I recently worked with a colleague in a “async pair programming” setting, and found it produced good results. I’ve been trying to understand why. Now I think I know: we were jamming, in parallel, in our own editors, and this gave us each the time to do design/composition of our own — as well as performances of our own. We mixed sync and async work time, and played each to its strength.
The workflow went something like this:
- synchronously lay out a plan, or rough design sketch
- asynchronously hack on a couple of prototypes, a few functions and classes
- synchronously discuss the prototypes and pro’s and con’s
- asynchronously iterate and refine them
- synchronously discuss a plan for splitting up the “performance”
- asynchronously code on the independent pieces
- synchronously integrate the results
- asynchronously review each the merged code and polish further
We did the async portions in separate editors (at our own workstations), often at separate times, but made each other available for quick (audio) interruptions during the final integration phase. This is the first time direct pair collaboration on code unequivocally seemed to work well for me, and so I’d like to reproduce the results. At the very least, it changed my mind about pair programming. Yes, two heads at one keyboard may be silly.
But, two heads at two keyboards with one goal may be just right for many problems.