はじめに
GMOコネクトの永田です。
前回、引き継いだ案件の git log からレビュー観点を掘り起こす話を書きました。
今回はその続きで、作った観点が本当に効くのかを測っています。
きっかけは、その案件で外部連携の試験に入ってからAPIの改修漏れが次々に出たことです。再発防止の案はいくつも出ます。チェックリストを足す、渡す資料を整える、実装後に機械照合を入れる。どれがどれだけ効くかは主張だけでは決まらないので、事故が起きる前のコミットまで戻し、そこから設計をやり直させて測りました。
- 条件19通り、同じ条件を3回ずつ、のべ42回
- うち30回はチェックリストの書き方を変えたA/B、12回は渡す資料を変えたA/B
- 漏れの原因はいくつもあります。この記事が扱うのは、現況の資料と、洗う観点の2つです。全体像は5章に置きました
チェックリストは効きました。ただし効いたのは書き方を変えた2項目だけで、どう書き換えても出てこない項目が残りました😇
それを検出できるようにしたのは、チェックリストではなく既存システムの棚卸しでした。しかもその棚卸しは、現行ソースの静的解析でほぼ機械生成できます。新しい観点を考えるより、いま何がどうなっているかを先に書き出したほうが早かった、という話です。
これはAIに設計をやり直させた結果で、人がやり直した結果ではありません。人がやる洗い出しを代理させたベンチマークとして読んでください。裏を返すと、同じ設計を19通りの条件で42回やり直すのは人手では試せません。のべ8時間ほどで済んだのは、やり直しをエージェントに任せられたからです。開発プロセスそのものをA/Bで比べられるようになったこと自体が、今回いちばんの発見だったかもしれません。
先にまとめ
比べたのは、チェックリストの整備と、既存ドキュメントの整備です。どちらが効くかは、設問で逆になりました。
設問は性格の違う2つを立てました。設問の中身と正解データの作り方は1章で書きます。表の網羅率は正解のうち何件を挙げられたか、精度は挙げた行のうち何件が本当に対象だったかです。難所6項目は、正解のうち実作業では終盤まで誰も気づかなかったものを指します。
整えた既存ドキュメントは3本です。うち2本は現行ソースの静的解析で機械生成できました。
設問1: 使わなくなった機能を、どこまで消すか
| 与えたもの | 網羅率 | 難所6項目 | 誤って挙げた行 | 精度 |
|---|---|---|---|---|
| どちらも無し(1回) | 87.5% | 2 | — | — |
| チェックリストを整備した状態(3回) | 83.3% | 4.0 | 39 | 27% |
| +既存ドキュメントの整備(3回) | 98.6% | 3.7 | 2 | 67% |
差が大きかったのは既存ドキュメントの整備です。網羅率も精度も大きく上がりました。一方、難所の検出を上げたのはチェックリストのほうで、既存ドキュメントを足しても平均は動いていません。ただし内訳は入れ替わっていて、9回とも検出できなかった項目が出るようになった代わりに、別の項目が落ちました。この「足すと別のところが薄くなる」現象は4章でもう一度出てきます。
設問2: 使うキーを変えたとき、どこに影響が出るか
| 与えたもの | 網羅率 | 3回の和集合 | 誤って挙げた行 |
|---|---|---|---|
| どちらも無し(1回) | 60.0% | — | — |
| チェックリストに観点として書く(3回) | 58.1% | — | — |
| 同じ内容を手順の形で与える(3回) | 76.2% | 91.4% | 24 |
| +既存ドキュメントの整備(3回) | 78.1% | 97.1% | 58 |
こちらはチェックリストの書き方で差が出ました。ただし観点として書いただけでは、網羅率はチェックリスト無しと変わりません。そして既存ドキュメントを足しても網羅率の平均は動かず、誤って挙げた行はむしろ24から58へ倍以上に増えました。上2行の誤検出は採点方法が違うので空けています。
1. 同じチェックリストでも、書き方で結果が変わった
測ったのは、ある共通機能を外部システムへ載せ替える改修で、直す対象を洗い出すところです。事故が起きる前のコミットからソース一式・要件定義書・改修前のAPI定義だけを取り出して Claude Code に渡し、「改修対象を漏れなく挙げよ」と指示しました。以下、挙げた・落としたの主語はすべてこのエージェントです。改修後の成果物や影響範囲の資料は一切渡していません。それを再現できるかが問いだからです。
正解は、最終的に確定した改修対象100件弱です。設問はいくつか立てましたが、この記事で扱うのは先に示した2つです。毎回、独立したセッションで走らせ、同じ条件は3回以上くり返しています。
先に、測った組み合わせを書いておきます。チェックリストを土台にして資料を1つずつ足していく積み上げで、2×2の総当たりではありません。
| チェックリスト無し | チェックリストあり | |
|---|---|---|
| もとの入力 | 1回 | 3回 |
| +既存ドキュメント | 未測定 | 3回×2条件 |
資料を足した条件は、すべてチェックリストを渡した状態の上に積んでいます。「既存ドキュメントだけあればチェックリストは要らない」は、この実験からは言えません。
効いたもの1: 洗うべき層を並べて渡す
機能を廃止する設問には、実作業では終盤まで誰も気づかなかった難所が6項目あります。判定の本体が共通ライブラリ側にあった、CDNのエッジ側にルーティング設定が残っていた、どこからも呼ばれないスキーマ定義が残っていた、といったものです。いずれも、廃止するパス名でgrepしても出てきません。
チェックリストには「廃止のときに洗う層」、つまり消し残りが出る場所を10個並べました。
① 画面
② API・インタフェース定義
③ ハンドラ本体
④ 共通ライブラリの判定関数・ログ書込
⑤ 内部ルータ・ディスパッチの分岐
⑥ CDN・エッジのルーティングと配信設定
⑦ バッチ・ジョブ・スケジュール定義
⑧ DBのテーブル・カラム・データ
⑨ 権限マスタ・定数・コード値・設定ファイル
⑩ 到達不能になったスキーマ定義
さきほどの難所3つは、④と⑥と⑩にあたります。これを並べて渡すと、3回とも6項目のうち4項目が挙がりました。並べない場合は1〜2項目で、ほとんど拾えません。
層を並べなかった回の出力は、30行を30種類バラバラの区分で書いていました。列挙はできても、体系が無いと「この層は洗ったか」の自己点検ができません。
効いたもの2: 観点ではなく、手順として書く
使うキーを変える設問では、チェックリストにこう書いていました。
旧キーの使用箇所を全数列挙する
正解の35件のうち、旧キーが改修前ソースに現れるのは30件です。残り5件は旧キーが出てこないので、機械検索では原理的に届きません。つまり 30件が機械検索の理論上限 で、これを先に計算してから測りました。
| 条件 | 回ごとの到達(機械可達30件) | 平均 |
|---|---|---|
| チェックリスト無し | 19 | 19 |
| 観点として与えた | 15 / 26 / 15 | 18.7 |
| 3つの軸に分解して与えた | 23 / 13 / 16 | 17.3 |
| 全数インベントリを強制した | 17 / 14 / 21 | 17.3 |
観点をどう細かく書いても、到達件数はチェックリスト無しと同じでした。細かくすれば拾えるだろうと思って3軸に分解したバージョンまで作りましたが、元の版と同じ値です。全数インベントリを強制した条件では、誤って挙げる行が19から9へ半減した一方、到達件数は変わらず、コストは倍以上になりました。
そこで同じ内容を、検索対象と突合先と変換の形まで書き下しました。プロンプトへの追記は次の14行だけです。
【作業の進め方(機械検索を先に行う)】
設計を書き始める前に、必ず次を実行すること。
1. 変更前のキー名を、改修前ソース全体で機械検索する。
検索語には表記ゆれ(スネークケース・キャメルケース・先頭大文字)をすべて含めること。
ヒットしたファイルの一覧を作る。
2. 各Lambdaのルータ定義(path とメソッドからハンドラ名への対応表)を読み、
ヒットしたハンドラファイルを path × HTTPメソッド に変換する。
3. その変換結果を表1の出発点にする。ヒットが無いエンドポイントでも、
要件から改修が要ると判断できるものは表1に加える。
4. 機械検索では出てこないが改修が要るものを表5に分けて書く。
【表】機械検索では出てこない改修対象
| # | 対象 | なぜ機械検索で出ないか | 何から気づけるか |
末尾の2行は、出力してほしい表の見出しをそのまま指定したものです。実際のキー名は伏せています。
| 条件 | 回ごとの到達 | 平均 |
|---|---|---|
| 観点として与えた | 15 / 26 / 15 | 18.7 |
| 手順として与えた | 30 / 18 / 30 | 26.0 |
3回のうち2回が上限の 30/30 に届きました。
同じことを言っているつもりでも、「全数列挙する」では実行されず、「何を検索して、何と突き合わせて、どの形に変換するか」まで書くと実行されます。実験ではチェックリストではなくプロンプトに足して測りましたが、この結果を受けてチェックリストの該当項目も手順の形に書き直しました。チェックリストを整備していていちばん効いた学びがこれです。
なお、良かれと思って足した指示が逆効果になることもありました。当たりは案件ごとに違うので、実際に測って確かめるほかありません。
2. それでも検出できないものがあった
書き方を直して、効く形は分かりました。層を並べれば難所の検出は 4/6 まで上がります。それでも、残りは何回やり直させても検出できません。
| 項目 | 結果 |
|---|---|
| 集約によって不要になったはずの2メソッド | 9回とも出ず |
| 取込履歴テーブルの種別コードを消してはいけない、という判断 | 9回とも出ず |
| 旧キーが出てこない5件 | どの条件でも 0〜2件 |
1つめは、要件定義書のどこにも「この2メソッドを廃止する」とは書かれていません。「操作を1つのメソッドに集約する」という設計側の決定から派生した結果です。ある回は、このAPIを明示的に検討したうえで「存続を確認」と書いて対象外に落としていました。知らなかったのではなく、要件からは存続に見えるのです。
2つめは、まったく手が届かなかった上限です。ファイルの一括アップロード機能を廃止しても、過去の取込履歴がその種別コードを参照しているので、消すと履歴が不明種別になります。この時点では、消してはいけないものを見分ける判断は自動化できない、と結論づけました。
3. 上限を突破したのは、既存システムの棚卸しだった
そこでチェックリストではなく、渡す資料のほうを変えて測り直しました。渡したのは既存システムの現況と、この改修で下した決定だけです。改修方針や変更内容は書いていません。
唯一の上限は、既存の区分値一覧で突破できた
現行の履歴テーブルに、どの処理がどの区分値を書き込んでいるかを静的解析で全件抽出し、末尾に1行だけ手で足しました。
これらの区分値は、書き込み時点の値が履歴レコードに残り続ける。
これだけで、9回とも検出できなかった判断が、既存ドキュメントを渡した6回すべてで出るようになりました。出力は「停止(過去レコードは残す)」と正解と同じ結論を書き、残すか消すかで判断が割れる点を未確定事項として起票した回もあります。
2章で「この判断は自動化できない」と書いた自分の結論を、あとの実測で自分で覆したことになります。足りなかったのは推論能力ではなく、現行システムの現況が書き出されていないこと でした。
同じように、共通の認証処理が何を操作者としてログに書いていて、それが画面のどの列に出ているかを書いた画面項目定義書を渡すと、対照では3回とも落としていた操作ログの改修が拾えるようになりました。この資料にも「変更すべき」とは一言も書いていません。現行の事実を書いただけです。
決定に「撤回済」を持たせたら、9回とも検出できなかった項目が毎回出た
もう1本が決定記録です。全部で14行あり、そのうち2行を抜き出します。
| ID | 決定内容 | 状態 |
|---|---|---|
| D-06 | ある更新操作を単一のメソッドに集約する。集約先はPOSTとする | 現行 |
| D-07 | 集約先をPUTとする | 撤回済。D-06に置き換わった。本行の内容で設計・実装してはならない |
削除対象のメソッドは一言も書いていません。 それでも、9回とも検出できなかった2メソッドが毎回出るようになりました。出力はこう書いています。
D-07は撤回済。本書はD-06(集約先はPOST)に従って設計している
続きがあります。この決定を検討した文書は、実はリポジトリに実在していました。ただし結論が逆です。「PUTに集約する」と書かれていて、実際に出荷されたのはPOSTへの集約でした。逆転を記録した文書は1本も無く、最終結論の言い回しで全文検索しても0件です。
つまり、この検討書をそのまま入力に足すと答えは悪化します。足りなかったのは情報量ではなく、決定の版管理でした。
設問1の結果
設問1の全体では、こうなりました。
| 入力 | 平均網羅率 | 3回の和集合 | 提示した行数 | 誤って挙げた行 | 精度 |
|---|---|---|---|---|---|
| もとの入力 | 83.3% | 91.7% | 81 | 39 | 27% |
| 既存の現況+決定記録 | 94.5% | 100% | 46 | 5 | 52% |
| +画面単位の変更注記 | 98.6% | 100% | 36 | 2 | 67% |
そして1回あたりのコストは増えていません。効果が大きかったのは網羅率より精度のほうで、人が仕分ける行が39から2になりました。
整備の中身は、思ったより軽かった
棚卸しと聞くと重い話に聞こえますが、スクリプトで出せなかったのは決定表の14行だけでした。
| 渡した資料 | 何を書いたか | 作り方 | 分量 |
|---|---|---|---|
| 画面項目定義書 | 既存の現況 | ルータ定義からコンポーネント、API層、エンドポイント定数までを静的解析 | 169行 |
| 区分値一覧 | 既存の現況 | 履歴テーブルへの書き込み呼び出しを全件抽出。注記1行だけ追記 | 82行 |
| 設計決定記録 | この改修の決定 | 既存の資料から起こす。決定を並べるだけで、そこから何を廃止するかは書かない | 30行(決定14件) |
既存の現況を書いた2本は、現行ソースから機械生成できました。載せる行を選ぶ判断は入っていません。
対してチェックリストのほうは、新規に書いた章だけで88行、確定版では128行あります。既存の汎用チェックリスト2本と合わせると600行を超えます。観点は考えて書き起こすしかありませんが、現況はコードから引き出せます。書いた量と効いた量が、きれいに逆でした。
4. 同じことを別の設問でやったら、効かなかった
ここまでは設問1の話です。同じ入力を、キーを変える設問2にも当てました。
| 入力 | 平均網羅率 | 3回の和集合 | 誤って挙げた行 | 精度 |
|---|---|---|---|---|
| もとの入力 | 76.2% | 91.4% | 24 | 40% |
| 既存の現況+決定記録 | 75.2% | 94.3% | 33 | — |
| +画面単位の変更注記 | 78.1% | 97.1% | 58 | 25% |
網羅率の平均は動かず、和集合は少し上がり、誤って挙げた行は倍以上に増えました。廃止の設問とは効き方が逆です。
理由ははっきりしています。設問1では、既存の現況が「いま何が存在するか」を確定させるので母集団が締まり、過検出が消えます。設問2では、同じ資料が改修の候補を増やす方向に働くので、拾いも増えるかわりに誤りも増えます。
副作用も出ました。もとの入力では取れていた後方互換の項目が、整備後には落ちています。資料を足すと、書いてある層は厚くなり、書いていない層は薄くなります。 足せば足すほど良くなるわけではありませんでした。
既存の棚卸しが強いのは、母集団を確定させる問いです。探索そのものが問いになっている場合は、手順を書いたチェックリストのほうが素直に効きました。
どう使い分けるか
盛れば盛るほど良くなるわけではありませんでした。ただし、どちらを足しても悪くなるという意味でもありません。実測から言えるのは4点です。
問いの型で、渡すものを変える。 「いま何が存在するか」を確定させたい問いには、現況の棚卸しを渡します。「どこに影響が及ぶか」を探す問いには、手順を書いたチェックリストを渡します。逆に当てると、網羅率は変わらないまま誤検出だけが増えました。
単発の結果で判断しない。 1回あたりの網羅率は76〜98%とばらつきますが、3回の和集合はどちらの設問でも97%を超えました。数回走らせて和集合を取ります。
網羅率と一緒に精度を見る。 設問1では人が仕分ける行が39行から2行に減りました。網羅率だけを追うと、拾える代わりに人の負荷が倍増していても気づけません。人の仕事は「探す」から「仕分ける」へ移ります。
1回に全部渡さない。 今回はどの条件も1回のコマンドで走らせており、資料も観点も同じ1回に盛っています。増やすほど別のところが薄くなったのはその結果です。洗い出しのときに渡す資料と、結果をレビューするときに渡す資料は本来違うはずで、構成を変えた2系統を別々に走らせて和集合を取ったときは、片方では届かなかった35件に全数到達しました(1回きりの観測で、再現は確かめていません)。何をいつどこまで渡すかは、まだ人の側に残ります。
5. ここまでは、何を直すかを決めるところまでの話です
最後に、ここまでの話が届く範囲を書いておきます。この案件で最終的に確定した改修対象のうち、4分の3は設計の初版に書かれていました。 廃止だけを見れば9割です。書かれていたのに、手が付いていません。
つまり洗い出しの網羅性を上げても、今回の漏れが全部止まるわけではありません。原因を整理すると、少なくともこれだけのパターンがあります。
| 原因の型 | この記事 |
|---|---|
| 現況が書き出されていない | 3章と4章で扱う |
| 洗う観点が足りない | 1章で扱う |
| 完了の判定条件が間違っている | 扱わない |
| 未確定のまま次工程へ渡している | 扱わない |
| 成果物どうしの整合を確かめる場が無い | 扱わない |
| 試験が設計と同じ材料から作られている | 扱わない |
測ったのは上2つです。残りも別に測っているので、結果だけ書いておきます。
- 判断の書式。「APIの定義がもう消えているから廃止作業は実施不要」という判定で、10エンドポイント程度が見積から落ちていました。同じ問いを根拠つきで問い直させると、チェックリストを渡さなかった回も含めて4回とも「実施必要」と答えます。足りなかったのは観点ではなく、根拠つきで問う場でした
- 機械照合。確定した廃止台帳と、リポジトリにあるデプロイ用API定義を突き合わせるだけのチェックです。環境にデプロイしなくても、AIを使わなくても動きます。過去のコミットに当ててみると、人が漏れに気づいて起票する6週間前の時点で、すでに同じ項目を指せていました(6コミット分を流して実行3分)。ただし台帳が要ります
設問を当てること(チェックリスト)と、母集団を作ること(台帳)は別の対策です。片方だけでは止まりません。
6. 測り方と、この結果の限界
同じ条件でも、網羅率は 42.9% から 85.7% までばらつきました。1回の結果では優劣を論じられないので、同じ条件は3回以上くり返し、有意と書いたのは並べ替え検定を通したものだけにしています。それでも3回どうしなので、小さい差は判定できません。実際、1回だけで出した結論をあとから撤回しています。
そのうえで、この結果には前提が付きます。
- 入力を作ったのは、正解を知っている自分です
- 正解データは実作業から作ったので、当時誰も気づかなかった漏れは入っていません。網羅率は上振れしうる値です
- 現況の資料を維持するコストは測っていません。今回は静的解析で1回生成しただけです
まとめ
- チェックリストで効いたのは、洗うべき層を並べて渡すことと、観点を手順の形に書き直すことの2つでした。書き足したのは14行です
- それでも出てこなかった項目を拾ったのは、既存システムの現況を書き出した資料でした。しかもそれは、現行ソースの静的解析で機械生成できます
- 1回の結果はばらつきます。数回走らせて和集合を取ると、網羅率はどちらの設問でも97%を超えました
- ただし現況の資料が効いたのは、母集団を確定させる問いだけです。別の設問では誤検出が倍以上に増えました
- そもそも改修対象の4分の3は設計の初版に書かれていました。網羅性を上げるだけでは、今回の漏れは止まりません
チェックリストを整備した時間が無駄だったわけではありません。ただ、新しい観点を書き足すより先に、既存システムが今どうなっているかを機械で書き出しておくべきでした。
最後に、GMOコネクトではサービス開発支援や技術支援をはじめ、幅広い支援を行っておりますので、何かありましたらお気軽にお問合せください。