I used to think there was a lot of value in the concept of pair programming but I think the Pull Request and Code Review model is simply superior. It allows for a lot of the benefits of pair programming but with lower costs. I've always found that even looking over someone's shoulder to help debug something slows to a crawl. It takes more discipline than most engineers have to keep it truly paired.
I like pair programming -- though I personally prefer to do it remotely, believe it or not. I am never comfortable in other people's space (well, my wife being an exception, but I'm not willing to put in as much effort for a coworker ;-) ). Also, I have poor vision and I require a different setup on my computer than most people. Finally, I like being able to turn up or down the volume of the person I'm talking to (really, this is the killer feature for remote pairing).
But you are right that it takes a lot of discipline. Usually when I get a new person, we start with ping-pong (I write a failing test, you make it pass, you write the next failing test, I make it pass, I write the next failing test, etc, etc). This gets you used to the idea that it is a collaboration, not a demonstration.
Normally, switching "drivers" at most every 5 minutes is a good indicator of success. If you go more than 20 minutes with the same "driver", then you will almost always have problems.
I refer to the "non-driving" partner as the "navigator". Imagine a rally car race. The driver is concentrating on keeping the rubber on the downward side and not running into a tree. The navigator is concentrating on what's coming up and giving useful guidance like "3rd gear. left turn". By separating the two tasks, the car can go significantly faster -- especially in rough terrain.
In terms of programming, this usually comes out as descriptions of the next test, advice for refactoring, warning about YAGNI, keeping a todo list, etc. Normally the navigator should be giving short guidance, or asking quick questions. Occasionally the navigator should ask the question, "What are you doing?". If the driver goes silent, then it is up to the navigator to pull them out of their head.
Sometimes the navigator or driver can not explain what they are thinking in words. In those cases, they should take control of the keyboard and sketch their thoughts in code. This should take no more than 5 minutes, generally.
Many people I've worked with have difficult with pair programming. Usually these people have no trouble pairing with me. I don't say that to brag, it's just that it is a lot easier to pair with someone who has done it successfully for a long time (I started doing pair programming around the year 2000).
Most of the problems I see come down to one or more of the following:
- Personal problems between people. There are some people that don't get along (even some people don't get along with me ;-) ) Good programmers can mitigate this problem to a certain degree, but sometimes this requires an "organisational solution". Honestly, this is one of the best parts of pair programming because the hostility is going to come out one way or another. Making it obvious makes it easier to fix.
- Vast differences in approach. Pair programming works dramatically better with TDD IMHO. It is really difficult to get a good rhythm without it (although I'm sure there are ways to do it -- I just don't know what they are). If you are pairing with someone who really dislikes TDD, you are probably going to have problems. This is one of the places where I will usually back off on the pair programming and suggest other kinds of approaches.
- Experiential gaps. It is frustrating when your pair is sitting and looking at a blank screen with no idea what to do. It is equally frustrating when they start running off in a crazy direction because they don't know what they are doing. On the other side, it is often impossible to pair program with someone who charges ahead when you have no idea what's going on. It is embarrassing and frustrating to constantly have to ask them to stop and explain what they are doing. I could (and should) write a whole blog post about how to address these kinds of issues. The main thing is that you must hand over the keyboard every 5 minutes. If you do that, then the problems will become a lot more obvious.
- Schedule conflicts. Get to work at 8:30. Coworker has slept in. Do some admin until 9:30 when the coworker shows up. But you aren't done, so you suggest that you start at 10. Coworker, gets grabbed by someone to look over a design and doesn't get back until 10:30. By then you have been asked to pair on a quick and urgent bug. At 11:00 you are both free. After you get the pleasantries out of the way, you start coding. You get 1 pomodoro done and it's 11:45. Your coworkers are yelling at you to run out to the burrito restaurant before it gets busy. You've worked 3 and a half hours and have done 1 pomodoro :-P Unfortunately you need to be really, really disciplined. Pairing starts on time and finishes on time. If someone is late, you make sure that you start ASAP. This takes a lot of practice.
Finally, wrt to debugging, there are times when pairs should split. Debugging is usually one of them. It's another great reason to remote pair because it is trivial to split and then come back together again. As soon as you find the problem, you shout at the other person (or ping them on the computer) and you go back to pairing. Another time this happens is when you have to read documentation, or do google searches to figure out how to do the next bit.
Having said that, if you spend any non-trivial amount of time debugging, then you are failing at TDD. I say this having written very, very large system before. You virtually never need to debug code that you have TDDed well, because you can write a failing test more easily (the only time you can't is when you can't reproduce the failure, which hopefully will be rare ;-) ). Of course, if you are dealing with legacy code (even if it's your own legacy!) that's of scant help -- so you will have to split to debug. But it should give you at least a small benchmark to see if your TDDing has been effective.
Edit: formating