最小再現コードの作り方:問題だけを小さく取り出す

初級 | 13分 で読める | 2026.07.11

公式ドキュメント

最小再現は、期待と異なる現象を第三者が同じ手順で確認でき、しかも無関係な要素を取り除いた最小限のコードと条件です。 単に短いコードではなく、実行可能で、問題が残り、期待結果と実際結果を比較できることが結論です。

現象を固定し、一要素だけ外して同条件で再実行し、現象が残れば続け、消えれば直前を戻す最小再現の図

なぜ必要か

大きなアプリには、認証、通信、状態管理、CSS、ビルド設定など多くの変数があります。全部を含む質問では、回答者が環境構築に時間を使い、秘密情報の共有リスクも高まります。要素を一つずつ外す過程そのものが、原因候補を絞る実験になります。

最小再現を作って問題が消えた場合も失敗ではありません。最後に外した条件が原因範囲を示します。

登場人物と対象

現象を見つけた実装者、再現を確認する同僚・保守担当、必要に応じてライブラリのメンテナーが関わります。対象はコードだけでなく、入力データ、依存バージョン、OS・ランタイム、実行コマンド、期待結果です。

進め方の判断

最初に元の環境で再現手順を固定し、毎回同じ現象か確認します。次に新しいディレクトリやオンライン実行環境へ問題部分だけを移し、外部APIを固定値、DBをメモリ上の値、複雑なUIを単純な入力へ置き換えます。一変更ごとに再実行し、問題が残るか記録します。

作る手順

  1. 現象を一文で固定する
  2. 新しい小さなファイルへ関係部分を移す
  3. 外部データを固定値へ変える
  4. CSSや画面部品を外す
  5. 一つ外すたびに問題が残るか確認する

API取得後だけ配列処理が失敗するなら、まずレスポンスを固定します。

const response = { items: null };
const names = response.items.map((item) => item.name);

これだけで同じTypeErrorが出るなら、通信や認証は今回の最小再現に不要です。

外しすぎに注意

問題が消えた直前に外した要素は、再現条件の一部です。元へ戻し、最小限どの条件が必要か確認します。

削減パターンの比較

元の依存置き換え分かること
外部API固定JSON通信かデータ処理か
DB小さな配列永続化かロジックか
画面全体一要素レイアウト・イベント条件
本番ビルド最小設定ツール設定の影響
大量データ境界を含む数件入力条件の影響

置き換えによって現象の性質を変えてはいけません。競合や時刻依存の問題では、非同期性を消すと再現できなくなるため、必要なタイミング条件を残します。

具体例を確認する

既存例では items: null に固定しても同じ TypeError が出るため、認証や通信は原因ではありません。次は「API仕様上 items はnullになり得るか」を確認します。なり得るなら実装で扱い、ならないならレスポンス生成側または入力検証を調べます。エラーを消すためだけに空配列へ置換すると、仕様違反を隠す可能性があります。

再現コードは原因の証明ではなく、特定条件で現象が起きる証拠です。

よくある誤解

リポジトリ全体を共有すれば再現資料になる、という考えは誤りです。不要な依存と秘密情報が残ります。また、コードが短くても実行方法がなければ第三者は確認できません。逆に、一行まで縮める必要もありません。問題を理解するために必要な条件は残します。

注意とベストプラクティス

  • トークン、Cookie、個人情報、社内URLを架空の安全な値へ置き換える。
  • ライブラリ名と正確なバージョン、実行コマンドを記す。
  • 期待結果と実際結果を別々に書く。
  • ロックファイルなど再現に必要な設定は残す。
  • 削除履歴をメモし、現象が消えた直前の変更を追えるようにする。

デバッグ・確認方法

新しい環境でREADMEどおりに実行し、同じエラー種類・出力・操作結果になるか確認します。依存を再インストールしても再現するか、入力を一つ変えると消えるかも試します。共有前には差分と全文を検索し、秘密情報がないことを確認します。

ケーススタディ:送信が二重になる

課題提出画面で、送信ボタンを一度押したのに要求が二回送られる不具合を考えます。元アプリには認証、入力検証、ファイル添付、分析タグ、状態管理があります。最初にネットワーク記録で「一回の操作に対して同じ提出要求が二件発生する」と現象を固定し、発生回数を10試行中何回か記録します。

次に外部APIを、呼び出し回数を数えるローカル関数へ置き換えます。認証を外しても二回なら認証は不要です。ファイル入力を文字列一つへ変えても残るなら添付処理も外せます。一方、送信処理を同期関数へ変えた瞬間に消えたなら、非同期完了前の再実行という条件を消した可能性があります。遅延を固定したPromiseへ戻し、ボタン操作、フォーム送信、再描画のどの組み合わせが二回目を起こすか確かめます。

削減順を決める判断手順

第一に、秘密情報と外部課金につながる依存を安全な代替へ変えます。第二に、現象と遠い表示装飾や別画面を外します。第三に、境界を一つずつ置換し、通信、永続化、状態、入力、実行環境のどちら側に現象が残るか記録します。第四に、現象が消えた変更だけを戻し、必要条件を半分ずつ比べます。最後に、新規環境へ作り直し、元リポジトリ固有のキャッシュや未追跡ファイルがなくても再現するか確認します。

削減候補を選ぶ時は、コード量ではなく「変えても問いの意味が保たれるか」を基準にします。二重送信の調査で非同期性を消す、文字化けの調査で文字コードを変える、レイアウト崩れの調査で親要素を消す、といった変更は短くなっても現象を別物にします。

失敗条件と観測方法

最小再現の失敗条件は、手順どおりでも発生しない、期待結果が書かれていない、無関係な依存を大量に要求する、再現のために実サービスや秘密情報が必要、発生頻度を一回の成功だけで表す、という状態です。また、例外文が同じでも入力や発生箇所が違えば同じ現象とは限りません。スタックトレース、要求回数、DOM状態、戻り値など、その問題を識別する観測点を先に決めます。

二重送信なら、クリック回数、submitイベント回数、送信関数の呼び出し回数、要求識別子を別々に数えます。10回試して10回二件なのか、10回中2回なのかも残します。修正後は「エラーが出ない」だけでなく、一操作一要求になり、失敗後の再試行では新しい要求が一件だけ発生することを確認します。

良い例と悪い例

悪い例は、リポジトリ一式と「たまに二重になります」という説明だけを渡すことです。起動に外部アカウントが必要で、観測点も頻度もありません。別の悪い例は、ボタンの関数だけを貼り、フォームのsubmitイベントを削除することです。原因条件まで消えて再現しません。

良い例は、依存バージョンと一つの起動コマンドを示し、遅延を固定した送信関数、フォーム、ボタンだけを残し、「ボタンを一回押すと呼び出し回数が2になる。期待は1」と書く形です。入力を変えた場合や遅延をゼロにした場合に消えることも併記すれば、回答者は競合条件に集中できます。

実践演習:削除ログを付けて縮める

不具合を複製した安全な作業場所で、削除候補を「見た目」「外部通信」「永続化」「認証」「データ量」「依存設定」に分類します。一回につき一分類だけを変更し、現象が残ったかを表に記録します。問題が消えたら、その変更を半分戻して必要条件を探します。

最終成果物を別の人に渡し、書かれたコマンドだけで実行してもらいます。同じ例外名だけでなく、同じ入力で同じ期待差が生じるかを確認します。環境差で再現しない時は、ランタイム、依存バージョン、ロックファイル、OS条件を比較します。

ライブラリへ報告する場合は、そのライブラリを外しても発生するかを確認します。特定バージョンだけで起きるなら、動く版と失敗する版の境界を記録すると回帰範囲の手掛かりになります。

最小になったかを判定する

各ファイル、依存、設定について「これを外すと現象が消えるか」を確認します。外しても残るなら、原則として再現資料から除けます。ただしライセンス、実行環境、ビルドに必要なファイルは、原因と無関係でも実行可能性のため残る場合があります。

再現資料には、開始状態から現象までの操作が一通りだけ存在するのが理想です。複数の手順で起きる場合は、最短で安定するものを主手順にし、別条件は補足します。毎回起きない問題なら、再現頻度を実測範囲で記録し、起きなかった試行を隠しません。

共有後に第三者の環境で再現しない時は、コードを増やす前に差分一覧を作ります。環境差を一つずつ合わせ、現象が現れた境界を新しい再現条件として文書へ反映します。

まとめ

最小再現は、現象を保ったまま変数を減らし、第三者が同じ期待差を確認できる調査成果物です。 一要素ずつ外し、消えた直前の条件を戻して境界を確かめます。短さより、実行可能性、安全性、再現性を優先します。

参考リソース

共有前の確認

  • 秘密情報や個人情報がない
  • 実行方法が書かれている
  • 期待結果と実際の結果がある
  • コピーして同じ現象を確認できる

次に読む記事

← 一覧に戻る
PR
PR
PR
PR