1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AIのコードは読めば安全なのか。人が決めるべきはコードではなく期待する結果

1
Posted at

※この記事は 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 に変えさせず、人はその差分だけを読む。テストはわざと壊して効いているかを確かめる

「読まずに出してよいか」の答えは、期待する結果を人が決めていて、それが確かめられているなら、よい。そうでないなら、コードを全部読んでいても安全とは言えません。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?