はじめに
最近、AI Coding Agentを使っていて、かなり実装速度が上がりました。
Repositoryを調べてもらい、実装してもらい、テストを書いてもらう。
失敗したらログを解析して、そのまま修正まで進めてもらう。
以前なら半日以上かかっていた変更が、かなり短い時間で形になることもあります。
これは非常に便利です。
一方で、実際に使い続ける中で別のところが苦しくなってきました。
コードを作る速度に、レビューする速度が追いつかない。
AIはどんどんコードを書ける。
しかし、人間がコードを理解する速度まで同じように上がったわけではありません。
AIによってImplementation側のボトルネックを取り除いた結果、今度はVerification側がボトルネックになる。
最近、この問題をかなり実感するようになりました。
最初は「AIにレビューさせればいい」と思った
当然、最初に考えるのはこれです。
AIで作ったなら、AIにレビューさせればいい。
実際、かなり役に立ちます。
AI Reviewerは、
- Diffの要約
- 明らかなBug
- Null Handling
- 型の問題
- Test不足
- 不自然な実装
などを探す用途では優秀です。
自分も使っています。
ただ、使っていて少し違和感が残りました。
確かに、人間が500行を直接読むより速い。
しかし、よく考えるとレビュー対象は依然として500行のDiffのままです。
人間が読む前にAIが読んでいるだけです。
レビューの問いも、
このコードに問題はないか?
のままです。
AIによってChange Volumeそのものが増えていくなら、レビューを高速化するだけではなく、レビューの起点そのものを変えた方がいいのではないか。
最近はそう考えるようになりました。
Diffを見る前に「何が変わったのか」を見る
今は、変更されたファイルを上から読む前に、
このPRによって、システムの振る舞いとして何が変わったのか?
を見るようにしています。
例えば、配信処理のRetry Logicを変更したPRがあったとします。
変更ファイルが、
delivery.service.ts
delivery.worker.ts
delivery.repository.ts
delivery.integration.spec.ts
だったとします。
この情報だけでは、まだレビューの優先順位は分かりません。
そこでファイル一覧ではなく、まず意味上のChangeへ変換します。
Partial Failure発生時、未処理対象だけをRetryするようになった。
次に考えるのは、
これが壊れたら、何が起きるのか?
です。
例えば、
- 同一ユーザーへの二重処理
- Partial Failure後のState不整合
- Retry対象の欠落
- Queue Jobの重複
などが考えられます。
この順番に変えると、レビューすべき場所がかなり見えやすくなりました。
全部のDiffを同じ濃度で読む必要はなかった
以前は、変更されたファイルを順番に確認していました。
もちろん、今でもコードそのものは読みます。
ただ、AIによって変更量が増えてくると、その方法はかなり重くなります。
先ほどのRetry Logicなら、本当に深く見たいのは例えば、
- Atomic Claim
- Retry Condition
- Idempotency
- State Transition
- Job Identity
あたりです。
NamingやFormattingまで同じ濃度で見る必要はありません。
つまり、
500行全部を同じ濃度で読む
のではなく、
Riskに直結する部分を重点的に読む
ということです。
コードを読まないのではありません。
読むべき場所を先に決める。
この違いはかなり大きいと感じています。
自分の中では「Code Review」より「Change Verification」に近い
最近やっていることを整理すると、こうなります。
この記事では、この考え方を便宜上、
Risk-based Change Verification
と呼びます。
ポイントは、最初にDiffを読むのではなく、
- 何が変わったのか
- 何が壊れる可能性があるのか
- どこに影響するのか
- それを何によって確認したのか
- どのコードを人間が深く読むべきか
という順番で見ることです。
Riskが分かると、見るべきBoundaryも見えてくる
先ほどのRetry Logicを例にします。
最も重要なRiskが、
同じ対象へ二重処理されること
だったとします。
すると見るべきBoundaryも自然に絞られます。
この場合、レビューで重要なのは、
- DBで正しくClaimされるか
- Queueへ重複投入されないか
- Workerが再実行されても安全か
- External APIへ二重Requestされないか
です。
ファイル単位で見るより、System Boundary単位で見る方がFailureとの関係を理解しやすいと感じています。
「テストがあります」ではなく「何を確認したか」
テストの見方も変わりました。
以前なら、
テストが追加されているか?
を見ることが多かった。
今は、
このRiskは何によって検証されているか?
を見るようにしています。
例えば二重処理がRiskなのに、
expect(response.status).toBe(200);
だけを確認していても十分ではありません。
本当に確認したいのは、
External API Request Count == 1
かもしれません。
例えば次のように整理できます。
| Risk | Verification | Evidence |
|---|---|---|
| 二重処理 | Integration Test | External API Request Count |
| State不整合 | Integration Test | DB State |
| Job重複 | Integration Test | Queue State |
| 型破壊 | Static Analysis | Type Check |
重要なのはテスト本数ではありません。
RiskとEvidenceが対応しているか。
こちらを見るようになりました。
「何を確認していないか」が意外と重要
もう一つ、レビュー時にかなり重要だと思うようになったのが、
Not Verified
です。
AI Agentは自然に、
実装しました。
テストしました。
All Tests Passed.
と報告してきます。
これは間違いではありません。
ただ、Reviewerとしてはそれだけでは足りません。
知りたいのは、
何を確認していないのか?
です。
例えば、
Verified
- DB State
- Queue State
- Retry後のRequest Count
Not Verified
- Production固有のNetwork Failure
- External API Timeout
- 高Concurrency環境
ここまで分かれば、人間は初めて、
この未検証Riskを許容してよいか?
を判断できます。
個人的には、場合によってはVerifiedよりNot Verifiedの方がレビュー材料として重要だと感じています。
AIには「レビュー」より「レビュー材料」を作らせる
この考え方に変えてから、AI Reviewerへの期待も少し変わりました。
以前は、
このPRに問題がありますか?
と聞くことが多かった。
今は、それよりも、
- What changed
- Main risks
- Affected boundaries
- Verified
- Not verified
- Human review focus
を整理してもらう方が使いやすいと感じています。
つまり、
AIにApproveさせるのではなく、人間が判断するための情報を圧縮させる。
この使い方の方が、Change Volumeが増えた環境には合っている気がしています。
すべてのPRを同じ濃度で見る必要もない
ChangeとRiskが整理できれば、Review Depthも変えられます。
例えば、
Low Risk
- Documentation
- Typo
- Test-only Change
- 単純なRefactoring
High Risk
- Authorization
- Payment
- DB Migration
- Concurrency
- Retry
- Idempotency
- Transaction
- State Machine
など。
もちろんRisk LevelはProjectによって変わります。
重要なのは、
Diffの大きさではなく、RiskによってReview Costを変える
という考え方です。
将来的にはCI/CDにもつなげられそう
今のところ、自分はHuman Reviewの材料として使う程度で十分だと考えています。
ただ、この考え方は将来的にはCI/CDにも発展できそうです。
例えばHigh Riskなら、
- Integration Test必須
- Human Review必須
- 特定Required Check必須
とする。
Low Riskなら既存CIとAI Reviewを中心にする。
こうすれば、
Risk-based Testing / Code Review / CI/CD
を同じQuality Modelでつなげられるかもしれません。
ただし、ここはいきなり自動化する必要はないと思っています。
この方法にも当然Riskはある
Risk-based Change Verificationが正解だ、と言いたいわけではありません。
特に大きな問題があります。
AIがRiskを見落としたらどうするのか?
当然あり得ます。
本当はHigh Riskなのに、Low Riskと判断する可能性もあります。
さらに実装したAgent自身に、
- Test
- Risk Analysis
- Verification
- Review
まで全部任せれば、
という構造にもなり得ます。
これでは以前の記事で書いた問題に戻ります。
重要なのはAI Agentの数ではなく、評価軸の独立性です。
そのため、AIのRisk Analysisだけを唯一のQuality Gateにするべきではありません。
- Static Analysis
- Existing Tests
- CI
- Integration Test
- Human Knowledge
など、異なるSignalを残す必要があります。
まとめ
AI Coding Agentを使っていて、自分が最初に感じたのは、
実装は速くなったのに、レビューはあまり速くならない
という問題でした。
最初はAI Reviewerで解決できると思っていました。
実際、かなり助けになります。
ただ、AI Reviewerを追加するだけでは、レビュー対象は依然としてDiffです。
そこで最近は、
という順番で見るようになりました。
AIにはコードを書いてもらう。
テストも作ってもらう。
レビュー前の情報整理もしてもらう。
その代わり、人間はすべてのDiffを同じ濃度で読むのではなく、
何が変わったのか?
何が壊れる可能性があるのか?
それは何によって確認されているのか?
何をまだ確認していないのか?
を見る。
その上でRiskの高いコードを深く読む。
AIがコードを書く速度に、人間がコードを読む速度で対抗する必要はない。
人間が見るべきものを変える。
まだ試行中ですが、今のところ自分はこの方向がAI時代のCode Reviewには合っているのではないかと考えています。
おまけ:実際に使うAI Script
最後に、この考え方を実際のレビューへ落とすためのAI Scriptを載せておきます。
目的はAIに、
問題ありません
と言わせることではありません。
Human Reviewerが見るべきRiskとEvidenceを整理させることです。
# AI Script: Risk-based Change Verification
## 目的
この変更について、単純なCode Reviewではなく
Risk-based Change Verificationを実施してください。
目的は「問題ありません」と結論付けることではありません。
Human Reviewerが重点的に確認すべき
RiskとEvidenceを明確にしてください。
---
## 1. Change
変更ファイルの列挙ではなく、
「システムの振る舞いとして何が変わったか」
を3〜5項目以内で整理してください。
---
## 2. Risk
変更によって発生し得るFailure Modeを抽出してください。
必要に応じて以下を確認してください。
- Boundary
- State Transition
- Retry
- Concurrency
- Idempotency
- Transaction
- Authorization
- External API
- Database
- Queue
関連しない項目を無理に挙げる必要はありません。
重大度と発生可能性を考慮し、
Human Reviewが必要なRiskを優先してください。
---
## 3. Affected Boundary
変更が影響するSystem Boundaryを整理してください。
特に以下を明示してください。
- Contractが変わる箇所
- Stateが変わる箇所
- External I/O
- Transaction Boundary
- 非同期処理
---
## 4. Verification Evidence
各Riskについて、以下を対応付けてください。
- Verification Method
- Test Layer
- Oracle
- Evidence
テストが存在するだけではEvidenceとしないでください。
「何を観測し、
何をもって成功と判断しているか」
まで確認してください。
---
## 5. Not Verified
現在の
- Test
- CI
- Static Analysis
- Review
では確認できていないRiskを明示してください。
不明な場合は推測で補完せず、
「確認できない」
としてください。
---
## 6. Review Priority
Human Reviewerが確認すべき箇所を、
### High
重大なFailureにつながるため必ず確認する
### Medium
可能であれば確認する
### Low
Static Analysis / Test / AI Reviewに委譲可能
の3段階で分類してください。
可能であれば、
- File
- Function / Class
- Risk
- 確認理由
も記載してください。
---
## 7. Output
最後に以下を簡潔にまとめてください。
### What changed
システムの振る舞いとして何が変わったか
### Main risks
最も重要なFailure Mode
### Affected boundaries
どのSystem Boundaryへ影響するか
### Verified
何が、どのEvidenceによって確認されているか
### Not verified
現在確認できていないもの
### Human review focus
Human Reviewerが重点的に確認すべき場所
---
## 制約
- All Tests Passedだけで安全と判断しない
- Coverage率だけで品質を判断しない
- Change VolumeだけでRiskを判断しない
- 実装者の意図を正しいものとして前提にしない
- 不明な情報を推測で補完しない
- Low Riskを無理に問題化しない
- AI自身の評価結果を唯一のQuality Gateとしない
このAI Scriptの出力は、Approve判定そのものではありません。
あくまで、
人間がレビューするためのReview Material
として利用します。
AIにコードを書かせる。
AIにテストを書かせる。
そしてAIに、
「どこを人間が見るべきか」まで整理させる。
その上で、最後の判断はRiskとEvidenceを見ながら人間が行う。
今のところ、自分はこの使い方が一番しっくり来ています。