The many sides of pair programming and the importance of deliberate practice of it
--
Pairing can be a very triggering topic, so I’ll start by stating my bias: I am an advocate of pair programming; I generally enjoy it but more importantly, I think it results in better software delivery. I should also state that I’ve actually only ever worked as a developer in teams that have done the majority of work paired (5 teams across 2 companies)… I appreciate this puts me in a minority position in the industry. I’ll try and provide scientific backing throughout the post, so that it’s not just my limited personal anecdotal experience.
I’ll start by giving a brief intro to pair programming and then relating a shifting pairing experience I had recently, before going on to talk about some criticisms of pairing and my responses to these, provide a checklist we often use for pairing and then some musings. This is quite a long read, feel free to skip to the end for some key takeaways (but then come back and read the rest 🙂 ).
Pairing is two people working on the same bit of work at the same time, and in its most common form involves two developers sat at the same machine working on the same code. One person is the “driver” and they control the machine itself; writing out the code and being concerned with the “small picture” details e.g. syntax. The other person is the “navigator” and they tend to navigate through the code design details; they take a “big picture” view of things. These tend not to be rigid roles, and are very context dependent. There are other ways to split the work e.g. “ping pong-ing”: one person writes a failing test, the other then writes the simplest code to make it pass and then writes the next failing test; repeat. The general idea being that you have a very short feedback loop between decisions on code design. Within a team you will tend to “rotate” pairs every so often e.g. each day, this tends to involve one person staying on the piece of work and the other switching out for someone else in the team to join in their place.
Recently I was pairing with a colleague, Nat, more junior than me, who I’ve paired with often before and who I have a good relationship with. The first day Nat started leading and I made a conscious decision to give her more of the reigns for the day and to lean the focus more towards learning/ mentoring; this consisted of me being in control less, and providing hints more than solutions. The next day we shifted back to a more traditional pairing dynamics, with a more even split between driving duties & discussions on solutions. I think we did test/ implementation ping-pong: one person writing a test, the next person making it pass in the simplest way and then writing the next test; repeat. This was a good example of pairing not being one thing, it can shift depending on what the aim is.
It would have been better to have been more explicit about what we wanted to achieve on each of the days. We shifted between the two pairing styles quite naturally during the two days, this might be down to us having paired a fair amount already (one of the many benefits of constant pairing in a stable team, building up the psychological safety) but I was aware on the first day that it was more tiring for her and that I didn’t know whether she was in the mindset for it. Being explicit at the beginning of the day has multiple benefits: you can focus on it more/ have buy-in if you both know what you’re planning for the day, if a learning/ mentoring day then one person doesn’t feel extra pressure because things are going slower, you can make sure that both people are in the right mindset for the pairing dynamic. Thankfully Nat fed back in our team feedback session that she appreciated the day and the extra time we took to focus on learning. The decision to work this way was made easier because there was less “pressure” on delivery at this point, but this shouldn’t be needed to take the time to focus on learning.
Particularly on the “learning focused” day, the uneven workload when pairing like this can be particularly tiring for the person driving, so be conscious of taking breaks regularly rather than just when you feel you personally need to. It can be good to set a regular interval for the breaks so that you don’t forget and so the other person doesn’t feel they have to request one. For similar reasons, this is dependent on each person’s energy levels for the day. Another way we could have split the work would be for me to drive/ type but just to implement what Nat says — different dynamic & learning experience, takes away the pressure of the person learning having to type but means they don’t build up muscle memory by doing it themselves.
Common criticisms of pairing
It’s stressful/ tiring
Correct… I’ll be open, even now I can still find pairing stressful, especially with new people… imposter syndrome is very much a thing and getting used to someone takes time. This can be improved by increasing psychological safety within the team (which has huge benefits for the team generally) but it takes constant effort; it takes time to build but can be destroyed in a fraction of that time. Also, adding/ removing just 1 person from a team effectively makes it a new team and so the safety starts at 0 again, and although a strong previous base can make it faster to build again, be extra aware as soon as team structure changes to not lose momentum.
All that being said, I don’t think it means you shouldn’t pair, I believe the benefits outweigh this downside, you just need to be conscious/ appreciative of this. There are also a number of things you can do to mitigate some of this:
- Regular breaks — this may seem like wasted time, but pairing is intense, you’ll be more productive overall
- Other team tasks/ activities that don’t require pairing — research, spikes (afterwards throw away spike and pair on actual solution), support tasks, learning, blogging
- It gets easier after practice and building psychological safety in the team (this has other benefits to the team as well); although it’ll likely always still be tiring
- Following on from previous point, being open with pair around mental energy fluctuations during the day & on different days
Opportunities to fail
Another common criticism is that you don’t have a chance to fail in a friendly way, or you feel pressure to not appear stupid in front of your pair. In my opinion the “chance to fail on your own/ it’s good to hit your head against a brick wall sometimes” criticism is actually one of the most valid ones, but even there I think there are other ways of achieving this without giving up the benefits of pairing on the vast majority (if not all) production code e.g. spikes/ giving time for personal projects/ share leading on particular strands of work.
Differing levels of experience/ context
There are varying criticisms that come from this but some are: someone gets bored, or someone loses track; Junior/ senior pair is a waste of the senior person’s time; Two junior people together is dangerous; Two senior people together is a waste
I think some of this relies on the assumption that learning has a one-way benefit, whereas in my experience, both people get a huge amount out of it; having your assumptions questioned can be really beneficial in making you question why you actually do things in a particular way and if that’s actually the best way. Teaching someone also forces you to really understand a topic, which helps your own development. Also, being able to explain something to different types of people helps you to communicate with other roles involved e.g PMs. “Experience” is also multifaceted and context dependent e.g. different technologies, domains, someone may have more experience at a technology but be newer to the domain. There are also different outcomes you can focus on from different pairing combinations — this is good, particularly if done consciously. Dan North talks about this a little in his Dreyfus squared model https://www.youtube.com/watch?v=lvs7VEsQzKY.
Different learning/ processing speeds
People are different and diversity of thought has been shown to be important in a multitude of studies, different processing speeds have different positives/ negatives and mixing these can result in some tension but handled with empathy can result in a healthy tension that results in better solutions. Something that can help is that you don’t have to constantly be sat together… go away and research independently/ spike/ think and then come back together. It’s important to build up awareness & empathy of different styles over repeated pairings.
The misconception that pairing is for knowledge transfer only
Often the benefit that gets talked about with pairing is that it’s there for silo breakdown and learning; both “bus factor” and domain/ technical learning for people less familiar. Although I do think these are useful, I actually view knowledge transfer as a surprisingly small part of the benefit to pairing.
Some other benefits of pairing:
- Fast, instantaneous, feedback on code (compared to code review). A higher number of people buy in to the fast feedback benefit of TDD & releasing frequently, pairing is another side of this
- Fewer bugs as you have two eyes on the code and thinking about edge cases
- Faster delivery of story/ feature (traded off against possibly slightly fewer features, although I’m not sure that’s even the case) as less likely to get stuck
- Better code design as you can chat about different ideas and their tradeoffs on the spot, with the most context
- More consistent code in team
- More understandable code by other people/ future you; having to articulate reasons means you are less likely bake your current pre-existing biases/ context in to the code
- Team connection
- More consistent delivery speed; less likely to get stuck for extended periods of time, fluctuations in energy levels get balanced out
- Forces individual biases to the surface, which can increase the benefits of a diverse team, as long as you provide opportunities for the team to address them.
- Team code ownership: when one person writes some code, there is a bias to feel like they own it, which can result in blaming someone for a bug in it, make criticisms more personal, or a reluctance for others to change it. Having multiple people write the code helps alleviate some of this “preciousness”.
It could be argued that you can get a number of these benefits from code reviews, but in my limited experience and from chatting to others, you get them to a much lesser extent and at an extended feedback loop. It’s easy to fall in to the trap of skim reading code reviews as proper ones take a large amount of time, but this is a dangerous trap. Proper code reviews take time to understand the context and thought processes that went in to decisions and as they are often done at the end of a story, there is a large amount of code to review. The back and forth of the extended feedback loop adds an extra overhead of constant context switching. Waiting for someone to review code also encourages larger change sets, less frequent deploys and reliance on branching… in my opinion these all add to the chance of larger bugs that are harder to track down, more time and annoyance spent merging. Most code consists of trade-offs and the nuance of these can be lost during a review, particularly if scheduling “face-to-face” reviews is hard and the default is text comments on a pull request. Text comments on a pull request also lose the emotional nuance of conversation, this can cause comments to be perceived incorrectly and it’s easy to fall into the trap of them sounding passive aggressive.
“They found that for a development-time cost of about 15%, pair programming improves design quality, reduces defects, reduces staffing risk, enhances technical skills, improves team communications and is considered more enjoyable at statistically significant levels.” — The Costs and Benefits of Pair Programming; Alistair Cockburn, Laurie Williams https://collaboration.csc.ncsu.edu/laurie/Papers/XPSardinia.PDF
Tuple have put together a nice summary of some of the research in to pairing https://tuple.app/pair-programming-guide/scientific-research-into-pair-programming (disclaimer: Tuple offer a remote pairing product and so likely to have the same, if not greater, bias to positive research than myself)
Less flexible working day e.g. having to work similar hours/ no remote work
This is one of the trickier ones. Tools for remote pairing are getting much better (screen sharing through Slack/ Zoom, VSCode, Tuple), but fundamentally they still rely on two people being sat at their computers at the same time, this can be a blocker for teams across multiple time zones. I have no experience with this, but I wonder whether regular overlapping blocks of time to pair would enable at least some of the benefits, without waiting for a code review on pull request when they feature is done. Please let me know if you have experience of being in this situation and what you’ve found.
Checklist
We came up with the below checklist as a way to code our agreed working practices, although we could do better at explicitly using them at the start of the pairing session both as a reminder to be more explicit with some of the decisions that vary day to day, but also as a ritual to get in to a pairing mindset. (Dave Snowden talks about the power of rituals in cognitive activation: https://youtu.be/r8T7wlJ8DgM?t=1525)
Musings
My gut feel is some of the reluctance to pairing is previous negative experiences where it hasn’t been treated as a skill that takes practice.
Pairing is a skill, only practicing it on hard things isn’t the best time to practice, you want to build up the skill in easy situations so that it is more habitual when you really need it. It needs to be deliberate practice (provide link/ context), just sitting on the same machine doesn’t count; you won’t get better, & you’ll miss out on many of the benefits. Although some of the latest literature on deliberate practice indicates a reduction in its influence on elite performance compared to some of the original studies, this is relative to other factors that result in the differences in performance between performers e.g. genetics, not the importance of deliberate practice itself in improving your own skill level. The benefits of deliberate practice over “basic practice” is the more relevant factor for individuals/ teams improving their pair programming as a skill e.g. if you accept that pair programming is beneficial, then getting better at pair programming has performance increases for team delivering products, and so deliberate practice is vital.
It also feels like some of this comes from a tension between what’s best for the product/ company and what’s best for the individual… these don’t have to be completely mutually exclusive but if one of the benefits to pairing less is the flexibility it provides (and the multiple benefits this gives, including hiring/ retaining people), then this is traded off against the belief that pairing results in better code/ products and benefits the company more directly.
I’m coming round to the idea of rotating pairs less frequently; switching pairs every day is great for knowledge sharing on a story, but as I’ve mentioned through the post, knowledge sharing is actually one of the smaller benefits. I actually think the other benefits mentioned earlier in the article benefit from slightly stickier pairs. You get time to build up closer working relationship with your pair, which benefits team relationships; you maintain more context on story, which means you spend less time context shifting/ getting up to speed; you can get in to deeper discussions about the feature and code design because there feels like less of a time pressure. The question of when to rotate does then become a little trickier as stories will start/ stop at different times, so when do you rotate? This seems to work out fairly organically around other things going on e.g. research days/ meetings/ time off, certainly once you get used to pairing as a team, it may be trickier at the beginning. I do still think that you probably want to switch pairs, or add someone to create a mob, on a story if it takes more than a few days; in my opinion, the benefits of having more points of view on things that are more complex outweighs the downsides.
Takeaways
- There is more to pairing than knowledge transfer
- It’s a skill, practice deliberately
- Tension between what’s best for individual (e.g. flexible working) vs what’s best for the team/ product
- Yes, pairing is tiring, particularly at the beginning. This doesn’t mean you shouldn’t do it, it means you should take that into account with breaks & emotional awareness (easier said than done, see above point)
Please leave comments (both on pair programming & the writing generally). Although I am an advocate of pair programming, I’m also a firm believer in not having anything cargo culted and that we should be constantly trying to challenge/ question and improve our working practices, as long as this is happening on a level playing field of understanding the reasons behind things, rather than a straw-manned/ misunderstood argument based on anecdotal experiences.
Further reading
For more detail about the reasons behind pairing, and other XP practices, read Extreme Programming Explained by Kent Beck
Studies on deliberate practice:
- Deliberate practice and acquisition of expert performance: a general overview by Ericsson KA
- Facing facts about deliberate practice by Hambrick et al
- The Relationship Between Deliberate Practice and Performance in Sports: A Meta-Analysis by Macnamara et al
Badass: Making user awesome is a great book on general skill acquisition (http://shop.oreilly.com/product/0636920036593.do) and conference talk by her (https://www.youtube.com/watch?v=r4dNaflEgP4)
Project Aristotle @ Google https://www.nytimes.com/2016/02/28/magazine/what-google-learned-from-its-quest-to-build-the-perfect-team.html
The many sides of pair programming and the importance of deliberate practice