Pair programming with people who think differently

Why the best pair-programming session is with someone whose brain works differently from yours. And the techniques that turn 'I'll drive' into 'we both got smarter'.

The best pair-programming session of my career was with a backend engineer named Andrei, on a Tuesday afternoon, debugging an Airflow DAG that was producing the wrong totals downstream. We sat for about three hours and found two bugs, one of them mine, one of them in a Postgres window function that nobody on the team had really understood.

What made the session unusually good wasn’t the bugs. It was that Andrei thinks completely differently from me. He starts from the data, looks at rows, forms a hypothesis. I start from the schema, build a mental model, then check the data against it. Neither approach is wrong. But his “wait, look at this row” kept catching things my model assumed away, and my “the schema says this should never be null” kept catching things his rows-first approach hadn’t generalised. Three hours later we were both better at our jobs.

Pair programming with someone who thinks like you is fine. Pair programming with someone whose mental model is different is where you actually grow. This post is mostly about the second kind, and the small techniques that turn “I’ll drive, you watch” into “we both got smarter”.

Driver, navigator, and what “narrating” actually means

The classic frame for pair programming is driver and navigator. The driver has the keyboard. The navigator’s job is to think a level above the keystrokes: where are we going, what are we missing, what’s the next thing to check. If both of you are looking at the same line, you are not pairing, you are co-staring. The whole point of two brains is that they’re operating at slightly different zoom levels.

The hardest habit to build is narrating your thinking out loud. The driver should be muttering things like, “okay, I’m going to add a filter here, because the rows we’re seeing have nulls in the join key”. The navigator should be saying, “before you do that, can we print out what’s actually in the join key? I want to make sure we know what we’re filtering”. It feels awkward the first few times. It is also the single most important thing distinguishing a useful pair from two people in the same Zoom.

Most bugs live in the gap between what you think the code does and what it actually does. When the driver says, “I’m filtering the nulls because they’re invalid”, the navigator’s brain pings on “wait, are they invalid, or just unhandled?”, and that ping is exactly the catch you wanted. Without the narration, the filter just lands silently in the code, and the bug ships.

If either of you has been quiet for more than two or three minutes, something is broken. The driver has stopped thinking out loud, or the navigator has zoned out. Both are fixable, but only if you notice.

Swap the keyboard, often

The default I aim for is: swap roles every twenty-five minutes. Pomodoro length, by coincidence or not. After twenty-five minutes at the keyboard, the driver’s brain has narrowed: they’re deep in the syntax, tracking the file structure, remembering which tab the docs are open in. They have lost altitude. The navigator, if they’ve been doing their job, is still at altitude. So swap.

I have been in pair sessions where one person drove for two hours straight, and they were almost always a waste, even when productive-looking. The non-driver checks out. The driver gets tunnel vision. The cognitive load gets carried by one brain, with the other a polite witness. That’s not pairing.

Twenty-five minutes is not magic. Some pairs swap every fifteen, some every forty. The principle is: swap before either of you settles in. The first few times you’ll feel like you’re interrupting flow. You’re not. The flow you’d be interrupting is exactly the kind that drifts off-target without anyone noticing.

Remote pairing without burning out

Remote pairing has failure modes that aren’t obvious until you’ve felt them. The biggest is camera-on, full-Zoom pairing. It looks collaborative. It is exhausting. Both people are watching each other’s faces and the code, in different parts of the screen, while making sure they look engaged. After ninety minutes you are wrecked, and you got maybe forty-five minutes of actual pairing done.

The remote setup that has worked best for me is screen-share plus voice, no video. The shared screen is the workspace. The voice is the thinking. Your brain stops running the “do I look engaged” subprocess and spends the energy on the code. If you need the social connection part, do it for the first five minutes, then drop video and pair properly.

Tools that have held up for me: VS Code Live Share is the gold standard for code-level pairing. Both cursors, both keyboards, shared terminal. ssh plus tmux is the old-school option, ugly but unbeatable when the workflow is mostly terminal. Zed has built-in collaborative editing that is genuinely smooth and feels closer to “we are both really here” than the alternatives.

What I would not recommend, despite a lot of teams defaulting to it: a Zoom call where one person shares their screen and the other watches. The non-sharing person cannot type or annotate. That is a code review with bad ergonomics, not a pair session.

When pairing is the wrong tool

Pair programming costs two engineers’ attention to produce one stream of code. For some work that is a great trade. For others it is a waste, and pretending otherwise is how teams end up exhausted and slightly resentful.

What pairs well: tricky debugging where the bug is in a model gap, code in a domain one of you knows and the other needs to learn, gnarly refactors where two pairs of eyes catch ten times more than one, and onboarding where the goal is partly the code and partly the knowledge transfer.

What doesn’t: routine implementation of a clear ticket, anything where one of you is just going to type while the other reads Slack, work that’s primarily research and reading, and most yak shaving. Pair programming on yak shaving is a way to make two people grumpy about a config file.

There is also a real cost to pairing too much. I have seen teams that pair-programmed everything, on principle, and the engineers were burned out within a quarter. A reasonable rhythm is one or two pair sessions a day, with the rest of the day available for solo work. The principle that pairing is a feature, not a default mode, has held up.

Pairing across seniority, including the weird direction

The cliché about pair programming is that the senior teaches the junior. That happens. Less obviously, the junior teaches the senior surprisingly often, and pair sessions where you’re alert to that direction are some of the most productive you’ll have.

Juniors haven’t absorbed all the conventions of the codebase. So when they ask “wait, why does it work this way?”, they’re often pointing at accidental complexity the senior has stopped seeing. “Because we’ve always done it that way” is sometimes a fair answer. More often it’s a flag, and the senior, if paying attention, goes, “actually, why does it work this way? Hold on”. A piece of the codebase gets fixed that nobody had noticed needed fixing.

Juniors also bring tools and reflexes that aren’t in the senior’s hands. New language features, type-checker tricks, ways of structuring tests. I have learned more about modern Python typing from juniors than from any documentation. A pair session is the cheapest channel I know for that knowledge to flow upward.

The trick, if you are the senior, is to be genuinely open to it. Ask their opinion before you give yours. Take their suggestions seriously enough to try them even when you “know” they won’t work. Saying “huh, I didn’t know about that, show me again” out loud tells the junior that pairing is a real exchange, not a one-way review.

Trying the other person’s idea first

The single hardest pair-programming habit I’ve had to build is this: when we disagree, try the other person’s idea first.

This is counterintuitive. Your idea is, by definition, the one you currently believe is right. The answer is that “trying it” is much faster than “arguing about it”. Five minutes of running their approach typically resolves the disagreement without anyone having to win or lose. Either it works, in which case great, or it doesn’t, in which case you have a concrete reason to try yours, and the conversation is grounded in evidence instead of opinion.

The pattern I’ve settled into: “okay, let’s try yours first, give me five minutes”. Either way the conversation moves on, and the other person feels their idea got a fair test. People who feel their ideas get tested fairly are willing to push back on you, which is exactly the dynamic you want from a pair partner.

The inverse anti-pattern, which has wrecked a lot of pair sessions I’ve seen, is the senior version of “let’s just do it my way, trust me”. You’ll save twenty minutes today and pay back two hours of resentment over the next month. Try the other person’s idea. The cost is small. The trust dividend compounds.

Takeaway

The pair sessions that have made me a better engineer were almost all with people who didn’t think like I do. The friction was the point. The mechanics around it are mundane: narrate your thinking, swap the keyboard often, drop the camera on remote calls, treat juniors as people who can teach you, and try the other person’s idea before you argue about it. None of this is hard. It just requires the small humility of saying “let’s try yours first” instead of “trust me”. The dividend, paid in fewer bugs and faster learning, has been the largest single contributor to whatever I’ve gotten good at.

Search