/note/tech

AIにコードを書かせた先で、ボトルネックはどこに移ったか —4つの詰まりどころを追いかけて

要約:

■ 1. Software Factory化とボトルネックの移動

  • 現在の開発スタイル:
    • Codex、Claude Code、Cursorなどを使うが、ツールの使い分けを意識することは減った
    • どのツールでも挙動が同じになるSoftware Factory用のPluginsを自作して運用している
  • Software Factoryとは:
    • 人間が設計した生産ラインの中で、AIエージェントがソフトウェアを作り続ける仕組み
    • 顧客の問題発見から価値の提供、結果の観測、次の改善までを指す(現状はデプロイまで)
  • 開発ペース:
    • 品質をできる限り維持しつつ、多い週は200PRを超える
  • ボトルネックは移り続ける:
    • コードを書く速度が上がっても、全体は同じ比率では速くならない
    • ボトルネックは一つ解消するたびに別の場所へ移る
  • AIに任せられるかの決め手:
    • 失敗をちゃんと見つける手段をどれだけ用意できるかで決まる

■ 2. ボトルネック1: 意図・前提のズレ

  • コードは書けるが、つくりたいものがつくれるわけではないという問題に最初にぶつかった
  • 詳細な仕様書の限界:
    • 仕様書を詳細に書く方向に進み、cc-sddもつくった
    • エージェントが生成した大量の設計書を、人間は同じ速度では読めない
    • 事前に固めるほど、エージェントの強みである生成速度が失われる
  • grill-meの限界:
    • 設計の曖昧な点をエージェントが質問攻めにしてくるスキル
    • 論点には気づけて、今も機能している
    • 10問、20問と質問されると疲れ、最終的には理解を諦めて承認してしまう
    • これが理解負債の始まり
  • ズレの原因:
    • エージェントのズレの多くは能力不足ではなく、前提がズレたまま走り出すことで起きる
    • 長時間自律するようになった分、最初のズレの被害はむしろ大きくなっている
  • エージェントに理解を説明させる:
    • 何をしようとしているか、なぜそうするか、どんな前提で考えているかをエージェントに説明させる
    • 人間は理解のズレだけを指摘する
    • ゼロから大量の情報を入力するより、ズレだけを直す方が認知的負荷は圧倒的に小さい
  • 人間が先に握っておく3つ:
    • 目的
    • 制約(対象範囲・やらないこと・守るべき条件)
    • 判定基準(何をもって良しとするか・しないか)
    • 要求の細部まで事前に決めきることは意識的に減らしている
  • 判断できるものをつくる:
    • 細部は動くものを作り、比べながら見つける
    • マルチプレイヤーAIでエージェントの権限やコンテキストを決める際、ドキュメント上では決めきれなかった
    • 複数パターンを実装して比較すると、権限管理が複雑すぎる案やチーム作業で問題が起きる案がすぐ分かった
  • 可逆か不可逆かの区別:
    • 権限周り、データ構造、外部連携のAPI仕様のような不可逆なものは複数案を作って比べる
    • 不可逆なものは、8割完成からリリースまでの間にリファクタの時間を設ける
    • 可逆的なものは素早く進める
  • 未解決の課題:
    • この方法が効くのは何をつくるかが決まっている時だけ
    • プロダクト開発で本当に難しいのは何をつくるかを決めるまでで、その解決策はまだ見つかっていない

■ 3. ボトルネック2: 正しくつくれたかの検証

  • エージェントの実装ミス:
    • 指示が明確でも、エージェントは実装ミスを普通にする
    • 例として既存コンポーネントの破損、細かなビジネスロジックの実装漏れがある
    • テストはグリーンなのに要件の核心を満たさない実装もある
    • それでもエージェントは自信満々に完了を報告してくる
  • 人間による検証の限界:
    • 実装が数分で終わるのに人間が環境を立ち上げて手動確認していたら、開発はそこで止まる
    • そのため検証作業をエージェントにやらせることにした
  • 実際のプロダクトを触って確かめる:
    • テストを流すだけでなく、Computer Use等で実際に操作させる
    • 購入機能なら商品選択から注文完了まで操作し、仕様書にない挙動もおかしくないかを見る
  • QA手順書は渡さない:
    • 手順書自体が巨大な仕様書になるのを防ぐため
    • 渡すのは主要な画面と機能の全体像、画面と機能の対応表、実際の要求
    • どう触るかもエージェントに考えさせる
    • 大きな要件では参照用ドキュメントを残し、膨らんだら片付ける
  • 証拠の添付:
    • エージェントの「問題はありませんでした」という報告は信用しない
    • スクリーンショット、実行ログ、保存データの中身などの証拠をPRや確認画面に添付させる
  • 特に役立つ証拠:
    • 条件ごとに「mainでは失敗し、このPRでは通る」ことを示す表
    • わざと壊すと検証が失敗することの確認
    • 「このPRで証明していないこと」の明記
  • 書いたエージェントに判定させない:
    • 同一セッションで検証させると、都合の良い検証ばかりを行う
    • 新しいセッションで検証エージェントを立ち上げ、QAテスターとして敵対的に検証させる
    • クリティカルな指摘がなくなるか、指定回数に達するまでループを回す
    • トークン消費は大きいが、実環境でしか見つかりにくいバグを事前に大量に潰せている

■ 4. 検証環境とCIの詰まり

  • どこで確かめるかの問題:
    • 本番相当の環境は構成が複雑で、変更のたびにエージェントの手元で再現するのが大変だった
    • 現在のプロダクトはエージェント実行基盤、KVストア、DWHなど複数サービスにまたがり、1コンテナで完結しない
  • 手元で検証できる環境の整備:
    • KVストアはローカルのエミュレーターに置き換えた
    • DWHはDIで差し替えられる口を用意した
    • 本番データの代わりに検証用のデモデータをつくった
    • 環境の立ち上げはワンコマンドでできるようにした
  • PRごとのプレビュー環境との比較:
    • 本番相当のプレビュー環境を並列に立てれば、エミュレーターで見逃す挙動も拾える
    • ただしコストがかかり、構成が重い今回のプロダクトでは見送った
  • 検証場所のルール:
    • マージ後にサンドボックスが立ち上がるが、マージ後に間違いに気づくのでは遅すぎる
    • 基本はローカルやCIで回すE2Eテストまでで完結させ、サンドボックスでのチェックは毎回はしない
    • 本物に近い環境でしかわからないことだけをサンドボックスで見て、それ以外は手前で検証する
  • Agent Nativeなアーキテクチャ:
    • エージェントが自分の間違いを安く速く見つけられる設計のこと
  • CIの待ち時間がボトルネック化:
    • マージ後にブラウザ検証が4本壊れていたことを機に、PRでもブラウザ検証を全件回すようにした
    • ミスは手前で見つけやすくなったが、PRのチェックは一時十数分かかるようになった
    • 並列でタスクを進めても、それぞれがCI完了待ちで止まり全体は進まなかった
  • CIの短縮:
    • 変更された領域を判定し、関係する検証だけを回す
    • ブラウザの検証を並列に分け、重複や待ち時間を減らす
    • これにより約7分まで縮めた
  • 残る課題:
    • 7分でもまだ完全な解決ではない
    • 既存の開発プロセスをゼロベースで考え直す必要がある時期にきている

■ 5. ボトルネック3: レビュー

  • レビューの詰まり:
    • 初期は10,000行のPRが平気で上がり、PRの説明も見る順番も分からず読めなかった
  • PRの切り方:
    • PR段階ではなく、最初の設計段階で目的と境界を握る
    • 目的と境界を握れば、1つのPRが1つの目的に収まりやすい
    • Issueの分解やStacked PRで、人間が理解できる大きさとスコープに収める
    • 行数を減らすこと自体は目的ではない
  • 人間が理解する範囲を狭める:
    • PRに人間に判断してほしいことと、見る順番を明確に書かせる
    • 意図や判定基準に対応する実装前後の証拠を残させ、コードを読まずに確認できるようにする
  • Auto Merge:
    • 人間の認知的負荷のボトルネックに対してかなり有効
    • 人間が見るべき範囲を先に決め、それ以外は動いた証拠や不変条件のチェックが通ればマージまで進める
    • 人間が見る範囲は、権限周りやデータ構造、外部連携のような不可逆なものに絞る
    • 可逆性の低いところまでAuto Mergeにすると、後からの手戻りが大きくなる
  • Auto Mergeの実績:
    • 現状PRの約85%がAuto Mergeで入っている
    • PR作成からマージまでの時間の中央値は約18分
  • 段階的な導入:
    • 検証環境が完全に整うことはないため、最初からAuto Mergeにはしていない
    • リスクの低いところや、ほぼ問題なく書けているところから少しずつ切り替えてきた
  • レビューで見るポイントの変化:
    • 1行ずつのコードではなく設計を見る
    • 構造的な境界が守られているか、明確なインターフェースになっているかを確認する
  • エージェントの局所的な修正:
    • エージェントは修正時に局所的な解決をしがち
    • その場では動くが、長期的には変更容易性が低下し技術的負債となる
  • 次の課題:
    • 個々のやらかしを長いガイドにせず、Linterやレビューに足していく
    • 機械的かつ個別最適にならない構造で検知できるようにする
  • 構造だけは手放せない:
    • 構造が崩れると、エージェント自身が書く中身まで崩れていく

■ 6. ボトルネック4: 構造の維持

  • 抜き打ちレビューで見つかる問題:
    • Auto Mergeが回っても、動いてはいるが怪しい実装が普通に見つかる
    • 特にフロントは可逆だからと雑に実装しがちで、小さいバグを後から直すことがある
  • 具体的な劣化パターン:
    • 処理をフロントエンドのロジックに無理やり書き、複数箇所に分散する
    • 同じような領域の処理が整理されないまま複数箇所に入る
    • 古いルールが抜けきらず、エージェントがそれに引っ張られる
  • コードベースの汚れはエージェントにも影響する:
    • 汚れるほど、エージェントにとって正しそうな実装の候補が増える
    • 同じ処理が3箇所にあれば4箇所目をつくりやすくなる
    • 後方互換性のような古いパターンが残っていればそれを真似する
    • クリーンなコードベースはエージェントの探索空間を狭める意味でも重要
  • オーバーエンジニアリング:
    • 緩和はできているが、まだ防げていない
    • テストケースで検証したが、Opus 5.5やGPT-6 Astraなど最新モデルでも全くうまくいかなかった
    • 指示の問題というより、設計が曖昧なまま任せている箇所が残っていることも一因
    • これもエージェントの探索空間が広すぎることが原因
  • 構造を保つ仕事は増えた:
    • 定期的に設計を見直し、契約や境界、依存の向きに漏れがないかを確認する
    • 重複やオーバーエンジニアリング等を検出したら修正する
    • 機械的に守れるものはLinterや構造を制約するテストで縛る
  • 検証の有効性の確認:
    • カバレッジよりも、ミューテーションテストのような考え方で見る
    • わざとコードを壊して検証が失敗することを確かめる
  • 保守の比率:
    • マージされたPRの約2割は保守のPR
    • 本当はリリース後の運用やプロダクト改善に時間を使いたいが、今はコードベースの保守が必要
  • 設計段階で潰すのが最善:
    • 手戻りが最も少ないのは設計段階で潰せたとき
    • 検証環境で見つけられるのは、決めたこととズレた実装まで
    • 前提そのものが間違っていれば、検証は全部通ってしまう
  • 設計段階で力を入れること:
    • 解くべき問題と前提を理解できているかを確かめる
    • トレードオフやアーキテクチャ上の弱いところを早めに洗い出す
    • エージェントの話す内容を自分が理解できる状態にした上で、壊しながら進める

■ 7. つくって解体してきた仕組み

  • 解体の繰り返し:
    • この1年ほど、つくった仕組みの多くを自分で解体してきた
    • cc-sddの出番は少なくなったが、必要に応じて使っている
    • 自作Pluginsも3ヶ月ちょっとで100回以上つくっては解体を繰り返している
  • 消えた仕組みの例:
    • エージェントの段取りを細かく決める仕組み(作業の契約や書式、ワークフローのスクリプト等)を一気につくった
    • 3週間ほどで新モデルが出て不要になり、まとめて消した
  • 育ち続けている仕組みの例:
    • PRの証拠を機械的にチェックする仕組み
    • 検証環境をつくったり直したりするSkillsは0から5本に増えた
  • 新しい仕組みを入れる際の問い:
    • 「モデルが10倍強くなっても本当に必要か?」を自問する
    • つくり込みすぎた仕組みを捨てるのも判断の1つ
  • チーム開発でも同様:
    • 必須のコンテキスト不足によるズレや、検証・レビューでの詰まりなどボトルネックは移る
    • 既存の開発プロセスにAIを足すだけでは、局所的に速くなるだけで全体はあまり変わらない
  • 消える仕組みと残る仕組み:
    • モデルの能力不足を埋める仕組みは、モデルが強くなれば消える
    • 意図のズレを見つけること、失敗を観測できることはモデルが強くなっても残る
    • フィードバックを速く返すこと、境界やアーキテクチャを保つことも残る
  • 今後の方針:
    • エージェントを細かく制御する仕組みより、「間違えてもすぐ気づける環境」づくりに時間を使う
    • モデルがさらに10倍強くなったとき何が残るかを考えながら、つくっては壊していく