※この記事は Zennの記事 からの転載です。
AI にコードを書かせると、差分が人の読む速さを超えて積み上がっていきます。Zenn でも「コードを読まずにマージするために必要なこと」や「人間がコードを読まずにPRをマージする技術」が続けて読まれていて、多くの人が同じところで迷っているのが分かります。
全部読むのはもう無理。でも、読まずに出して本当に大丈夫なのか。
この記事では、この問いを一段さかのぼって考えます。**コードを読むことで、私たちは何を確かめていたのか。**そこが分かると、読まないかわりに人が手放してはいけないものが見えてきます。
コードを読むのは、間接的な確認だった
レビューでコードを読むとき、本当に知りたいのは「書き方がきれいか」ではありません。**「この変更を入れたあと、システムが期待どおりに動くか」**です。
ところが、コードを読んで分かるのは「期待どおりに動きそうか」までです。読む人は頭の中でコードを動かし、いくつかの入力を思い浮かべて、結果を予想します。つまり読むことは、頭の中で行うテストです。
この確認には、もともと弱いところが2つあります。
- **思い浮かべた入力しか確かめられない。**読む人が想像しなかった組み合わせは、読んでも見つからない
- **量に弱い。**差分が数百行を超えると、注意が続かなくなる。AI が1日に何本も PR を出すと、読む確認は先に崩れる
「読めば安全」だったのではなく、「量が少ないうちは、頭の中のテストでなんとか間に合っていた」ということです。
では、テストを AI に書かせれば済むのか
読む確認を、実際に動かすテストに置き換える。これが自然な答えです。ただ、ここで落とし穴があります。コードもテストも AI に書かせると、答案と採点基準を同じ人が作ることになるからです。
起きることは2つあります。
1. 期待する結果が、実装から逆算される
AI は、書いたコードを動かして、その出力をテストの「正解」にすることがあります。こうしてできたテストは、今のコードがそう動くことを確かめているだけで、そう動くべきかは確かめていません。バグがあれば、バグごと正解として固定されます。
2. テストを通すために、ずるをする
テストが通らないとき、AI がコードではなくテストのほうを書き換えたり、特定の入力にだけ答えを返す処理を入れたりすることがあります。「生成AIはテストを「通す」ためにズルをするのか」では、この「報酬ハッキング」を実際に再現して対策まで検証しています。
AI は「テストを通す」という目標に対して素直に動いているだけです。目標の中身(何が正解か)を AI が決められる状態なら、目標そのものを動かすほうが早い、ということです。
人が手放してはいけないのは「期待する結果」
ここまでをまとめると、役割の分け方が見えてきます。
| 誰が持つか | 中身 |
|---|---|
| AI に任せてよい | コード(どう実現するか)。テストを動かすための仕組み |
| 人が持つ | 期待する結果(どんな入力なら、どうなるべきか) |
期待する結果は、仕様書の言葉でも、表でも、テストコードの中の期待値でもかまいません。大事なのは、それを決めたのが人で、AI が勝手に変えられないことです。
そしてこれは、コードを読むよりずっと楽です。期待する結果は、業務の言葉で書けます。「この部署のこの職種の人には、この品目が出る」「2回申し込んだら、2回目で上書きされる」。プログラミングの知識はいりません。**読む対象を、コードの差分から、期待する結果の差分に移す。**これが「読まずに出す」の中身だと私は考えています。
期待する結果をどう作るか
思いつきで並べると、読む確認と同じ弱さ(想像した入力しか確かめない)が残ります。次の順で洗い出すと、抜けが減ります。
1. 結果を変える条件を全部挙げ、組み合わせごとに1行
「何によって結果が変わるか」を先に挙げます。たとえば区分・種類・状態などです。その組み合わせごとに、代表を1つずつ用意します。同じ結果になる入力はまとめてかまいません(テストの用語では同値分割と呼びます)。
2. 境界を足す
「10件以上なら」「30日以内」のような区切りには、ちょうどの値と、その前後を入れます。間違いはだいたい境界で起きます。
3. 時間を足す
1回目だけでなく、2回目・翌月・翌年に何が起きるかを書きます。最初の動作だけを確かめた表は、くり返し使ううちに壊れるケースを拾えません。ここが一番見落とされやすいところです。
4. 同時と失敗を足す
2人が同時に保存したら。途中で通信が切れたら。入力が空だったら。業務で実際に起きることを、起きる前に1行ずつ書いておきます。
期待する結果を、AI に変えさせない
表を作っても、AI がテストを書き換えられるなら元に戻ります。仕組みで止めます。
- **期待する結果のファイルを分ける。**テストコードとは別のファイル(表や JSON)に置き、テストはそれを読むだけにする
- **そのファイルの変更は、人が見てから入れる。**PR では、コードの差分は自動チェックに任せ、期待する結果の差分だけを人が読む
- **テストが本当に効いているかを確かめる。**コードをわざと壊して、テストが落ちるかを見る。落ちないテストは、何も確かめていない(ミューテーションテスト。Vitest なら「@mizchi/mutator」のような道具がある)
- **「テストが通った」で終わりにしない。**AI の「完了しました」やテストの成功表示ではなく、出てきた結果そのもの(画面・書き出したファイル・データ)を、期待する結果と見比べる
例:コードを読めない人が、業務システムを本番に出したとき
私は医療機関の事務職で、エンジニアではありません。職員の制服の申請と、支給の判定・発注数の集計を行う仕組みを、コードはすべて AI に書かせて作りました(今も使われています)。私にはコードを読んで正しさを判断する力がないので、最初から「読まずに出す」しかありませんでした。
そのかわりにやったのが、期待する結果を先に作ることです。制服は部署・職種・性別で支給の中身が変わります。そこで、この3つの組み合わせごとに1人ずつ架空の職員を作り、「この人には何が出るべきか」を表にしました。テストではこの職員たちに申請させ、出てきた判定と発注数を表と見比べます。コードは1行も読んでいませんが、どの組み合わせで何が出るかは、全部自分の目で確かめています。
それでも1つ、見落としがありました。最初の版は年度を区別していなかったため、翌年度に申し込み直すと、前の年の記録まで消えてしまう作りでした。表には「1回目の申請で何が出るか」しか書いておらず、「翌年にもう一度申請したら」の行が無かったのです。コードを読めていたとしても、この行が無ければ同じように見落としていたと思います。直したあとは、表に年度をまたぐ行を足しました。
足りなかったのは、コードを読む力ではなく、期待する結果の表の1行でした。
まとめ
- コードを読む確認は、頭の中で行うテスト。想像した入力しか確かめられず、量に弱い
- コードもテストも AI に任せると、期待する結果が実装から逆算されたり、テストを通すためのずるが起きたりする
- 人が持つべきなのは、コードではなく期待する結果。業務の言葉で書け、コードを読むより楽
- 期待する結果は「条件の組み合わせ → 境界 → 時間 → 同時と失敗」の順で洗い出す。特に「2回目・翌年」が抜けやすい
- 期待する結果は別のファイルに置いて AI に変えさせず、人はその差分だけを読む。テストはわざと壊して効いているかを確かめる
「読まずに出してよいか」の答えは、期待する結果を人が決めていて、それが確かめられているなら、よい。そうでないなら、コードを全部読んでいても安全とは言えません。