Prepare for a pair programming interview by practicing a short cycle: agree on the next observable result, implement it, check it together, and explain what changes next. Make your reasoning accessible while still producing correct, readable code; neither constant talking nor a finished answer alone guarantees a pass.
TL;DR: Confirm the working rules and one concrete input/output example before coding. Explain decisions rather than keystrokes. Pause briefly when you need to think, then report what you concluded. Treat hints as information, test the risky assumption first, and leave the interviewer with an accurate account of what works and what remains unfinished.
Establish how the two of you will work
A pairing invitation can mean several different exercises. You might build a small feature in an existing repository, repair a failing test, or solve a standalone problem with an interviewer who mostly observes. Ask the recruiter about the format beforehand. During the session, establish whether the interviewer will write code too or expects you to keep the keyboard throughout.
Sophie DeBenedetto's first-person Pair Programming for Interviewees emphasizes clarifying the assignment, checking the approach with your partner, and communicating during implementation. Those are useful preparation habits. They are not a universal scoring formula: employers differ in how they assess technical depth, progress, and collaboration.
Before starting the task, settle these practical details:
- Which language, editor, and test command are available?
- May you consult documentation, and what assistance is permitted?
- Should you begin with tests, an implementation, or a discussion of alternatives?
- How much of the session is available for coding and final review?
Keep this conversation short. You are arranging a shared workspace, not negotiating every line of code. If the environment is unfamiliar, run the smallest existing test or example immediately. Discovering a missing dependency near the beginning is easier to handle than discovering it after writing a solution you cannot execute.
For remote sessions, check that your partner can read the font and see the terminal as well as the editor. Close unrelated windows before sharing. If you need an accessibility adjustment, ask about it before the interview where possible; a brief thinking pause or a different communication setup should not be treated as evidence of poor collaboration.
A useful partner makes the next decision easier to inspect. They do not narrate every keystroke or hide every uncertainty.
Choose questions by the cost of a wrong assumption
Not every ambiguity deserves equal time. Ask about a detail when a wrong answer would change the data structure, output contract, or expected behavior. State a reversible assumption when the choice affects only presentation and the interviewer has left it open. Then check that assumption at a natural checkpoint.
For example, alphabetical sorting is not automatically cosmetic. If the task asks for the first event in arrival order, sorting would change the answer. In a directory display where no ordering rule has been specified, proposing alphabetical output may be reasonable. The consequence of the assumption determines whether to ask, not the name of the operation.
| Uncertainty | Why it matters | Useful question or proposal |
|---|---|---|
| Can the same path appear twice? | Determines whether insertion must be idempotent | "Should repeated paths appear once?" |
| Can a file also be a parent directory? | Requires conflict handling or an input guarantee | "Can I assume file and directory names do not conflict?" |
| Should folders appear before files? | Changes display order without changing stored paths | "I will start alphabetically; we can group folders first next." |
| Can paths contain empty segments? | Decides whether to normalize, reject, or accept them | "Are these already normalized relative paths?" |
| What should I name a local variable? | Usually has little effect on the agreed behavior | Pick a clear name and continue |
Once the scope is clear, repeat it in one sentence. That sentence becomes a reference when a follow-up changes the task. It also prevents an easy failure mode: hearing an answer, then continuing with the assumption you had before you asked.
Build the directory structure before polishing its display
Consider this hypothetical interview exercise: print a directory tree from a list of relative file paths. This example is deliberately small so that you can inspect the collaboration as well as the implementation. It does not claim to reproduce a particular employer's assessment.
The agreed contract is that paths are nonempty, slash-separated, normalized, and end in files. There are no empty directories, trailing slashes, or file/directory conflicts. Repeated identical paths should appear once. These exclusions matter because the implementation below identifies a directory by whether it has children.
A productive opening exchange could sound like this:
Interviewer: Turn these paths into an indented tree: src/app.js, src/lib/util.js, README.md, and src/lib/date.js.
Candidate: I will first build a structure that shares common prefixes, then produce the lines. May I assume every path ends in a file and that src cannot also be a file?
Interviewer: Yes. Repeated paths should not create repeated output.
Candidate: I will use a map of child names at each level. Adding an existing path will revisit the same entries. I will check that src has two children before spending time on indentation.
This is an observable checkpoint. Both people can inspect whether src contains app.js and lib, rather than debating a finished display whose underlying structure may already be wrong. My recommendation is to prioritize that checkpoint over attractive output. A polished printer cannot repair an incorrect tree.
JavaScript's Map documentation explains a relevant distinction: a map has no accidental inherited keys. A plain object needs care when arbitrary names such as constructor or __proto__ become keys. Here, using Map keeps a file name from being confused with an existing object property.
function buildTree(paths) {
const root = new Map();
for (const path of paths) {
let children = root;
for (const part of path.split("/")) {
if (!children.has(part)) children.set(part, new Map());
children = children.get(part);
}
}
return root;
}
function renderTree(children, depth = 0) {
const entries = [...children.entries()].sort(([a, aChildren], [b, bChildren]) => {
const aFolder = aChildren.size > 0;
const bFolder = bChildren.size > 0;
if (aFolder !== bFolder) return aFolder ? -1 : 1;
return a < b ? -1 : a > b ? 1 : 0;
});
const lines = [];
for (const [name, descendants] of entries) {
lines.push(" ".repeat(depth) + name);
lines.push(...renderTree(descendants, depth + 1));
}
return lines;
}
const paths = [
"src/app.js",
"src/lib/util.js",
"README.md",
"src/lib/date.js",
"src/app.js",
"__proto__/note.txt",
];
console.log(renderTree(buildTree(paths)).join("\n"));
// __proto__
// note.txt
// src
// lib
// date.js
// util.js
// app.js
// README.mdThe duplicate src/app.js appears once because the same map entries are reused. The __proto__ directory behaves like any other directory. Folders appear before files, with names ordered by JavaScript string comparison within each group. That is deterministic for this example, but it is not a promise of natural-language alphabetical order for every writing system.
After running it, inspect the result against the contract:
- Both top-level folders appear before
README.md. src/libappears beforesrc/app.js, even thoughapp.jssorts earlier as a name.date.jsappears beforeutil.jswithinlib.- Repeated insertion adds no second
app.jsline.
Building visits every path segment. Rendering visits the stored entries and sorts each set of siblings. If there are S total input segments and each directory has k children, the relevant sorting work is the sum of k log k across directories, plus traversal and output construction. Explain those costs in terms of the task instead of claiming the entire solution is simply linear.
Let a changed requirement reveal your design boundary
Suppose the interviewer now allows empty directories. The current representation cannot distinguish an empty directory from a file: both have zero children. This is a meaningful requirement change, not another comparator tweak. Say so before editing.
Interviewer: How would you support a directory with no files in it?
Candidate: My folder check depends on having children, so it would misclassify that case. I would add an explicit kind to each node and agree on how the input marks a directory. Do you want me to make that change now or describe it after checking the current version?
Interviewer: Describe it first.
Candidate: Each node would hold a name, a file-or-directory kind, and children for directories. The printer would sort by kind rather than child count. Insertion would also need a rule for a file path that conflicts with a directory path.
That answer identifies exactly where the original assumption lives. It avoids pretending that a restricted solution already handles the broader problem. If the interviewer asks for the extension, implement that boundary and add an empty-directory example before reorganizing unrelated code.
There are other reasonable follow-ups, each with a different consequence:
- Platform-specific path separators require an input convention before splitting strings.
- Case-insensitive matching requires a collision policy, not just lowercasing the display.
- Very deep trees may need iterative traversal to avoid recursive call-stack limits.
- A large output may need incremental writing rather than collecting every line in memory.
Do not implement every possibility preemptively. Show that you can locate the relevant boundary, then ask which extension serves the exercise. The ability to defer a feature explicitly is part of keeping two people focused on the same task.
Use silence deliberately and return with a result
Continuous speech can consume the attention you need for difficult reasoning. A better target is continuity of shared understanding. Your partner should know what you are investigating, even when you take a short quiet pause to investigate it.
Say, "I need a moment to trace why this name appears twice. I will compare the insertion step with the output step." Then trace a two-path input. Return with an observation: "Insertion creates one entry, so the duplication is in traversal." You have reduced the uncertainty and given your partner a useful place to contribute.
A practical recovery sequence is:
- State the exact mismatch between expected and actual behavior.
- Reduce the input until you can follow it by hand.
- Inspect one intermediate value that distinguishes two possible causes.
- Make one change, rerun the example, and explain the result.
When a hint arrives, connect it to the code. "Using an explicit kind would fix the empty-directory distinction" shows that you understand the suggestion. Merely saying "yes" and copying the proposed edit leaves that understanding unclear. If you disagree, explain a concrete counterexample and invite a comparison rather than defending your first idea as a matter of pride.
Birgitta Böckeler and Nina Siessegger's On Pair Programming describes driver and navigator roles, small shared goals, and the difficulty of balancing different working styles. In an interview, borrow the shared-goal principle while following the format you were given; do not assume you should hand over the keyboard without checking.
Rehearse interruptions, not a memorized monologue
Practice with a partner who changes one requirement after you reach a working checkpoint. For the directory exercise, use folder-first ordering as the first change and empty directories as a later discussion. Your partner should listen for whether you restate the new requirement and identify what must change before typing.
If you practice alone, record a short session and review the transitions. Count unexplained changes of direction, not seconds of silence. Did you abandon one representation without explaining why? Did you call an output correct without checking it? Did you spend several minutes polishing names while the main example still failed?
Use this review list to choose one improvement for the next attempt:
- Can a listener state your next checkpoint after hearing your explanation?
- Did you run an example that could reveal your main implementation mistake?
- Did you distinguish an assumption from a confirmed requirement?
- Could you explain a suggestion in your own words before applying it?
In the final minutes of an interview, give a factual handoff. For this exercise: "The current version groups shared prefixes, removes duplicate paths, and prints folders first. It assumes normalized file paths and does not represent empty directories. I checked the supplied example, a duplicate, and a special property name. My next step would be explicit node kinds if empty directories are required."
An unfinished solution needs the same clarity. State what runs, what fails, and the next smallest fix. Do not describe untested code as working, and do not spend the remaining time apologizing repeatedly. A clear account gives the interviewer usable evidence even when the implementation is incomplete.
Questions candidates ask about pairing rounds
Does finishing the task matter more than communication?
Both can matter, and the employer sets the assessment criteria. Do not assume that talking compensates for incorrect code or that a correct answer compensates for ignoring your partner. Aim for small working increments that make both your technical progress and your decisions visible.
What should I do when the interviewer stays quiet?
Keep giving concise updates at decision points and after checks. Ask a specific question when you need a requirement clarified. A quiet interviewer may be intentionally observing, so do not repeatedly seek approval for choices already covered by the brief. Continue toward the agreed checkpoint.
Can I take a moment to think without speaking?
Yes, ask for a brief pause and say what you are thinking through. Resume with your conclusion or a narrower question. There is a difference between a signposted pause and disappearing into unexplained edits. If the interview format makes communication difficult for you, discuss adjustments in advance where possible.
Should I write automated tests or just print output?
Follow the brief and the available environment. In an existing repository, relevant tests may be the natural first checkpoint. In a tiny standalone exercise, comparing a printed result can establish behavior quickly, but precise assertions make regressions easier to detect. Ask how the interviewer wants to balance implementation and testing.
What if I cannot remember a library method?
Describe the operation you need and ask whether documentation is allowed. Keep the lookup narrow, then verify the result in the program. If references are prohibited, explain a simpler approach you can implement reliably. Do not quietly introduce assistance that the interviewer has not permitted.
How do I respond to an approach I think is worse?
Identify the tradeoff without making it personal: "That reduces the insertion code, but how would we distinguish files from empty directories?" Compare against an example. If the interviewer asks you to proceed with their approach, do so while keeping the stated limitation clear and checking the resulting behavior.
What should I practice the day before?
Run the expected editor and test command, solve one small task while explaining your decisions, and rehearse a concise final handoff. Check screen sharing and audio for a remote session. Avoid changing your whole language or tool setup at the last minute; familiarity leaves more attention for the problem and your partner.
Prepare the next practice session
- Use the mock interview practice plan to schedule a partner session with a requirement change.
- Review live coding interview preparation for choosing visible checkpoints under time pressure.
- Check your remote interview setup before sharing an editor and terminal.