cswork / libraryOpen practice workspace

Articles

Pair Programming Interview Communication: Drive, Navigate, and Recover from Disagreement

Practise pair programming interview communication with driver and navigator roles, explicit handoffs, and a worked disagreement resolved through a test.

Pair programming interview communication works best when your partner can follow the current decision, influence it, and see what changed after a test. As the driver, make the next small change visible. As the navigator, protect the contract and notice risks the driver may miss. When you disagree, turn the competing assumptions into a question or experiment, then resume work with an explicit decision.

This article is a rehearsal for those interactions, rather than an employer's scoring rubric. The conversations below are original examples; they are not candidate transcripts.

Establish the collaboration contract before the code

Published practice guidance: Birgitta Böckeler and Nina Siessegger's On Pair Programming describes driver and navigator perspectives and regular role changes. The keyboard role handles the immediate implementation; the other perspective tracks broader concerns. That is development guidance, not a guarantee that an interviewer will switch roles with you.

Provider guidance: CoderPad's pair-programming interview article treats pairing as a way to observe a candidate working on a problem with another person. Employer rules differ: use your invitation and the interviewer's opening instructions for permitted tools and the actual format. GitLab's technical interview handbook is one employer-specific reference, not a universal schedule.

No candidate report is used to establish a recurring prompt here. Our preparation recommendation is to make ownership of the next action explicit, even if you remain the driver for the entire interview.

Open with a short working agreement: “I'll start by restating the behaviour, then implement a small slice and run a test. Please interrupt if I've misunderstood the requirement. Would you prefer to navigate while I type, or switch when we reach the first passing case?”

That invitation leaves room for the interviewer to explain their role. They may observe more than participate. They may ask you to critique code while they type. Neither arrangement requires you to force a textbook pairing ritual onto the session.

Then confirm one useful boundary: is the goal a complete feature, a diagnosis, or a demonstrably correct core? If setup is unfamiliar, say which file or command you need to inspect. You can lead the work while asking for information that only your partner has.

Drive by explaining decisions at useful checkpoints

Driving is more than narrating keystrokes. Your partner needs to know which behaviour you are changing, why you chose that location, and how the result will be checked. A useful sentence names all three: “I'll validate the event before updating the ledger, so a rejected event cannot partially change the balance; the first test will compare state before and after rejection.”

You do not need to speak continuously. Announce a bounded thinking pause: “I need a moment to compare the two branches; I'm checking whether either mutates state before validation.” Return with an observation or a next check. Silence becomes difficult to follow when neither its purpose nor its endpoint is clear.

Avoid asking permission for every line. Once the pair agrees on a slice, implement it. Ask again when the contract changes, an irreversible choice appears, or two options have materially different consequences. Repeatedly asking “Is this okay?” without explaining a trade-off transfers your problem-solving responsibility to the interviewer.

Keep the shared view useful. When changing files, name the path and reason. When a test fails, read the relevant assertion before scrolling through a long log. If you discover unrelated cleanup, park it in one sentence and return to the agreed behaviour. Your partner should not have to reconstruct your navigation from cursor movement.

Navigate without becoming a second driver

The navigator's contribution is a concrete observation that improves the next decision. “This might have edge cases” is too broad. “We append the identifier before validating the amount; could a rejected event block a corrected retry?” gives the driver something testable.

If you are navigating, first identify the current slice. Watch its invariant, then inspect the next risk. Offer one concern at a time. Listing five alternative designs while your partner types makes it hard to distinguish an immediate correctness issue from a future improvement.

Use questions when the intent is unclear and direct statements when the evidence is clear. “What should duplicate identifiers mean?” resolves a missing contract. “This branch returns before adding the identifier, so the accepted retry remains possible” reports an observed property. Both are more useful than judging the person writing the code.

In an interview where you do not control the keyboard, remain technically active. Predict the next test result, propose a smaller reproducer, or identify which operation changes state. If the driver takes your suggestion, check the outcome together. A suggestion without verification leaves the pair with a new assumption.

Original rehearsal: disagree about duplicate events

Use this small contract: a ledger starts at zero. Each event has an identifier and a positive integer amount. An accepted identifier changes the balance once. Invalid events do not change the balance or reserve their identifiers. Return the final balance and the identifiers accepted in order.

Fixture: [("a", 5), ("a", 9), ("b", -2), ("b", 4)]. The expected balance is 9, and the accepted identifiers are a, b. The second a is a duplicate. The first b is invalid, so it does not prevent the later valid b.

Here is an original conversation at the first decision point:

Driver: “I'll add every identifier to a set as soon as we see it, then reject invalid amounts.”

Navigator: “Would that mark the invalid b as processed? The contract says invalid events don't reserve identifiers.”

Driver: “I was treating ‘seen’ and ‘accepted’ as the same thing. Let's name the set accepted_ids and add to it after validation.”

Navigator: “I'll trace the two b events while you make that change. The first should leave both state variables untouched.”

The recovery is useful because it names the wrong assumption and the new invariant. It does not end at “you're right.” The navigator also takes a follow-up action, so the conversation returns to shared work.

An implementation for this original contract is:

def apply_events(events):
    accepted_ids = set()
    accepted_order = []
    balance = 0
    for event_id, amount in events:
        if amount <= 0 or event_id in accepted_ids:
            continue
        balance += amount
        accepted_ids.add(event_id)
        accepted_order.append(event_id)
    return balance, accepted_order

The mock assumes well-formed pairs and integer amounts. If the interviewer introduces malformed input, say which validation boundary must expand. Do not quietly invent an exception policy or claim this tiny function is a production payment ledger.

A second disagreement changes the task: “What if a repeated identifier contains a different amount?” The current contract ignores that event. An alternative could reject the whole batch as a conflict. These are different behaviours, not competing coding styles. Ask which one the task requires before adding conflict tracking.

If the new requirement is batch rejection, explain why an incremental mutation needs staging or rollback. The conversation has exposed a technical consequence. Merely adding an error message after earlier mutations would not satisfy an all-or-nothing contract.

Switch roles with a state handoff

A keyboard switch should preserve the reasoning state. Use four facts: what works, the active assumption, the next test, and the unresolved concern. For the ledger exercise, say: “Positive events and duplicates pass. We treat duplicate identifiers as ignored. Next, add the invalid-then-valid retry case. We haven't added malformed-input handling.”

The incoming driver should paraphrase the next action: “I'll add the retry test first, without changing duplicate semantics.” That catches misunderstandings before either person edits code. The outgoing driver becomes navigator and watches the invariant they just described.

Do not use a handoff to deliver a retrospective of every line. A short state summary is easier to act on. If a file or test command matters, include it. If the pair has already agreed on the implementation, avoid reopening the whole design simply because ownership changed.

Role changes are especially useful during practice after a passing test, a reproduced failure, or a clarified requirement. The exact interval is your rehearsal choice. During an interview, fit the switch to the format rather than interrupting a timed exercise on an arbitrary schedule.

Recover when the disagreement remains unresolved

Some disagreements survive the first explanation. Separate three cases. A factual disagreement needs a check. A missing requirement needs clarification. A design trade-off needs an agreed priority. Repeating the same argument louder solves none of them.

For a factual issue, make the smallest example that distinguishes the claims: “If the first event is invalid, I predict the set stays empty. Let's inspect that state.” For a requirement, ask: “Should a conflicting duplicate invalidate earlier accepted events?” For a trade-off, state the constraint: “The simpler scan is enough for this input bound; we can choose indexing if repeated queries are part of the task.”

If the interviewer prefers an approach you would not choose, clarify whether it is a requirement or an invitation to discuss alternatives. Give your concern once with evidence, then implement the agreed path and test it. You can retain a documented limitation without continually undermining the decision.

If you made the error, identify its scope: “My assumption affected when we reserve identifiers. The balance update is otherwise unchanged.” Then repair the affected behaviour and rerun the distinguishing case. If the test disproves the navigator's concern, explain the trace calmly and keep the useful check. Both people can contribute to correctness without being right on every hypothesis.

When time is short, converge explicitly. “We have a working baseline and one remaining conflict-policy question. I'll finish the required cases and state that limitation in the summary.” The aim is an honest, reviewable result. Rushing into a broad redesign can leave neither approach verified.

Rehearse the interaction, then inspect the evidence

Run a mock in which your partner introduces the invalid-then-valid identifier, requests a role switch, and challenges your duplicate policy. Keep those interventions hidden until the session so you must actually listen. If recording is mutually agreed, replay one difficult exchange; otherwise write down what each person said immediately afterward.

Review observable actions: did you restate the concern accurately, change a named assumption, choose a distinguishing test, and resume coding? Check whether the partner could predict your next action. A fluent explanation can still be unhelpful if it never gives the other person room to contribute.

End with behaviour and limits: “The ledger counts each accepted identifier once. Rejected amounts preserve state, and the corrected retry passes. Conflicting duplicate payloads are ignored under today's contract; batch rejection would need a different atomicity design.” That summary connects implementation, evidence, and future work.

The behavioural records help you describe disagreement; the coding records give a partner concrete code to challenge.

Practice questionPairing exercise
Debug and refactor a legacy moduleHand off the failure, hypothesis, and next test before switching roles.
Resolve a Conflict with a Teammate or ManagerState both legitimate concerns before proposing a decision path.
Discuss a Disagreement with a TeammatePractise explaining what evidence changed your view.
Design a circular queue data structureLet the navigator challenge the empty/full invariant.
Reverse Words While Preserving SpacesClarify the output contract before either person types.

Choose one Software Engineer practice question, agree on driver and navigator roles, and rehearse one disagreement that ends in a test and a visible next action.

Sources and Further Reading