I have done somewhere in the range of 150 phone screens this year. Doubling your engineering organization means talking to a lot of people, and I mean a lot. I talk to them about their work history, their software philosophies, and the processes that help enable high quality software delivery. This regularly turns to processes to help enable a collaborative programming paradigm, and ultimately pairing. Inevitably I hear things like, “But, you're fully remote!” and “How would you share a keyboard?”
These types of questions always confuse me. I'm someone who has never worked in a co-located team, and has seen pairing be successful in an engineering department that is majority remote. Through my conversations, it has become apparent that there is a contingent of developers out there that think pairing is effective, but cannot be done on a remote team. So I thought it would be useful to share the tips and tricks that have allowed pairing to be successful for the Plans and Pricing Team at CircleCI, a 100% remote team that pairs (almost) 100% of the time.
The thing that is most often brought up as an inhibitor to remote pairing is tooling. “How are you supposed to pair without 2 keyboards hooked up to a monitor?” people ask me. Very easily, as it turns out.
When I asked our Plans and Pricing Team what tools they used to be effective, the answer was pretty simple: mostly screen sharing, and sometimes tmate for terminal sharing. My favorite response to this question was “Wait, what would you have beyond screen sharing? Like, full AR experiences? Lol.”
The team is able to pair effectively by having one person code while the other follows along, gives advice, discusses implementations, looks stuff up, and is an engaged co-pilot. Screen sharing is a more than adequate tool to enable this.
Tmate can work well to enable remote terminal sharing, but it isn’t very useful for browser development, requires each participant to be familiar with the others environment, and excludes people who use IDEs like IntelliJ or Cursive. So, while it can be useful in some situations, as a team with vim, emacs, and Cursive users that does a lot of frontend work, its utility ends up being fairly limited.
After tooling, the thing I was most curious about was the paradigm that made pairing most effective. Was it driver <> navigator? Does one person write tests, and the other make them pass? The answer was, once again, more straightforward than that: do what makes sense for the pair.
Most of the time, it is just a conversation. A back-and-forth between two engaged teammates about the best path forward, the most advantageous way to name a function, whether or not to refactor. Sometimes the pairs do TDD, sometimes they don’t. Sometimes one person drives while the other navigates, and sometimes it is more of a learning opportunity as the more experienced person shows the other around the code base, helping them gain context and familiarity. It's about what works best for that specific pair.
Overall, there was only one thing I saw consistently from all the answers I received: it's about engagement. Pairing is not about one person coding while the other browses Reddit, or responds to Slack. It is about two people working together collaboratively to solve a problem. As long as both of those people are engaged in solving that problem, the specific paradigm they utilize to do that is far less important than the collaborative environment they are creating.
However, even with great intentions, and a team highly motivated to pair and create a collaborative environment, we have still experienced some wrinkles and issues that forced us to come up with creative solutions.
One of the biggest blockers to pairing at a fully remote organization is dealing with timezones. For about 6 months the Plans Team had people in timezones UTC+7, UTC+8, and UTC-9, for a grand total of a 17 hour difference. However, the team still managed to pair. How did they do this?
Each day, the team would use a handoff process between our teammates in the US and our teammate in Tokyo. The two would pair for the last few hours of the West Coast’s day, transfering context to our Japanese coworker. After the handoff, he would work for the rest of his day, pushing up his branch and leaving detailed notes at the end. The next morning, the pair would pick up where he left off, continuing the work.
This practice allowed the team to continue to have a highly collaborative paradigm even across oceans.
An issue the team experienced at one point was uneven pairing across the team. This was caused by a combination of not knowing who was free for pairing, as well as “pair marriages,” where two people continuously pair together ticket after ticket. To prevent this, the team implemented pair randomization.
At the beginning of each day, during standup, the team picks random pairs through a variety of processes such as automated scripts and a “wheel of fortune.” The team follows some constraints to ensure this is not disruptive:
- At least one person has to stay consistent per ticket, so context carries from one day to the next.
- If there is a good reason to not change the pair, the team doesn’t. An example of this is research tickets, where certain people have the context necessary to complete the task.
Pairs then coordinate to create a schedule that makes sense for them. This has lowered the barrier to pairing, and increased knowledge-sharing across the team.
This also has some fun side effects, like the pairing scripts the teams used pictured below:
Being a remote engineering organization doesn’t mean you have to be an organization of people working alone. Pairing can be just as effective in a remote setting as in a co-located one, and has some added benefits like combating social isolation that co-located pairing does not. In the end, if you want to make something work, it just takes buy-in and some creative thinking. If you want to make remote pairing work, hopefully these practices will provide you a helpful springboard.