Processes and Practicalities
First, an assumption on team composition
The advice in this article assumes you are working in a team that can commit to at least three working pairs. A typical team might consist of six engineers, a team lead and perhaps cross-functional roles like a tester, designer or product manager.
This may work with larger teams. I haven’t personally tried. If you do, let me know how it turns out! In smaller teams it will be a strain to make it work smoothly. The limited combination of pairs will reduce some of the benefits and constrain your productivity.
Set a pairing schedule
As a team, agree on when you will be pairing and what you will be doing when not pairing. In many of my teams we went all-in and decided we would only write production code while pairing. This required a rigid schedule to maximize pairing time. Pairing started right after stand-up around 9:15am. At 12:00pm we all took an entire hour for lunch then resumed pairing from 1:00pm until 5:00pm. At 5:00 we considered we had put in a solid day’s effort and all went home. In other teams we were less extreme and set pairing hours between 10:00pm and 4:00pm.
Play Ping-Pong — Test Ping Pong
You probably have heard that there are two roles when pairing — the ‘driver’ and the ‘navigator’. The driver types, the navigator keeps an eye out for issues and thinks through the design.
In order to keep both pairs engaged the driver and navigator need to swap roles frequently. One extremely effective way of achieving this, while simultaneously boosting your software quality, is to apply test-driven-development [TDD] and play ‘test ping pong’.
First I will write a test and you will make it pass. Then you write a test and I will make it pass. Not only does this achieve the goal keeping both pairs of hands continuously on the keyboard, it helps you keep each other honest when it comes to writing the tests first.
Talk before coding
Don’t spend all your time just playing ping-pong. The discussion about which test to write next, or how to implement your current task, is critical and may take up as much time as the actual implementation, if not more. Pair Programming is also known as ‘pairing out loud’ and continuous discussion is a sign that it’s working.
Drop the pull-request
Pair programming stands in for your review process, so you don’t need to raise pull-requests for the purposes of reviewing code within your team. But why stop there? I personally would recommend you drop feature branches entirely and embrace trunk-based-development. Describing how to do this safely and effectively requires an entire article of it’s own. I hope one day to share my own experiences, but for now I’ll just leave this link here.
You can pair without trunk based development. For example, by committing regularly back to a feature-branch. But continuous-integration has some fantastic benefits and a strong synchronicity with pair programming. It would be like eating cake without the frosting.
Swap pairs frequently
Within your team try to change up the pairs every couple of days. One person leaves the task, another joins. Try to get a good rotation across all the tasks in flight. This keeps things interesting, irons out knowledge silos, accelerates knowledge transfer and avoids people getting stuck on the same task for extended periods of time. I also cover this in my previous article on building sustainable pace.
Two days is based upon experimentation. Less than two days is disruptive to the flow of the work. More than two days and you start to lose or lessen the benefits of rotating.
Don’t pair on everything…
“Spikes”, technical investigations, performance investigations, incident response, documentation and bathroom breaks are all examples of tasks that do not necessarily need to be paired on. If you have an odd person out, perhaps due to leave or just team numbers, these are good tasks for them to pick up.
An alternative is that you can still assign a ‘pair’ to some tasks but have them spend their time independently, checking back in two or three times a day. The benefit of this approach is that it still fits into the overall team flow without leaving another individual working solo.
…but pair on most things
Most tasks benefit from pairing, including relatively mundane tasks. It is common for experienced teams to start feeling that certain tasks such as adding a cookie-cutter REST end-point or some basic CRUD operations could be done more efficiently without pairing. This may be true if talking purely about speed of implementation but there are other benefits to pairing beside velocity, such efficient code review and sharing exposure to all parts of the code base.
Every time we broke our own rule and let a single person work through a ‘trivial’ task on their own, they invariably went on holiday shortly after finishing it. Then we found a bug (and defects hitting production were incredibly rare in our pair programming teams), and they weren’t there, and fixing the thing took far longer than it should have.
This happened every time we let someone finish a task on their own. It made me suspicious. I came to believe it was not a coincidence. Even an individual applying TDD and having their code reviewed will make more implementation mistakes, and have them slip through, than a pair.
Use ‘over-the-shoulder’ reviews if you can’t pair
In most of my teams, when working solo we would pull someone else over every few commits to talk through the code before pushing. We preferred the inclusiveness and immediacy of this approach over pull-requests. It does mean you are ‘bothering’ another pair quite frequently, but it is also worth noting that pairs are more immune than individuals to interruption. This is because someone can keep typing while their pair is briefly pulled aside. This approach felt like it achieved a better outcome than a pull request. The balance between not blocking the committer and not completely disrupting the reviewer worked well for us.
Rotate between teams occasionally
If you have the luxury of multiple product development teams, do consider swapping team members across them as well. If all your software teams are pairing there is very little overhead to short-term, temporary swaps between teams. The team members swapping join in the pairing and task rotation allowing them to get up to speed and contribute very quickly. If we’re baking a cake, and no-one has licked off the frosting, adding teams swaps is like mirror glaze and tempered chocolate curls. All the benefits you get pairing within your team are magnified when you occasionally pair outside it.
Two keyboards, two mice, two monitors
The ideal pairing setup is two keyboards, two mice and two mirrored monitors plugged into the same machine. This eliminates all friction swapping driver/navigator roles. If you can’t have mirrored monitors the next best solution is still two mice and two keyboards and position your single monitor directly between the pair.
Use Git if possible, configure it for multiple users
GitHub has support for multiple authors, which is useful if you care about tracking individual contributions. If you do not, you can overload the git username and email configuration options. If you scratch around, there are plenty of git aliases to help you do this.
For example, at one company we had a home-grown script ‘git su’, as in switch-user. If Margaret Chan and myself were pairing we would start our session by typing ‘git su sg mc’. This would set the username to be “Margaret Chan and Simon Gerber” and the email-address as “[email protected]”
Standardize your development environment
In order to reduce friction as pairs swap around, having a standardized operating environment is really helpful. Not absolutely necessary, but definitely helpful.
Try to keep the environment as minimal as possible and prefer to use tools like docker for running build dependencies such as databases. Otherwise you run the risk of a ‘runaway SOE’ that becomes the superset of every build-dependency of every project for every team. Maintaining this is overhead you probably do not want or need.
Lightweight configuration management tools like Ansible are your friend, here.
Keep a spare laptop nearby for breakout sessions
You will often find while pairing that you both get stuck. You might need to look up how something is done in a particular framework — or you’re struggling your way through a task and can’t shake the feeling that, “surely someone out there on the internet has a better solution.” For these and many other reasons you will always find it useful to keep a spare laptop nearby.
It is perfectly acceptable while pairing for someone to say, “I think there could be a better way. Do you mind if I do a spot of research?” Of course if you’re doing this all the time you’re not actually pairing, but lowering the barrier to a quick breakout without someone needing to take over the shared screen is a powerful tool.