はじめに
AIによるコーディングが普及し、レビューのボトルネックの深刻化をよく聞くようになったし、自分たちも感じている。 ペアプログラミングの考えを現代版にしたペアプロンプティングを考えているので、その紹介をする
AIによってコードレビューのボトルネックが深刻化した
ここ最近の開発作業のほとんどは、「自分もしくは他人がAIを使って生成したコードをレビューする時間」がほとんどな気がする。プロンプトを書いているか、出力されたコードをレビューするかのどちらかがほとんどの時間を占めている。
しかし、「コードレビューがボトルネック」という問題は、実はAI以前からずっと議論されてきた。
SmartBearがCiscoで行われた2,500件のコードレビューを分析した研究では、人間が一度に効果的にレビューできるコード量は400行までであり、1時間を超えると集中力が切れて欠陥の発見率が急激に低下することが示されている。
Best Practices for Peer Code Review
A successful peer review strategy requires balance between strictly documented processes and a non-threatening, collaborative environment. Highly regimented peer reviews can stifle productivity, yet lackadaisical processes are often ineffective. Managers are responsible for finding a middle groun...
つまり、人間がコードを読んで理解し、フィードバックを返すというプロセス自体が、もともと認知負荷が高く、物理的にも時間がかかる「関所」になっていた。
そこにAIが登場し、コードの生成量が爆発的に増えた。レビューすべきコードの量は増えたが、人間がコンテキストを理解するスピードは変わっていない。その結果、既存のボトルネックがいよいよ限界を迎えている。
この記事だと、レビューする人数(承認レイヤー)が増えるほど開発速度が指数関数的に遅くなる(1層につき10倍遅くなる)とも言われている。
Every layer of review makes you 10x slower
We’ve all heard of those network effect laws: the value of a network goes up with the square of the number of members. Or the cost of commun...
それほど「レビュー」という作業は開発プロセスの中でも支配的で、時間がかかる。
人間がしなくていいレビューと、しないといけないレビューを整理する
ボトルネックを減らすためにまず思いつくのは、AIによるレビューの自動化になるのだろう。Claude CodeのコードレビューやCodeRabbitなどが普及してきていて、各社レビューがネックになっていることを受け止め、解消しようとしている。
ただ、レビューの中にも「人間がやらなくていいレビュー(=AIに任せて良いレビュー)」と「人間がしないといけないレビュー」の2つがあると考えていて、その整理をする。
人間がやらなくていいレビュー(=AIに任せて良いレビュー)
よく言われていることだが、明確なルールに基づくレビューはAIに任せてしまっていい。
- コードのフォーマット・コーディング規約への準拠
- 明らかなバグや未使用変数の検出
- 期待された仕様書通りに動作しているか
これらは、すでにCIやAIレビューツールで自動化できるし、すべきだと思う。
人間がしないといけないレビュー
こっちが難しい。こちらは逆に明確なルールが定められないものになる。
- 正しい仕様はなにか(入出力・ユースケースが適切か)
- 適切なモデリング・命名・設計判断ができているか
- 影響範囲が明確になっていて、漏れがないか
この3つは、大規模なシステムになればなるほど人間の判断が必要になると考えている。コードベースの文脈、チームの意思決定の経緯、ドメイン知識が絡んでくるからだ。
影響範囲の部分は、明示的な関数の呼び出し箇所などであればAIの方がいいかもしれない。しかし実際事故につながるのは大体、何層にもコード呼び出しが連なって暗黙的な依存関係を生み出している箇所や、複雑な操作を行ったときのみ起きるパターンなどだと思う。このようなものはそもそも、「この箇所に問題があるかもしれない」という仮説を立てられなければ見つからないので、指示を出す人間がそれに気づかないとAIにも気付けない。
また、スタートアップで急成長したプロダクトなどだと、実装だけ読んでいてもその背景や意図が見えないことも多い。これをドキュメントに残すことが大事なのはもちろんだが、存在しない状態でAIに実装やレビューをさせるとこれは抜け落ちるだろう。
このような観点は、チームメンバー間で合意を得たり議論の必要がある箇所だと感じている。特にチームメンバー間で知識の偏りがある場合(ベテランと若手が混在しているとか、機能担当がまたがっているとか)は、よりこのレビューが重要で、そうしないと後で大きな問題になる。実際に何回もなってきた。
ペアプログラミングではなく、ペアプロンプティングをする
ペア作業でボトルネックを解消してきた歴史
XP(エクストリームプログラミング)には「ペアプログラミング」という実践がある。2人が一台のPCの前に座り、一方が実装(ドライバー)、もう一方が設計・レビュー(ナビゲーター)を担うというやり方である。
これはコードレビューがボトルネックになっているときの有効な対策としてよく使われている。個人的な経験としても、レビューが滞留しているときはちょっと画面共有してペアプロしよう、と提案するとスムーズに作業が流れることが多い。
これをすると実装とレビューを同じプロセスで行うため、PRが出てからレビュー待ちが発生しない。設計の議論もリアルタイムで行われるので、後からの差し戻しも減る。
この考え方は、AI時代の今でも有効だと思う。コードを書く時間が減ってレビューが増えた今、より重要になっているかもしれない。
そして現代ではペア作業の対象が変わり、コードではなくプロンプトを書くようになる。これをペアプロンプティングと名付けたい。
ペアプロンプティング = プロンプトをペア作業で書くこと
「ペアプロンプティング」とは、2人で協力してプロンプトを書く作業だ。
具体的には以下のようなイメージだ。
- 実装する機能の仕様と影響範囲を、2人で言語化する
- AIへの指示(プロンプト)を一緒に考え、書き下す
- 設計の方向性や、AIへの制約条件をプロンプトに盛り込む
- 生成されたコードを2人でレビューし、プロンプトを修正して再生成する
ポイントは、コードを書く前の「プロンプトを書く」フェーズで、仕様の確認と設計判断の議論を済ませてしまうことだ。
従来のペアプログラミングが「コードを書きながら設計を議論する」だとすれば、ペアプロンプティングは「プロンプトを書きながら設計を議論する」になる。
ペアプロンプティングのコツ
少し試してみたところわかってきたコツがある。
ゴールは「一回の指示で正しい実装をしてくれるプロンプトを作り出すこと」とする
最も重要なコツはプロンプトを1回の指示で実装させることだと思っている。追加指示が必要な状況というのは仕様・要件・設計が不確定な状態で走り出してしまっていることになる。
AIに実装を出力させた後、うまくいかない部分を追加指示で修正する、というやり方をしている人は多いと思う。作業中はこれをすることは仕方ないが、最終的な成果物としてはこれは避けたい。
イメージとしては
- プロンプト = コンパイル前のソースコード
- 生成されたコード = コンパイル結果(機械語)
というような捉え方をする。コンパイル結果(生成されたコード)を手修正するのは、機械語を直接書き換えるようなものだ。次に同じ実装が必要になったとき、プロンプトから再現できなくなる。
そのため以下のようにしている。
- プロンプトを実行し、結果を確認する
- 結果が不完全なら、AIと会話しながら修正していく。ここで仕様や設計の考慮漏れに気づける。
- 最終的にOKな状態になったら「今回の成果物を一回の指示で生成できるようにプロンプトを修正して」と指示する
- 実装の修正をすべて変更前の状態に戻し、出来上がったプロンプトの指示1回で期待する実装ができるか試す。できなければまた2に戻る
- 出来上がったプロンプトを成果物の一部とする。
こうすることで、プロンプト(=設計書)が常に最新の実装意図を反映した状態になる。特に4が重要で、これができていれば正しい設計書が得られたと言える。
仕様駆動でプロンプトを書く
プロンプトに含めるべき情報を事前に決めておく「仕様駆動」のアプローチが有効になる。
たとえば以下のような構造でプロンプトを書く習慣をつけると、ペアプロンプティング中の議論が整理しやすくなる。
## 目的
[この実装で解決したい問題・達成したいこと]
## 仕様
[入力・出力・ユースケース]
## 制約・設計方針
[使ってはいけないもの、既存の設計との整合性]
## 影響範囲
[触れるファイル・モジュール・DBテーブルなど]
このテンプレートを2人で埋める作業自体が、レビューポイントの洗い出しになる。
難しいところ
ペアプロンプティングを試してはいるものの、難しい点はたくさんある。
プルリクエストの差分が大きくなる
AIが一気に大量のコードを生成するため、PRの差分が従来より桁違いに大きくなることがある。
「2人でプロンプトを書いた」という経緯がなければ、後からそのPRをレビューするメンバーは非常につらい思いをする。また、後々実装の経緯などを確認するときに、大量の差分が一つのPRにまとまっているとかなり読み解くのは辛いと思う。
対策として有効だと思っているのは、プロンプト(計画書)をPRの説明文に添付すること。「どんな意図でこの指示を書いたか」が残っていれば、コードの差分を追うよりもまだ負荷は少なく確認できる。
仮にペアプロンプティングに参加していないメンバーがレビューする必要があるときも負荷を下げたいので、プロンプトを中心にレビューする。
自然言語で記述することの難しさ
プロンプトはどこまで行っても自然言語なので、コードと違って曖昧さを含む。「適切に」「いい感じに」「既存の設計に従って」という表現は、モデルによっても解釈が変わる。
どこまで詳細に書けばAIが意図通りに動くか、まだ正解がわかっていない。モデルのバージョンや種類によっても最適なプロンプトは変わるため、チームで「このプロンプトパターンがうまくいった」という知見を蓄積していく必要がある。また、実装時に使ったモデルを明示しておく必要もある。
プロンプトを作り込む作業は時間がかかる
ペアプロンプティングのやり方で紹介したように、1回の指示で期待した結果を得られるというプロンプトを作る作業は結構時間がかかる。 コードを生成する時間も、人が書くよりは圧倒的に早いのはもちろんだけど、一瞬というわけじゃない。10分くらい待つこともあるので、その都度多少の待ち時間は生まれる。
仕様駆動のテンプレートを作ることは比較的簡単だが、「どこまでプロンプトに書けばいいか」「specをどう記述するか」という標準化はまだ難しい。
チームや機能ドメインごとに最適なフォーマットが違うと感じており、一律のルールを作るのは難しい。現時点では「試しながら蓄積する」しかないと思っている。
おわりに
ペアプロンプティングと新しい概念のように書いたが、やっていることはペアプログラミングと何ら変わりはない。各対象が自然言語になっただけである。
うまくいかないことは多いが、「プロンプトを書く段階で設計と仕様を議論する」というアプローチは、手応えを感じている。コードが出来上がってからの差し戻しより、プロンプトを書く段階での認識合わせのほうが、チーム全体のコストが低い。
同じ課題を感じているチームがあれば、ぜひ試してみてほしい。