用語解説
第8章 既存コードを小さく読む
この章は、すでに動いているコードの不具合を、勘ではなく観察から小さく読む方法を扱う。ここでは、再現からPR説明までのデバッグで使う、研修の外でも通用する一般的な用語を解説する。
再現
- 読み:さいげん(reproduction / repro)
- 一言で言うと:同じ手順で同じ不具合をもう一度起こせる状態にすること。
- くわしく:再現は、デバッグの最初の成果物である。修正コードより先に、何をしたら不具合が起きるのかを手順として書き出す。再現できると、修正前と修正後を同じ条件で比べられる。逆に再現できないまま直し始めると、直ったのかどうかも判断できない。だから「直す前に再現する」がデバッグの基本になる。
- 具体例:支援ステータス機能で「一覧から特定のメンターを選ぶとステータスが空欄になる」なら、起動して一覧を開き、そのメンターを選ぶ、という手順を書く。第8章の題材では、アプリを起動し
http://localhost:3000/mentors/progressを開き、未提出者フィルタを選ぶ、という手順になる。 - つまずきやすい点:「一度起きた」だけでは再現ではない。誰がやっても同じ結果になる手順まで書けて初めて再現と言える。
- 関連語:回帰確認(第8章)、スタックトレース(第8章)、ログ(第5章)
- テキスト本文での登場箇所:第8章「直す前に、再現できる説明を作る」
入口
- 読み:いりぐち(entry point)
- 一言で言うと:広いコードベースのうち、その不具合に関係する「最初に読むべき場所」。
- くわしく:既存コードは全部読んでから直すのが現実的ではない。そこで、画面・通信・ログから手がかりを集め、関連しそうなファイルだけを読み始める。その読み始めの一点を入口と呼ぶ。入口を決めると、読む範囲が小さくなり、調査が散らばらない。エラーメッセージやスタックトレースも入口を探す材料になる。
- 具体例:支援ステータス機能で表示がおかしいとき、まず画面を描く処理か、ステータスを返すAPIのどちらかを入口に選ぶ。第8章では、
filter=unsubmittedがAPIに届いているなら、API側のfilter処理を入口にする。 - つまずきやすい点:入口を一発で正解の行に当てる必要はない。観察結果から「まずここを見る」を決められれば十分である。
- 関連語:検索語(第8章)、スタックトレース(第8章)、最小修正(第8章)
- テキスト本文での登場箇所:第8章「観察結果から、読む範囲を小さくする」
検索語
- 読み:けんさくご(search term / search query)
- 一言で言うと:関連コードを探すために使う、見えている言葉の手がかり。
- くわしく:コード探索の入口は、画面や通信に見えている言葉から作る。URL、API名、画面の文言、field名、エラーメッセージなどがそのまま検索語になる。良い検索語があると、関係するファイルを少ない手数で見つけられる。検索ツール(
rgなど)と組み合わせて使うのが普通である。 - 具体例:支援ステータス機能なら
supportStatusや/api/mentor/support-statusを検索語にする。第8章では/mentors/progress、/api/mentor/learners、submittedAt、unsubmitted、filterを検索語にする。 - つまずきやすい点:1語だけで決め打ちしないこと。URL・field名・文言を複数並べて探すと、関係ファイルを取りこぼしにくい。
- 関連語:入口(第8章)、rg / ripgrep(第8章)、差分(第8章)
- テキスト本文での登場箇所:第8章「検索語は、画面と通信から作る」
rg / ripgrep
- 読み:リップグレップ(ripgrep、コマンド名は
rg) - 一言で言うと:プロジェクト内の文字列を高速に探すコマンドラインの検索ツール。
- くわしく:
rgはripgrepの略で、ディレクトリ配下のファイルから指定した文字列を素早く探す。検索語をコードベースに当てて、関連ファイルを見つけるのに使う。|で複数の語をまとめて検索できる。標準のgrepより速く、無視設定(.gitignore)を尊重するため、調査の入口探しで広く使われる。 - 具体例:支援ステータス機能で
rg "supportStatus" starter-apps/learning-log-sampleと打つと、その語を含むファイルが一覧で出る。第8章ではrg "/mentors/progress|/api/mentor/learners|submittedAt|unsubmitted|filter" starter-apps/learning-log-sampleのように使う。 - つまずきやすい点:ヒットした行はあくまで候補である。出てきたファイルを、画面・API・ロジック・データ・テストに分けて読む段階が別に必要になる。
- 関連語:検索語(第8章)、入口(第8章)
- テキスト本文での登場箇所:第8章「検索語は、画面と通信から作る」
スタックトレース
- 読み:スタックトレース(stack trace)
- 一言で言うと:エラーが、どの呼び出しの流れで起きたかを示す一覧。
- くわしく:プログラムは関数が関数を呼ぶ形で動く。例外が起きると、そのとき積み重なっていた呼び出しの履歴が出力される。これがスタックトレースである。どの行で失敗し、その行を誰が呼んだかをたどれるので、入口を探す強い手がかりになる。全部を追う必要はなく、まず自分たちのアプリのファイル名と、最初に失敗した行を探す。
- 具体例:支援ステータス機能の更新APIで500が出たとき、スタックトレースに
src/store.js:42のような自分たちのファイル名が出ていれば、そこを入口にできる。借りているライブラリの奥を追うより、自分が直せる場所を先に探す。 - つまずきやすい点:一番上の行(ライブラリの内部)に飛びつきがちだが、見るべきは自分たちのコードが最初に出てくる行であることが多い。
- 関連語:入口(第8章)、再現(第8章)、ログ(第5章)
- テキスト本文での登場箇所:第8章「呼び出しの流れを、少しずつ追う」
仮説
- 読み:かせつ(hypothesis)
- 一言で言うと:観察した事実から考えた、原因の候補。断定ではない。
- くわしく:仮説は「たぶんここが原因だ」という当たりであり、まだ確かめていない。良い仮説には、どうすれば正しいと分かるか、または違うと分かるかの確認方法が付いている。原因を1つに決めつけず、複数の仮説を出して、外れたものを消していくのがデバッグの進め方である。外れた仮説も「次に見なくてよい場所が分かった」という成果になる。
- 具体例:支援ステータス機能なら「APIがステータス未設定の人を除外していない」「画面側で表示を上書きしている」などを並べる。第8章では「filter条件が逆」「画面がqueryを付けていない」などを仮説にし、コードとNetworkタブで確認する。
- つまずきやすい点:仮説と観察した事実を同じ文で混ぜないこと。混ぜると、相談された相手がどこまで確認済みか判断できない。
- 関連語:再現(第8章)、最小修正(第8章)、入口(第8章)
- テキスト本文での登場箇所:第8章「仮説は、消せる形で書く」
正常系
- 読み:せいじょうけい(happy path / normal case)
- 一言で言うと:想定どおりの入力で、想定どおりに動く正しい流れのこと。
- くわしく:機能には、正しく動く流れ(正常系)と、エラーや例外の流れ(異常系)がある。不具合を直すと、その近くの正常系まで壊してしまうことがある。だから修正後は、直した箇所だけでなく、もともと正しく動いていた流れも確認する。これが回帰確認の中身につながる。
- 具体例:支援ステータス機能なら、ステータスを正しく付けて一覧に反映されるのが正常系。第8章では「フィルタなしで全件が表示される」「提出済みフィルタで提出済みだけが出る」が正常系にあたる。
- つまずきやすい点:元の不具合の再現手順だけを確認して安心しがちだが、周辺の正常系を見ないと、別の場所を壊したことに気づけない。
- 関連語:回帰確認(第8章)、最小修正(第8章)
- テキスト本文での登場箇所:第8章「既存コード調査で起きやすい誤解」
最小修正
- 読み:さいしょうしゅうせい(minimal fix)
- 一言で言うと:原因に対応する範囲だけに絞った、小さな変更。
- くわしく:最小修正は、臆病な修正ではない。原因に対応する一点だけを直すことで、レビューしやすく、戻しやすく、回帰確認もしやすくなる。修正方針を一文で先に置くと、差分がその方針から広がっていないか確認できる。バグ修正のついでに別の整理(リファクタリング)や別仕様まで混ぜると、何を確認すべきか分からなくなる。
- 具体例:支援ステータス機能で表示条件のバグなら、その条件だけを直し、画面の文言や他のフィルタは触らない。第8章では「
filter=unsubmittedのときだけsubmittedAt === nullの受講者を残す」に絞り、他のfilterや更新APIは変えない。 - つまずきやすい点:構造整理が必要に見えても、バグ修正と同じPRに混ぜない。整理は別PRに分ける。
- 関連語:差分(第8章)、リファクタリング(第8章)、Pull Request(第6章)
- テキスト本文での登場箇所:第8章「最小修正は、原因に対応する範囲へ絞る」
リファクタリング
- 読み:リファクタリング(refactoring)
- 一言で言うと:外から見た動きを変えずに、コードの構造を整理し直すこと。
- くわしく:リファクタリングは、関数名の整理や処理の分割など、見た目の振る舞いはそのままで内部を読みやすくする作業である。価値はあるが、バグ修正と同時にやると、レビュアーがどの変更が不具合修正で、どれが整理なのかを区別できなくなる。だから不具合修正のPRとは分けるのが基本である。
- 具体例:支援ステータス機能のバグを直すついでに
listLearnersを別ファイルへ移したくなっても、それは別PRにする。第8章でも、関数名整理や表示文言変更は今回のPRでやるかどうかを判断する。 - つまずきやすい点:「ついでだから」と1つのPRに混ぜると、レビューも判断も難しくなる。目的が一つのPRにする。
- 関連語:最小修正(第8章)、差分(第8章)、Pull Request(第6章)
- テキスト本文での登場箇所:第8章「最小修正は、原因に対応する範囲へ絞る」
差分
- 読み:さぶん(diff)
- 一言で言うと:変更前と変更後の違い。レビューの中心材料になる。
- くわしく:差分は、どの行をどう変えたかを示す。
git diffで確認でき、Pull Requestでもこの差分がレビューの対象になる。自分で差分を説明できない変更は、まだPRに出せない。差分を見ることで、修正が当初の方針から広がっていないかも確認できる。 - 具体例:支援ステータス機能の修正後、
git diffで変えた行を見て「条件式の1行だけを直した」と説明できる状態にする。第8章でも、修正後はgit diffで差分を見て、最小修正に収まっているか確かめる。 - つまずきやすい点:差分の行数が少ないこと自体が目的ではない。原因に対応した変更かどうかを、差分を見て自分の言葉で説明できることが大切である。
- 関連語:最小修正(第8章)、Git(第6章)、Pull Request(第6章)
- テキスト本文での登場箇所:第8章「最小修正は、原因に対応する範囲へ絞る」
回帰確認
- 読み:かいきかくにん(regression check / regression testing)
- 一言で言うと:直した不具合が戻っていないこと、周りの正常系が壊れていないことを確かめる確認。
- くわしく:回帰(リグレッション)とは、一度直したはずの不具合が再び現れたり、修正の影響で別の場所が壊れたりすることである。回帰確認は、それが起きていないかを確かめる。具体的には、元の再現手順をもう一度実行し、加えて近くの正常系も確認する。既存テストがあれば実行するのも回帰確認の一部である。
- 具体例:支援ステータス機能なら、直した表示が正しくなったか確認し、さらに他の表示や更新が壊れていないかも見る。第8章では、未提出者フィルタの確認に加え、フィルタなしの全件表示、提出済みフィルタ、
npm testの実行を行う。 - つまずきやすい点:元の不具合の再現手順だけを確認して終わりにしがちだが、周辺の正常系まで見て初めて回帰確認になる。
- 関連語:再現(第8章)、正常系(第8章)、既存テスト(第8章)
- テキスト本文での登場箇所:第8章「再現手順で確認し、回帰確認を足す」
既存テスト
- 読み:きぞんテスト(existing tests)
- 一言で言うと:すでにリポジトリにある、自動で動かせる確認用のコード。
- くわしく:既存テストは、過去に書かれた動作確認のコードで、コマンドで一括実行できる。修正後に実行すると、変更が既存の動きを壊していないかを機械的に確かめられる。ただし、既存テストが通っても、今回の不具合を覆うテストがなければ安心しすぎてはいけない。可能なら、今回の条件を確認するテストを追加する。
- 具体例:支援ステータス機能を直した後、
npm testを実行して既存テストが通るか見る。第8章では、listLearners({ filter: "unsubmitted" })がsubmittedAt === nullの受講者だけを返すテストの追加を検討する。 - つまずきやすい点:既存テストが緑(成功)でも、その不具合をテストが見ていない場合がある。「既存テストにこの観点はなかった」と記録しておくとレビューの判断材料になる。
- 関連語:回帰確認(第8章)、正常系(第8章)
- テキスト本文での登場箇所:第8章「再現手順で確認し、回帰確認を足す」