ラバーダック・デバッグは、コードを誰かに順番に説明することで、自分の思い込みへ気づく方法です。相手は詳しい人でなくても構いません。
説明する順番

- この処理の目的
- 入力がどこから来るか
- 各条件が何を判定するか
- 値がどう変わるか
- 成功時と失敗時の出力
「ここは当然こうなる」と説明を飛ばした場所に、未確認の前提が隠れます。
例
ボタンを押すとsubmitが発生する。
submitでformDataを作る。
ここでemailを取得するはず……取得コードがnameではなくidを見ている。
説明中に原因へ気づいても、最初からやり直す必要はありません。気づいた前提を確認します。
AIへ説明する時にも使える
AIへコードだけ貼る前に、自分で処理を説明してから質問文へ入れます。説明できない箇所が、確認してほしい範囲です。
説明できることは、暗記ではなく処理のつながりを理解している証拠になります。
ケーススタディ:検索結果が一件ずれる
商品検索で二ページ目の先頭商品が一ページ目の末尾と重複する場面を考えます。「ページングが壊れている」と要約するだけでは、説明の粒度が粗すぎます。入力したページ番号、一ページの件数、並び順、計算した開始位置、DBへ渡した値、返却件数を順番に声へ出します。「二ページ目なので開始位置は十件目。式はページ番号掛ける件数」と説明した時、ページ番号が一始まりなのにそのまま掛けている矛盾へ気づけます。
気づいた直後に式を書き換えず、一ページ目、二ページ目、最終ページの具体値を紙へ置きます。期待する開始位置と実際の値が初めて違う場所を確認し、そこだけを修正します。良い説明は「この変数は何を表すか」「その値をどこで観測したか」「条件が偽なら次にどこへ進むか」を含みます。悪い説明はコードを日本語へ読み替えるだけで、「ここで適切に処理する」のような未確認語を使います。
説明を止める判断
ラバーダックは万能ではありません。十五分説明しても最初の差が見つからない、外部APIや並行処理の実際の状態が必要、再現が不安定という場合は、説明を続けるより観測を増やします。ブレークポイント、Network、DBの問い合わせ記録、最小テストを使い、得た事実を新しい説明へ戻します。秘密情報を含むデータは、AIや共有文書へそのまま貼らず、構造を保った仮の値へ置き換えます。
効果を観測する
開始時刻、最初に説明できなかった箇所、採用した仮説、原因特定までの時間を短く記録します。修正後には、同じ説明をコードを見ずに再現し、正常入力と境界入力の結果を予測します。説明と実行結果が一致し、追加したテストが修正前に失敗して修正後に通れば、思いつきではなく原因へ到達したと判断できます。
毎回長い文章を作る必要はありません。入力、変換、分岐、出力を矢印で並べるだけでも十分です。ただし「たぶん」「自動的に」「なぜか」が出た場所には印を付けます。その言葉が残ったまま修正へ進むこと、実行結果を見ずに納得すること、複数箇所を同時に変えることが失敗条件です。
よくある誤解:コードの朗読ではない
行を上から日本語へ置き換えるだけでは、プログラムが満たすべき約束を検査できません。「この変数に1を足します」ではなく、「ページ番号は1始まりだが配列位置は0始まりなので、ここで1を引く必要がある」と、値の意味と変換理由を話します。説明中に「適切に」「いい感じに」が出た場所は、まだ処理を説明できていない場所です。
相手が人形である必要もありません。紙、空のIssue、音声メモでも、入力から出力まで省略せず話せれば同じ役割を果たします。ただしAIへ説明する場合、秘密値や顧客データを渡さず、AIの推測を観測済み事実として扱いません。
| 説明する対象 | 具体的に口にする内容 |
|---|---|
| 入力 | 型、単位、空値、境界値 |
| 状態 | 変更前の値と所有者 |
| 分岐 | 真になる例と偽になる例 |
| 反復 | 開始、終了、各回で変わる値 |
| 出力 | 呼び出し側が期待する契約 |
| 副作用 | DB、通信、画面、時刻への変更 |
デバッグ確認:具体値で処理を通す
不具合が出た入力を一つ選び、各行の直前と直後の値を紙へ書きます。分岐では採用した経路だけでなく、なぜ反対側へ行かなかったかも説明します。初めて期待と違う値が現れた行を見つけたら、そこで失敗テストを追加し修正します。
説明しても値が分からない箇所は、推測で埋めずデバッガやログへ切り替えます。外部APIの応答、競合する非同期処理、DBトランザクションは実測が必要です。ラバーダックは観測の代用品ではなく、どこを観測すべきか絞る方法です。
まとめ
ラバーダック・デバッグ:処理を説明して自分で矛盾を見つけるで大切なのは、用語を単独で暗記することではありません。期待、観測、差分、仮説、操作、結果を順に残し、テーマに合う証拠で判断します。小さく確認し、再現できる説明を残すことが、修正と学習の両方を次へつなげます。
参考リソース
説明で判明した事実と推測を分け、次に観測する値を一つ決めます。聞き手が答えを知っていても、説明者が自分の前提を発見する時間を奪わないことが重要です。
説明の粒度は対象に合わせます。関数内の計算なら変数一つずつ、サービス間障害なら要求、キュー、保存、通知という境界ごとに話します。細かすぎて全体の目的を失ったら一段上へ戻り、粗すぎて値が見えなければ一段下へ降ります。この往復により、「APIが変」のような大きすぎる主語を、特定の応答項目や時刻へ狭められます。
複数人で使う時、聞き手は途中で修正案を連発せず、説明者が置いた前提を質問します。「その配列は空になれるか」「この時点で認証済みと言える根拠は何か」「同じ処理が二回走ったらどうなるか」のような問いです。答えが資料に依存するなら、その場で公式仕様やテストを確認します。
不具合が直らなくても、入力範囲、再現しない条件、未確認の外部状態が整理されれば進展です。その記録を技術質問へ転用すれば、次の担当者は同じ探索を繰り返さずに済みます。逆に、説明後に何も記録せず偶然の再実行で直った場合は、解決済みにせず再発時の観測点を残します。
説明の台本を処理に合わせる
検索結果が一件ずれるなら、「利用者が2ページ目を選ぶ」「URLから文字列の2を読む」「数値へ変換する」「APIのoffsetへ変える」「DBがoffset件を飛ばす」「結果を描画する」と境界を並べます。各境界で具体値を置くと、ページ番号と配列位置の基準差が見えます。関係のないCSSや通信設定まで列挙しません。
非同期処理では時間も説明します。「要求Aを開始し、次に要求Bを開始し、Bが先に完了し、最後にAが古い結果を上書きする」のように順序を話します。コード行の順と完了順を混同していることが分かれば、取消や要求ID照合を検討できます。共有状態では、誰がいつ値を書けるかを加えます。
再帰では、基底条件、引数が小さくなる理由、戻り値の合成を具体例で追います。オブジェクト参照では、コピーしたのが値か参照かを図にします。型変換では"0"、0、falseを代入し、暗黙変換の結果を予想してから実行します。題材に合う言葉を選ぶことで、説明が一般論へ逃げません。
修正後は同じ説明を短くやり直します。新しい条件分岐を「例外処理を追加した」で済ませず、どの入力がどの戻り値になるか言えれば、修正理由がコードと一致しています。説明できない複雑さが残るなら、関数分割や名前の改善も候補です。