出典
このドキュメントは、Netflixのエンジニアが提唱するAI時代のソフトウェア開発における危機管理と設計の重要性について解説しています。著者は、AIによってコード生成が加速する一方で、エンジニアが自ら書いたコードの仕組みを理解できなくなるリスクを警告しています。彼は「容易さ(Easy)」と「シンプルさ(Simple)」を混同せず、思考をアウトソーシングしない姿勢が不可欠であると説いています。その解決策として、無計画な生成を避け、調査・設計・実装の3段階を踏むことで、人間がシステムの構造を制御し続ける手法を提案しています。最終的に、ソフトウェアの本質的な難しさはコードの入力ではなく問題の理解にあり、開発者にはAIを使いこなしつつもシステムを深く把握する責任があると結論づけています。
📺 https://youtu.be/eIoohUmYpGI
TLDR:AI補助開発における三段階方法論
核心的な問題 AIはコードを書くことを「容易」にするが、「シンプル」にはしない。私たちはスピードと引き換えに複雑性の負債を積み上げ、自分でも理解できないコードを生成している。
AIの致命的な欠陥 AIは「本質的複雑性」(ビジネスロジック)と「付随的複雑性」(技術的負債)を区別できない。既存のコードをすべて「維持すべきパターン」として扱い、技術的負債を増幅させてしまう。
三段階方法論
| フェーズ | 目的 | ポイント |
|---|---|---|
| 調査 | 現状を理解する | AIにコードベースを分析させ、人間が検証し、研究文書を出力 |
| 計画 | やり方を明確にする | コードを書く前にすべてのアーキテクチャ決定を完了、詳細な設計書を作成 |
| 実装 | 実行する | 計画に従ってコードを生成、開発者の役割は「プロンプター」から「検証者」へ |
核心原則
- AIは思考を加速できるが、思考を代行することはできない
- 複雑な変更の前に、まず手作業で一例を完成させ「理解を獲得する」
- 人間によるチェックポイントが、災害を防ぐ最もレバレッジの効くポイント
一言でまとめると AIに思考させるな、AIで思考を加速させよ。
序文:無限のソフトウェア危機と人間の思考の役割
まず、告白から始めさせてください。NetflixのJake Nations氏は語ります。「私は、自分が完全には理解していないコードをシップしたことがあります」。AIで生成し、テストし、デプロイしたものの、その動作原理を説明することはできませんでした。これは彼一人の問題ではありません。AIによるコード生成の時代において、これは私たち開発者全員が、意識的か無意識的かにかかわらず、日々下している決断なのです。私たちは今、ソフトウェアの複雑性が人間の管理能力を無限のスケールで超えていく、新たな「無限のソフトウェア危機」の入り口に立っています。
この問題の根源は、プログラミング言語Clojureの作者であるRich Hickey氏が指摘した、「容易さ(easy)」と「シンプルさ(simple)」の混同にあります。私たちは、AIという究極のツールを手に入れ、「容易さ」を追求するあまり、将来にわたって管理不能な「複雑性」という負債を積み上げています。目の前のタスクを素早く完了させるという「容易さ」は魅力的ですが、それはシステムの構造的な健全性、すなわち「シンプルさ」を犠牲にすることで成り立っています。
このガイドの目的は、AI補助開発の時代において、このトレードオフを意識的に管理するための体系的な方法論を提示することです。ここで紹介する「調査、計画、実装」の三段階からなるアプローチは、AIを思考の代行者としてではなく、人間の思考と監督をプロセスの中核に据え、それを加速させるためのツールとして活用することを目指します。これにより、私たちは単に「動く」コードではなく、保守可能で理解しやすい、真に価値のあるソフトウェアを構築し続けることができるのです。
次のセクションでは、まずAIがなぜ、そしてどのようにしてシステムの複雑性を増幅させてしまうのか、その根本原因を掘り下げていきます。
1. 新たなソフトウェア危機:「容易さ」と「シンプルさ」の混同
ソフトウェア開発の歴史は、常に複雑性との闘いの歴史でした。C言語の登場からオブジェクト指向、アジャイル開発、そしてクラウドへ。私たちは常に、増大し続ける要求に応えるため、より大規模なシステムを構築する手段を模索してきました。そして今、AIという新たなパラダイムシフトが、この闘いを前例のない規模へと拡大させています。この課題を乗り越えるためには、私たちが無意識に陥っている罠、すなわち「容易さ」と「シンプルさ」の混同を理解することが不可欠です。
この二つの概念は、しばしば同じ意味で使われますが、その本質は全く異なります。Rich Hickey氏は、彼の有名な講演「Simple Made Easy」の中で、この違いを明確に定義しました。
シンプル(Simple)
- 「一つの役割を持つこと」「絡み合っていない状態」を意味します。これは、システムの構造的な品質であり、各コンポーネントが単一の責任を持ち、他の部分と複雑に絡み合っていない状態を指します。シンプルさを実現するには、思考と設計、そして物事を解きほぐす努力が必要です。
容易(Easy)
- 「近接性」、つまり「手の届きやすさ」を意味します。これは、努力なくアクセスできる状態であり、Stack Overflowからのコピー&ペーストや、AIによるワンショットのコード生成などが典型例です。
容易さを選ぶことは、現在のスピードと将来の複雑性を交換することです。 かつて、このトレードオフは機能していました。複雑性の蓄積は比較的緩やかで、私たちはリファクタリングや再設計によってそれを管理する時間的猶予がありました。しかし、AIはこのバランスを完全に破壊しました。AIは「究極のイージーボタン」であり、そのあまりの摩擦のなさから、私たちはシンプルさを追求するという選択肢自体を忘れかけています。アーキテクチャについて深く考える前に、コードが瞬時に現れてしまうのです。
この問題は、私たちが日常的に利用する会話型インターフェースにおいて顕著になります。この「複雑性のスパイラル」が、単純なタスクをいかにして混沌へと導くか、認証機能を追加するシナリオで見てみましょう。
-
最初の依頼: 「OAuth認証を追加して」→
oauth.jsが生成される。 -
方針転換: 「やはりOpenID Connectも追加しよう」→
oidc.jsが追加され、二つのファイルが並立する。 - 問題の修正: 「セッションが壊れたから直して」→ AIは場当たり的な修正を提案しますが、その過程で以前の方針と矛盾するセッション管理ロジックを導入します。放棄されたOAuthの実装はデッドコードとして残り、テストは単に『通るように』修正され、システム全体には複数の認証哲学の断片が混在するようになります。
このような対話を繰り返すうちに、当初の設計思想は完全に失われ、開発者自身でさえ、どのような制約を追加してきたかを完全に把握できなくなります。各対話が「容易さ」を選択した結果、システムの根本的な複雑性は雪だるま式に増大していくのです。これこそが、AI補助開発における最大の落とし穴です。
2. AIが複雑性を増幅させる理由:本質的複雑性と付随的複雑性
AIを効果的に活用するためには、ソフトウェアに内在する二種類の複雑性を理解することが不可欠です。この概念は、コンピュータサイエンスの古典であるFred Brooks氏の論文「銀の弾丸はない(No Silver Bullet)」で提唱されました。彼は、ソフトウェア開発の生産性を飛躍的に向上させる特効薬は存在しないと主張し、その理由を複雑性の性質から説明しました。
- 本質的複雑性(Essential Complexity) 解決しようとしている問題そのものに固有の、避けることのできない複雑性です。例えば、「ユーザーは支払いを行う必要がある」「注文は履行されなければならない」といったビジネスロジックの核心部分がこれにあたります。これは、ソフトウェアが存在する理由そのものです。
- 付随的複雑性(Accidental Complexity) 実装の過程で、人間が追加したすべてのものです。これには、過去の技術選定に起因する回避策、フレームワークの「お作法」、数年前に妥当だった抽象化レイヤーなどが含まれます。これは、コードを「動かす」ために追加されたものであり、問題の本質ではありません。
AIの根本的な問題は、これら二種類の複雑性を区別できないことにあります。AIエージェントがコードベースを分析する際、そこにあるすべてのコードは「維持すべきパターン」として扱われます。47行目の認証チェックも、数年前に書かれた奇妙なgRPCの実装も、AIにとっては等しく「パターン」です。技術的負債は負債として認識されず、単なる追加のコードとして扱われ、そのまま増幅されてしまうのです。
Netflixで実際に発生した認証システムのリファクタリングの事例は、この問題を明確に示しています。古い認証コードを新しい中央集権システムに移行させようとした際、AIエージェントは失敗しました。その原因は、古いコードにおいて、ビジネスロジックと認証ロジックが分かちがたく絡み合っていたためです。
- パーミッションチェックがビジネスロジックの奥深くに埋め込まれている。
- ロールに関する前提がデータモデルに焼き付けられている。
- 認証呼び出しが数百のファイルに散らばっている。
AIは、どこでビジネスロジックが終わり、どこから認証ロジックが始まるのかという「境界」を見つけることができませんでした。その結果、AIはリファクタリングの途中で依存関係を解決できずに処理を完全に放棄するか、さらに悪いことに、古いシステムの複雑なロジックを新しいシステム上で『再実装』するという、本末転倒な試みを行うことさえありました。
このように、付随的複雑性が高度に絡み合った状態では、AIは解決策になるどころか、さらなる複雑性のレイヤーを上塗りするだけの存在になりかねません。この問題を克服するためには、人間が主導権を握り、思考を体系化するアプローチが不可欠となるのです。
3. 三段階方法論:調査、計画、実装
ここで提案する方法論は、単なるプロンプトエンジニアリングの技術ではありません。これは、AIを思考の代行者ではなく、思考を加速させるためのツールとして活用するための、人間中心のフレームワークです。私たちはこのアプローチを「コンテキスト圧縮(Context Compression)」と呼びます。その目的は、広範で曖昧なコンテキストを、明確で実行可能な指示へと段階的に圧縮していくことです。
3.1. フェーズ1:調査 (Research)
目的:広範なコンテキストを、検証済みの単一の研究文書に圧縮すること。
このフェーズは、AIに大規模な変更を依頼する前の準備段階です。数時間かかるであろう手動での調査を、数分で読めるインサイトに凝縮します。
- 関連コンテキストの投入: 変更に関連するすべての情報をAIに提供します。アーキテクチャ図、設計ドキュメント、重要なインターフェースの定義、さらには関連するSlackのスレッドまで、あらゆるコンテキストがインプットとなります。
- コードベースの分析: AIエージェントを活用し、コードベースを分析させます。主要なコンポーネント、それらの依存関係、そして変更が影響を及ぼす可能性のある範囲をマッピングさせます。
- 対話による分析の深化: 一方的に結果を受け取るのではなく、対話を通じて分析を掘り下げます。「この部分のキャッシング戦略はどうなっていますか?」「障害処理はどのように実装されていますか?」といった質問を投げかけ、AIの分析が間違っていれば訂正し、不足しているコンテキストがあれば追加で提供します。
このフェーズの最終成果物は、「現状のシステムはこうなっており、これらのコンポーネントがこのように接続され、今回の変更はこれらの部分に影響を与える」という事実をまとめた、単一の研究文書です。
重要:人間によるチェックポイント この調査結果を人間がレビューし、現実と照らし合わせて検証する瞬間が、プロセス全体で最もレバレッジが効くポイントです。ここでの誤りを一つ見逃すことが、後の工程で大惨事を引き起こす可能性があります。逆に、この段階で誤りを捉えることができれば、手戻りを劇的に削減できます。
3.2. フェーズ2:計画 (Planning)
目的:検証済みの調査結果に基づき、詳細でレビュー可能な実装計画を作成すること。
調査フェーズで「何をすべきか」が明確になったら、次は「どのようにすべきか」を定義します。この計画書は、AIと人間の両方にとってのブループリントとなります。
計画書には、以下の要素を含めるべきです。
- 実際のコード構造
- 具体的な関数シグネチャと型定義
- コンポーネント間のデータフロー
- 守るべき設計原則やサービス境界
この計画書は、経験の浅いエンジニアでも迷わずに作業を進められる『塗り絵』(つまり、枠線に沿って色を塗るだけで完成するような、極めて明確な指示書)のようなものであるべきです。すべての重要なアーキテクチャ上の決定は、一行もコードが書かれる前に行われます。これにより、複雑なロジックの正当性を確保し、不要な結合を防ぐことができます。
このステップの真価は、AIの生成速度に人間の理解が追いつくための唯一の手段である点にあります。コードレビューで数千行を精査する代わりに、私たちは凝縮された計画を数分で検証し、システムの健全性をプロアクティブに確保できるのです。
3.3. フェーズ3:実装 (Implementation)
目的:明確な計画に従って、クリーンで焦点の定まったコードを生成すること。
調査と計画が完了していれば、このフェーズは驚くほどシンプルになります。明確な仕様書(計画書)があるため、AIとの長い会話から生まれる「複雑性のスパイラル」を防ぐことができます。50回のメッセージのやり取りで進化的に作られたコードではなく、3つの明確なステップ(調査、計画、実装)で検証されながら生成されたコードが得られます。
これにより、放棄されたアプローチや矛盾したパターンが最終的なコードに残ることはありません。「やっぱりこっちの方法で」といった手戻りによるデッドコードも発生しません。
このプロセスにおける開発者の役割は、試行錯誤を繰り返しながらプロンプトを調整する「プロンプター」から、生成されたコードが計画に準拠しているかを確かめる「検証者」へとシフトします。思考と判断という最も重要な作業を事前に行った上で、機械的な実装作業をAIに委任するのです。
ただし、この方法論は魔法ではありません。質の高い調査と計画は、それを行う人間の洞察力に依存します。AIが最高のパフォーマンスを発揮するには、まず人間が『正解』の形を教える必要があります。次のセクションでは、その不可欠な前提条件である『理解を獲得する』プロセスについて詳述します。
4. 理解を獲得する:人間が果たすべき前提条件
三段階方法論は強力なフレームワークですが、それを実践する上で最も重要な心構えがあります。それは、AIは既存の知識を体系化することはできても、ゼロから深い理解を生み出すことはできないという事実です。AIを効果的に活用するための前提条件として、人間がまず「理解を獲得する(earning the understanding)」プロセスが不可欠です。
先ほど触れたNetflixの認証リファクタリングの事例に戻りましょう。AIがこのタスクに失敗した後、チームはAIのプロンプトを改良したり、より高性能なモデルを試したりはしませんでした。彼らが取った行動は、以下の通りです。
- 手動での移行: まず、AIを一切使わずに、エンジニアが手作業で一つのサービスの認証ロジックをリファクタリングしました。コードを読み、依存関係を理解し、何が壊れるかを確認しながら、地道に変更を加えました。
- 隠れた制約の発見: この骨の折れる手動プロセスを通じて、コードを静的に分析するだけでは決して表面化しなかった数々の「隠れた制約」が明らかになりました。例えば、特定の不変条件を維持する必要があることや、認証ロジックの変更が予期せぬ他サービスに影響を及ぼすことなどです。
- 成功事例の提供: この手動で成功したプルリクエスト(変更履歴)そのものを、三段階方法論の**フェーズ1(調査)における「シード(種)」**としてAIに与えました。これにより、AIは「クリーンな移行とはどのようなものか」という具体的な手本を得ることができたのです。
この事例から得られる教訓は明確です。大規模で複雑な変更を安全に進めるためには、まず人間がその領域の深い理解を獲得しなければならない、ということです。この手作業による理解の獲得こそが、AIを活用したスケーラブルな展開を可能にするための不可欠な基盤となります。
私たちが求めるべきは、単に「より良いプロンプト」や「より良いモデル」ではありません。それらがいかに進化しようとも、システムの深い文脈や歴史、そして隠れた制約を理解するという、人間による知的労働を代替することはできないのです。
結論:「動く」コードの先へ:人間の判断力を取り戻す
このガイドで一貫して論じてきたのは、私たちの目標が単にテストをパスするコードを書くことではなく、将来にわたって変更・保守が可能な、理解できるシステムを構築することにある、という点です。AIによるコード生成の速度は魅力的ですが、その速度に私たちの思考が追いつかなければ、それは破滅的な複雑性を生み出す源泉にもなり得ます。
AIが数秒で数千行のコードを生成するとき、人間がそれを理解するには数時間、あるいは数日を要するかもしれません。この「知識のギャップ」が常態化するとき、私たちはコードを理解しないままシップするだけでなく、より深刻な問題を抱えることになります。それは、複雑な問題を認識する能力そのものが「萎縮する」という危険性です。危険なアーキテクチャや単純でない解決策を見抜く直感は、過去の失敗や、深夜3時に本番障害と格闘した生々しい経験から培われます。AIは過去の失敗から得た教訓をエンコードしません。思考のプロセスをAIに委ね続けることで、私たちはこの最も重要な、痛みによって得られた洞察力を失ってしまうのです。
本稿で提示した三段階(調査、計画、実装)方法論は、この知識のギャップを埋めるための橋渡しです。それは、人間のレビューと判断をプロセスの中核に据え、AIによる生成速度と人間の理解速度の同期を取るための体系的なアプローチです。AIに思考させるのではなく、私たちの思考を加速させ、その結果を検証可能な形で記録します。
最後に、Jake Nations氏が投げかけた問いでこのガイドを締めくくりたいと思います。これは、私たち開発者一人ひとりが自問し続けなければならない問いです。
「AIがコードの大部分を書くようになったとき、我々は自分たちのシステムをまだ理解しているだろうか?」
その答えを「イエス」であり続けるために、私たちはツールの進化に思考を委ねるのではなく、常にシステムの品質と設計に対する最終的な責任者であり続けなければなりません。コードを書くことのメカニクスは変わっても、何を、なぜ書くのかを知るという本質は、これからも変わることはないのです。