ペアプログラミング面接の練習:相談・実装・検証をどう進めるか
Quick Overview
ペアプログラミング面接を、容量2の予約区間ケースで練習。架空の対話と実行したPythonテストから、仕様確認、ヒントへの対応、役割の交代、同時刻の処理順と反例の検証を説明します。
ペアプログラミング面接で相手から「その条件で本当に合っていますか」と聞かれた時、何を言い直し、どの入力を試すでしょうか。同じ前提で考えているかは、期待値を一緒に決めて確かめます。契約を短く確認し、反例を選び、結果を見て次の一手を決める練習が役立ちます。
本稿は、容量が2の設備予約を題材に、相談、役割の交代、ヒントの受け取り、実装と検証をつなげます。証拠の区分: GDSの執筆者によるペア作業の実践記事と、Pythonの公式文書を参照します。GDSの記事は2018年の実践紹介であり、現在の企業共通の面接規則ではありません。以下の会話は架空で、候補者報告ではありません。Pythonで実行した20個のテストと、その一つに含む648組の比較を示します。実際の二人の面接や、採用結果を観察したものではありません。
まず Describe pair programming communication approach を開き、相談の言葉をこの予約ケースに置き換えてみてください。

開始時には、操作方法と最初の確認を合わせる
最初に、誰がキーボードを使うか、相手が編集する場合にどう交代するか、テストをどう実行するかを確認します。検索、補完、AI、外部のコードなどの利用条件は、実際の案内に従います。ペア作業という名称から、使える道具や交代の頻度を決めつけないでください。
実践者の説明: GDSのペアプログラミング記事 は、準備と計画、ドライバーとナビゲーターの協働、学習や交代について述べています。本稿ではその考え方を、契約・結果・次の確認を共有する練習に使います。記事内の仕事の進め方を、そのまま面接の制限時間や採点表にはしません。
たとえば開始時の架空の会話は、次のようになります。
候補者:「まず私が入力し、最初の二例を一緒に確認してから実装します。途中で方針を変える必要があれば、反例を決めて相談します。テストの起動方法も先に確認してよいですか」
相手:「はい。予約の時間が重なる時に、追加できるか判断してください」
候補者:「重なる予約を全て禁止するのか、設備の容量まで許すのかを確認したいです。また、終了時刻と開始時刻が同じ場合は重なりに含めますか」
容量と境界を質問するのは、正しい結果と実装を決めるためです。容量1で拒否する重なりでも、容量2なら受け入れられる場合があります。相手がすでに仕様を示している場合は、その内容を短く言い直し、同じ質問を繰り返さず例へ進みます。
予約の契約を、二人で追える小さな例にする
今回は、時刻を0から1440までの整数の単位とし、予約を [start, end) で扱います。開始を含み、終了を含みません。実際の時刻、タイムゾーン、夏時間を扱う予定表ではなく、境界と同時利用数を考えるための仮定です。startはendより小さく、長さ0の予約は不正とします。
設備の容量は2です。既存のR1が [10,12)、R2が [11,13) の時、新しいCが [12,14) なら追加できます。10から11では1件、11から12では2件、12から13でも2件、13から14では1件です。R1の終了とCの開始を、時刻12に同時に利用する二件とは数えません。
一方、Cが [11,12) なら、11から12にR1、R2、Cが同時に存在して3件になるため追加できません。まずこの二例を共有すると、単に「重なるか」ではなく「最大で何件同時に使うか」を求めていることが分かります。
| 既存予約 | 候補 | 容量 | 今回の契約での結果 |
|---|---|---|---|
R1 [10,12)、R2 [11,13) | [12,14) | 2 | 追加できる。最大2件 |
R1 [10,12)、R2 [11,13) | [11,12) | 2 | 追加できない。最大3件 |
[10,12) | [12,14) | 1 | 首尾が接するだけなので追加できる |
[10,11)、[12,13) | [10,13) | 2 | 二つと重なっても、同時には最大2件 |
最後の例も重要です。候補と重なる予約が二つあるから、候補を足して3件だとは言えません。二つの既存予約は別々の時間に存在しています。ナビゲーターは、このように実装の前提が崩れる入力を探す役割を持てます。
ヒントを受けたら、どの前提を変えるかを言う
最初に「一つでも重なったら拒否」という案を出したとします。容量1なら使える条件でも、容量2では先ほどの追加可能なケースを拒否してしまいます。本稿では、その誤った関数も実行し、[12,14) を拒否することを確認しました。
相手:「一つの予約と重なるだけなら、空きはまだありませんか」
候補者:「確かに、私の案は容量1を前提にしていました。今回の容量2には合いません。R1とR2にCの
[12,14)を足す例を、追加可能な期待値として先に置きます」相手:「何を数えるように変えますか」
候補者:「候補と重なる予約の総数ではなく、時間ごとの同時利用数です。開始をプラス1、終了をマイナス1にして、時刻順に追う案を試します」
ヒントを受け入れた後も、自分が変えた判断を説明します。「分かりました」と言って別のコードを写すだけでは、前提の修正が共有されません。相手の提案がどの反例を直し、どの条件がまだ残るかを短く確かめます。
逆に、提案に疑問がある時も、相手の意図を確認してから入力で比べます。「その案だと容量2の時も全重複を拒否しそうです。先ほどの追加可能な例で一緒に確認してよいですか」のように、人物ではなく結果へ話を戻します。架空の台本を暗記するより、自分のコードで同じ説明をできるかを練習してください。
同じ時刻の順序は、小さな反例で決める
開始をプラス1、終了をマイナス1とするだけでは、同じ時刻の処理順が残ります。[10,12) と [12,14)、容量1だけを試します。開始を先に数えると、時刻12で一瞬2件に見え、誤って拒否します。終了を先に数えれば、時刻12で利用数を1から0へ減らし、次の開始で0から1へ増やすため、最大1件です。
公式の技術的根拠: Pythonのtupleは要素を順に比較します。組み込み型の文書 と ソートの説明 を参照してください。今回 (時刻, 変化量) を並べると、同時刻では -1 が +1 より先になります。これは半開区間という本稿の契約に合わせた設計です。
ドライバー:「同時刻は開始を先にしますか」
ナビゲーター:「今回は終了を含まないので、12で終わる予約は12からの予約と重なりません。二本だけの例で、開始優先と終了優先の最大数を比べましょう」
ドライバー:「開始優先の版は2、終了優先は1でした。終了優先を残し、この例をテストに追加します」
開始優先で最大2、終了優先で最大1になる結果は、二つの関数を実行して確認しました。会話自体は架空です。実際のペアがこの通りに話した、あるいはこの対応で高評価を得たと報告しているわけではありません。相違を解消するために、何を実行すればよいかを示しています。

実装する人と、検証する人の仕事をつなげる
次は、実行した関数の中心部分です。全ての区間が今回の整数の範囲と形に合うことを interval で検証し、開始・終了のイベントを並べます。既存のlistをその場で書き換えず、候補を足した別のlistで判定します。
def peak_usage(intervals):
events = []
for value in intervals:
start, end = interval(value)
events.extend([(start, 1), (end, -1)])
active = peak = 0
for _, change in sorted(events):
active += change
peak = max(peak, active)
return peak
def can_add(existing, candidate, capacity):
if type(capacity) is not int or capacity < 1:
raise ValueError("capacity must be a positive integer")
if not isinstance(existing, list):
raise ValueError("existing must be a list")
interval(candidate)
return peak_usage([*existing, candidate]) <= capacity
ナビゲーターは、実装中に別の解法を次々に要求するだけでなく、現在の契約を見ながら確認できます。たとえばboolを整数として受け入れるのか、既存データに不正な区間があったらどうするか、候補が拒否された後に入力が変わっていないかを、一つずつテスト候補にします。
今回の入力では、bool、float、逆転した区間、長さ0、上限を超える区間を拒否します。既存予約にも同じ検証を適用します。既存予約だけで容量超過している場合も、候補を含めた全体が契約を満たさないのでfalseです。「候補と関係ない過去の異常は無視する」仕様ではありません。この違いも、相手と合意する必要があります。
イベントを並べる方式は、n件に対しイベント数もnに比例し、比較ソートを使う時間量はO(n log n)、補助領域はO(n)です。これはこの実装の分析であり、大量入力を計測した性能値ではありません。入力が小さい面接練習では、最初に契約と境界を説明できる実装を完成させ、別の要件が出たら変更を相談できます。
キーボードを渡す時は、契約・現在地・次の確認を渡す
役割を交代するなら、手だけを止めるのではなく、次に何を確認するかまで言い直します。交代が必須かどうか、どの時点で行うかは、実際の相手と進め方を合わせます。ここでは、同時刻の反例を確認した後に交代するという練習をします。
候補者:「ここまでで半開区間、容量2、同時刻は終了優先という契約です。追加可能な
[12,14)と、不可の[11,12)は確認しました。次は入力を並べ替えても結果が同じかと、入力を変更していないかを確認したいです。ここから操作をお願いできますか」相手:「では私が順序を逆にするテストを書きます。あなたは期待値を確認してください」
候補者:「既存予約の順序で同時利用数は変わらないので、結果はtrueのままです。元のlistのコピーも取って、呼び出し後に比較しましょう」
この引き継ぎなら、ナビゲーターになっても判断に参加できます。相手が書いたコードを一行ずつ読み上げる必要はありません。期待値、検証する性質、次の未確認事項を共有します。自分の案と異なる変更が入った時も、その目的を確認してから結果を比べます。
交代する余裕がない場合は、同じ形式で途中経過を短く伝えられます。「今は境界の二例を確認済みで、無効入力はまだです」と言えば、相手も残り時間に合わせて助言できます。単に「ほぼできています」では、どこまで動いたかが共有されません。
20個のテストと、648組の比較をどう読むか
実行環境はCPython 3.12.14です。unittestの公式文書 にある仕組みで20個のテストを実行しました。追加の可否、境界、同一の区間、入力順、不変性、不正な型や範囲、既存データの容量超過、二つの誤ったアルゴリズムの反例を確認しています。
20個のうち一つでは、10から13までの整数の端点から作った6種類の区間を使い、既存二件と候補一件の組み合わせを調べました。6×6×6通りに、容量1、2、3を掛けて648組です。それぞれの整数の時点で区間を直接数える別の方法と、イベントをソートする関数の結果を比較しました。
この別の方法は、開始を含み終了を含まない条件を各時点に直接当てるため、ソート順の実装をそのまま写してはいません。整数の端点だけを扱う今回の範囲では、区間の間で利用数が変わらないことを使っています。任意の実数端点やタイムゾーンを含む予定表にまで、この648組の確認を広げません。
また、648組は一つのテストの内部の比較です。20個に648個を足して「668個のテストに合格」とは言いません。全入力を証明したわけでもありません。面接の説明では、何を別の方法と照合し、その方法がどの範囲で使えるかを答えてください。
この関数は、予約の保存や確定を行いません。二人が同時に同じ空きを確認して予約する競合も検証していません。実サービスなら、判定と保存の整合性を別に考える必要があります。今回はペアで境界を相談するための純粋な判定関数です。
練習を終える時は、観察した行動で振り返る
終了時には、契約、実行結果、未確認事項を短くまとめます。「容量1の案から始めましたが、容量2の追加可能な反例で前提を修正しました。同時刻は終了優先にし、20個のテストと648組の比較を確認しました。保存や同時予約、実際の日付時刻は対象外です」と説明できます。
二人で練習した後の振り返りでは、「会話がよかった」より、どの行動を見たかを記録します。相手のヒントを自分の言葉で言い直したか。期待値を決める前にコードを変えなかったか。キーボードを交代した時に、次に確かめることを共有できたか。まだ通していないテストを、確認済みとしてまとめなかったかを見ます。
意見が割れた場面も、勝ち負けで採点する必要はありません。たとえば開始優先を提案した時、首尾が接する二本の例に戻れたなら、判断を変える証拠が共有できています。一方、正しいコードを持っていても、相手に契約が伝わっていなければ、次回は引き継ぎの説明を練習できます。
本稿で実行したのはコードの検証です。会話の速さ、相手の理解、役割交代のしやすさは実測していません。一人で練習する時は、表の候補区間を変え、次に確認する期待値を書いてください。台本にない入力でも、どの前提を相談すべきか整理できます。
関連問題で、同じ相談の仕方を別の入力へ広げる
問題を変えても、「相手と契約を確認し、一つの反例を実行してから変更する」という練習はできます。ただし、下記の問題全てが容量2の同じ課題や、同一企業のペア面接を報告しているわけではありません。技術的な隣接課題と、協働の説明を分けて使います。
| PracHubの問題 | 今回からつなげる練習 |
|---|---|
| Describe pair programming communication approach | 引き継ぐ契約、現在の結果、次の確認を短く伝える |
| Evaluate Defensive Testing and Pair Programming | ヒントを受けた後に、修正した前提と反例を説明する |
| Design Calendar Event Conflict Handling | 区間の境界を合意し、実際の日付や保存という追加要件を区別する |
| Check an Interval Against Existing Intervals for Conflicts | 容量1の重複判定と、容量2の同時利用数の違いを確認する |
| Find Peak Memory Usage Across Process Intervals | イベントの増減を追う考え方を、使用量が異なる区間へ応用する |
次は Check an Interval Against Existing Intervals for Conflicts で、首尾が接する二本の区間を提示してください。相手に期待値を説明してもらい、契約が一致してから実装を始めます。最後に、変更した前提、実行した反例、まだ確かめていない範囲を二人で言い直してください。この練習の記録を、企業共通の合否基準として扱わないようにします。
Sources and Further Reading
- GDS: How to pair program effectively in 6 steps — 2018年の実践記事。現在の面接規則ではありません。
- Python 3.12: Sorting Techniques — ソートに関する公式文書。
- Python 3.12: Built-in Types — tupleの比較と型に関する公式文書。
- Python 3.12: unittest — テストの実行に関する公式文書。
Comments (0)