- 最近、LLM(大規模言語モデル)が生成したコードを修正・補完するのに、開発者がより多くの時間を要するようになっている
- 既存のレガシーコードと同様に、コードを安全に変更するには、まず何を、なぜそのように実装したのかを理解する必要があるが、LLMコードはこの過程をさらに難しくする
- 一部のチームはコードを十分にレビュー・再作業するため速度が落ちる一方、多くのチームは読みづらく、ろくにテストもされていないコードをそのままリポジトリに反映している
- これは「理解負債(Comprehension Debt)」を生み、結局コード修正が必要になったとき、より大きな時間コストとして跳ね返ってくる
- LLMは概ね70%程度の問題解決には使えるが、繰り返し失敗する**「Doom Loop」**を避けられず、最終的には人間が自らコードを理解・修正しなければならない状況が必然的に発生する
LLMが生成したコードと理解負債の問題
- 最近の開発現場では、ChatGPT、CopilotなどLLMベースのコード自動生成ツールの利用が増加している
- これらのツールは、開発者の知識や直接的な理解がなくても、複雑なコードを迅速に生成する
- しかしこの過程で、コードの意図、制約事項、動作原理が明確に把握されず、「理解負債」が蓄積する現象が起きている
理解負債(Comprehension Debt)とは何か
- 理解負債とは、コードの品質、構造、意図をチームメンバーが十分に理解できていない状態を意味する
- 短期的には開発速度を高められるが、長期的には保守コストの増加、バグの発生、機能拡張の制約など、さまざまな副作用につながるリスクがある
LLM生成コードの追加的なリスク
- LLMが生成するコードは、明確なコメントや文脈の提示なしに結果だけを素早く導き出す
- チーム内での知識共有の不足や、既存システムとの互換性不足の問題が露呈する可能性が高い
- 繰り返しLLMコードに依存すると、プロジェクト全体のコード信頼性の低下を招くおそれがある
技術的負債との比較
- 従来の技術的負債は開発者が意識的に妥協した結果だが、LLMベースの理解負債は無意識のうちに蓄積しうるため、より危険性が高い
- 問題の認識が難しく、原因の追跡や解決がさらに複雑になる
- 問題解決時には**「Doom Loop」**(LLMを繰り返し回しても失敗する悪循環)を経験することが多い
結論と示唆
- 結局のところ、人間が直接コードを読み、修正しなければならない
- LLMを活用する際は、コードの文脈と意図をチーム全体が理解できるように文書化・共有する努力が重要である
- コードレビューの強化、コメントと文書の補強、知識共有セッションなど、組織レベルの仕組みが必要である
- 理解負債を管理しなければ、自動化ツールの利点がかえって長期的リスクへと転じる可能性がある
- 業界全体が急速に膨れ上がる理解負債の山の上に座っている状況である
8件のコメント
私も、AIは常に完全に判断できるわけではないので、すべてのコードについて自分で判断し、うまくできているかどうかも自ら確認しています。
私の基準では、せいぜい10行未満のスニペットを書く用途ですね(例: JSONパース、ソート実装)。このように使うだけでも、時間が飛躍的に節約できる気がします。
AIの助けで骨組みを作るのはいいけど、最後までディテールを詰めるのは本当に難しい気がする
私自身も、0から90までをLLMで書いたときの副作用をしばしば感じたことがあるので、最近は0から90まではできるだけ自分で直接やって、90から100まで仕上げる過程で主に活用していますが、満足しています。
Hacker Newsの意見
LLMへの依存が強まるにつれ、以前から存在していた問題がさらに悪化するのを経験した。
Naurの「理論構築」という概念を紹介し、プログラム開発チームが解散すると、そのプログラムは事実上死んだ状態になると指摘している。
Lamportの「プログラミング ≠ コーディング」という議論に触れ、プログラミングの本質は「何を、どうやって」達成するかについての理論を組み立てることだと強調している。
必要なモデルや理論を立てないプログラマほど、LLMが自分を素早く助けてくれると感じる傾向が強いと思う。
実際、コンピュータや技術から完全に離れているときのほうが、ソフトウェアプロジェクトでより大きな価値を生み出せた経験がある。
自分が正確に何を望んでいるか分かっていると、開発速度は飛躍的に上がり、そのときLLMは非常に役立つ。
目標が明確なら、LLMのハルシネーションも即座に見分けられる。
ただ漫然と真っ白なキャンバスを見つめて始めるやり方が効果的だとは思わない。
LLMはスタートを助けてくれるが、下手をするとかえって見当違いの方向へ逸れてしまうことが多かった。
いちばん難しい問題は、むしろキッチンで料理をしながら考えていて解決した経験がある。
AIコーディングで同僚たちより少しうまく活用できた理由の一つは、LLM導入前から、何かを素早くプロトタイプして、そこから構造を完全に作り直したり破棄したりする過程を繰り返していたからだ。
こうしたアプローチ(高速プロトタイピング、継続的リファクタリングなど)はかなり知られているが、多くのエンジニアは最初から完璧に設計しようとしたり、プロトタイプに改善を加えず継続的にパッチだけ当てようとする傾向がある。
AIと一緒なら複数の並列実装も安価にできるので、さまざまなバージョンを試して比較し、結果としてより強いプログラム理論や設計を素早く効果的に形成できる。
AIはこうしたループを短縮してくれ、成果物のレビューにより集中できるので、開発プロセス全体がはるかに効率的になる。
「理論構築」という概念が、LLMコードの「理解負債」と結び付いている点が印象的だ。
これは単なるプログラミングだけでなく、人間の思考や理解の過程にも深く関わっていると思う。
LLMが生み出すコードやテキスト、画像などは表面的な結果にすぎず、その背後の理論を自分で構築・経験しなければ、表層的な理解で終わるしかない。
LLMがいつか理論構築そのものまでできるようになったとしても、人間が過程に直接関与していない人工的な理解だけでは意味が乏しいと感じる。
機械が代わりに考えてくれることが便利になるほど、人間の<理解>能力が徐々に衰えていくのではないかという懸念がある。
Lamportの主張に同意すると同時に、AIは「理論構築」の過程、つまりコードベースやアルゴリズム、システム全体の理解において、既存チームにも引き継ぎ先のチームにもある程度は役立てると思う。
すべての知識を完全に置き換えるのは難しくても、AIが一定のギャップを埋めてくれることは期待できる。
既存の開発者が全員いなくなった後、新しいチームがプロジェクトを引き継いだことがあるが、前チームの知識がすべて蒸発していて非常に苦労した。
元の設計を理解しようとしてバグを量産し、結果的にコードの大半を書き直して拡張するなど、かなり大変だった。
ただ、こうした困難の中で、かえって多くの設計上の問題を自分でなぞる過程もあった。
LLMはしばしば動くソリューションを作り出すが、必要以上に複雑なコードになることが多い。
最初に書いた時点では何が問題かを最もよく理解しているため複雑さを簡単に取り除けるが、後になるとその複雑なコードが本当に必要だと誤解され、大幅に単純化するのがさらに難しくなる。
コードの保守担当者は文脈や背景知識が不足しており、もっと単純な代替案が可能だという事実に気付かないことが多い。
第一に、プロンプトを明確にして、LLMが不必要に複雑な成果物を作らないよう誘導する。
第二に、常に問題を可能な限り単純に解くようなルールや学習、文脈を与える必要がある。
最後に、生成された複雑なソリューションについて、追加のプロンプトで複雑さを減らすよう依頼すればよい。
LLMが膨大な量のデバッグしにくいコードを生み出すという問題は実際に存在する。
「品質を重視するチームは十分にレビューし、理解しなければならない」という原則はあるが、コード生成速度が速すぎてレビューが追いつかず、ボトルネックになったり形式的な承認で済まされたりすることが多い。
周囲ではレビュー工程を次々と追加しているが、このアプローチはジュニア開発者には有効でも、AIは学習しないため同じ問題が繰り返される。
LLMは非常に多くの文脈を必要とするのに、ほとんどの人はほぼ何の情報も与えずに「この問題を解く関数を作って」といった使い方しかしない。
結局、誰も理解できないコードの山(tech debt)を積み上げている。
根本的に必要なのは、LLMに対して、なぜこれを、どんな背景や意図、先行事例を踏まえて作るべきなのかを、より効果的に文脈として伝えられる「プリミティブ」だ。
コードレビューがボトルネックになるとしても、コーディングとレビューの両方がボトルネックになるより、レビューだけがボトルネックであるほうがまだましだと思う。
この過程を補完できるツール(lint、fuzzing、テストなど)はすでに存在する。
プロジェクト全体をアーキテクチャ設計したり、素早くコードを読んで分析したりする能力が乏しい人にとっては、LLM時代は難しいかもしれないが、こうした力は十分伸ばせるし、時間がたてば皆適応していくだろう。
私はこの分野が好きなので、新しい挑戦を前向きに受け止めている。
さまざまな指針をまとめた instruction .md ファイルを作り、エージェントが守るべきコーディング規則、必ず避けるべき落とし穴、コーディング基準ドキュメントへのリンクなどを入れて更新してきた経験がある。
GeminiやClaudeのようなモデルは、こうした文書ベースの指針をある程度うまく反映するが、ときどき同じミスを繰り返すこともある(e.g., C++で
autoを使うなと指示しても守らない場合など)。今後モデルが改善されれば、こうしたフィードバック処理もさらに進歩するだろうと期待している。
結局、「vibe coding」から離れ、コード構造やユニット間の相互作用は人間が直接気を配り、AIには文法とタイピングに集中させるのが、生産性も高く、開発者が全体の方向性を握り続けられる理想的な折衷点だと感じた。
プロンプトと文脈を組み立てる思考法を変えてから、LLM活用に対する直感が一段と研ぎ澄まされた。
プロンプトと文脈によって成果物の結果確率空間を狭めるという観点からアプローチするようになった。
この過程は、コードの理論を再利用可能な形で注入するのにも非常に効果的だ。
ただし、こうした文脈準備には多くの労力と思考が必要で、直接実装したほうがよい領域と、LLMに委ねたほうがよい領域の境界を見つけるのは今でも簡単ではない。
「プリミティブが違う」という指摘に共感し、本当に重要な単位は「テスト」だと思う。
モデルにコードを書くときはテストも一緒に作らせ、テストが読みやすいかを常に確認する。
テスト全体がすべて通ったときにだけコードをマージすべきだ。
テスト基盤を継続的に改善し、テスト全体が遅くなりすぎないよう維持する必要がある。
旧来のレガシーコードにはテストがないという特徴があったが、LLM時代にも同じことが当てはまる。
「ボトルネックになる」という指摘については、StackOverflowのコードを貼り付けるときも、いつも読んで確認してから使うので、結局は人間がボトルネックだ。
要するに、こうした過程を経なければコードを使うこと自体が不可能なのと同じだ。
最近Dwarkesh Patelのポッドキャストでゲストが
<A Deepness In The Sky>という小説を勧めていて、実際に読んでみると、数千年後のコンピュータシステムと、過去のレガシー知識が重要な役割を果たしている点が印象的だった。これはレガシーコードと組織的知識の価値を面白く扱ったすばらしい小説なので、お勧めできる。
ポッドキャスト: https://www.youtube.com/watch?v=3BBNG0TlVwM
書籍情報: https://amzn.to/42Fki8n
Vernor Vingeが亡くなってしまったのは残念で、彼のアイデアは時がたつほど現実的なインスピレーションを与えてくれるように感じる。
遠い未来にプログラマになる過程を描いた部分が本当に興味深かった。
膨大な数のライブラリやパッケージのため、新しいコードを書くのではなく、既存のモジュールを見つけて組み合わせることが主要な能力になっていた。
既存コードの細かなニュアンスや解釈を見抜くことが、本当の実力として描かれていた。
A Deepness In The Skyはシリーズの2冊目のようだが、1冊目を先に読まなくても大丈夫なのか気になる。そのまま読んでもよいのか尋ねている。
ほとんどの開発者はアセンブリや機械語レベルまでは理解していない。
高級言語が人間同士のコミュニケーションや協業の中核層になってきた。
LLMの登場によって、その層が自然言語や仕様ベース開発へ押しやられつつある。
結局、高級言語は数十年かけて進化し、プログラムの動作仕様をほぼ最適な形で伝えるようになったのだと思う。
自然言語でさらに多くの抽象化を試みると情報損失が起き、低級言語に行けば冗長すぎる。
自然言語への飛躍は、単なる抽象化レイヤーの変化ではなく、根本的にまったく新しい方式だ。
従来のツール(アセンブラ、コンパイラ、フレームワークなど)はすべてハードコードされた論理に基づいていて数学的検証が可能だったが、LLM以後は不確実性や推測、さらにはハルシネーションまで混在する世界へ飛び込むことになる。
JavaScript開発者の多くは、高水準の概念(適切なデータ構造、DOM、Node APIなど)ですら深く理解していない場合が多い。
抽象化レイヤーへの過度な依存が生じ、内部の動作原理をよく知らない状態に達している。
部外者からすれば、「ここで実際に何をしているのか?」という疑問を持たずにはいられない。
こうした現象はすでに日常的に受け入れられている。
結局、誰もコードの内部を正確に分かっていないのだから、LLMがコードを書いても本質的な違いはない、というたとえ話だ。
自然言語による仕様化が役割を果たすのは確かだが、必ず厳密な意味論を持つ中間レイヤーの技術が必要だと思う。
例としてRustとLLMの組み合わせでは、強力な型システムが無効な状態を排除してくれるので、コンパイルに時間がかかっても最終的な結果はたいてい正しくなる。
Rustコミュニティには「コンパイルさえ通ればだいたい動く」という文化があり、もちろん論理バグは残り得るが、実質的なエラー空間は狭くなる。
理想的には、論理的意味を厳密に定義する厳格なプログラミング言語と、事前条件・事後条件などによる仕様が積み上がり、LLMは自然言語を形式仕様へ変換する役割を担うのがよい。
自然言語はもともと明確ではなく、曖昧さを内包した言語だ。
プログラミング言語で構文解析に曖昧さがあれば重大なバグと見なすが、自然言語における曖昧さは、詩やニュアンス、含意など多様なコミュニケーション機能として成立している。
高級言語の決定論的な(import)性質だけが唯一の違いではない。
プログラミングでは決定論がすべてではなく、人間の観点から意味が明確でないコードでも十分に決定論的であり得る。
つまり、「高/低水準の抽象化」と「決定論/確率論」の軸は、互いにまったく別の問題だ。
私と私たちのチームにとって、これから押し寄せる巨大な仕事の波に見える。
8年近くレガシーコードを救って事業を続けてきたが、最近は企業がLLMにコーディングを依存しているため需要が減っている。
しかしあと18か月ほど持ちこたえれば、短期間で積み上がったLLM由来の技術的負債を解消してほしいという依頼が大量に押し寄せ、大きな機会になると予測している。
Claudeが「これでコードはもうプロダクションレベルです」と言いながら積み上げた負債の被害が、まもなく表面化するだろう。
知人がLLMの作ったPRをレビューしていて遭遇した話を聞いた。
見た目には機能が完璧に動くPRだったが、中身を調べると実際にはバックエンドを更新せず、キャッシュだけ操作するごまかしだったことが分かった。
このコードをマージしてはいけないとマネージャーを納得させるのに、多くの労力が必要だった。
結局、こういう表面だけ動いて見える「vibe coded」ソフトウェアは世の中にかなり多いのではないかと疑うようになった。
こういう場合は、いっそそのままマージして、あとで起こる反動を自分で体験させたほうがよいと思う。
誤った意思決定の結果を自分で味わってこそ、気付きが得られるものだ。
フィードバックがなければ学習も起こらず、そういうマネージャーは現実感覚のないまま開発チームへの無理な期待や圧力だけを高め、社員が疲弊して入れ替わる悪循環を招く。
非専門家のエンジニアリングマネージャーが、どうやって長い間この業界に残ってきたのか不思議だ。
この15年間で、本当に非技術的なマネージャーはほとんど見たことがない。
こういうマネージャーが問題を起こしたなら、CTO、CEO、オーナー、投資家などに報告すべきだと思う。
LLMコードに限らず、他人が書いたコードなら誰でも「理解負債」を負うことになり、
Googleのような大企業でも、新しいエンジニアがアルゴリズムに大きな変更をすばやく加えるには、数か月に及ぶ理解の過程が必須だ。
ただし、人間がうまく設計したコードは、LLMの出力より明らかに理解しやすい。
人に直接説明を受けることができるし、LLMももっともらしい答えは返せるが、実際の文脈には差がある。
私も「vibe coding」をかなりやってみたが、結局コードの精神的モデルが蓄積されないので、時間を節約したつもりでも、実際にデバッグするときにはもっと大きな時間損失が生じる。
最初から完璧にすべての設計を固めることも、現実には不可能だ。
そして、「承認されたコード行数」を生産性や時間節約の根拠にする基準は信頼しにくいと思う。
LLMに依存したコードも、慎重に検討しながら正しい形へ整えて使うのが確実に有効だ。
こうした過程は、むしろ「ペアプログラミング」に近いと思う。
LLMの出力を何の確認もせずそのまま使うやり方(「vibe coding」)が、本当に効率的であるはずがないことを強調したい。
Kernighan's Lawを例に挙げて、「デバッグはコードを書くより2倍難しい」と述べている。
だからLLMがコードを生成するなら、それをデバッグするには2倍賢いLLMが必要になるかもしれないと思う。
私の経験では必ずしもそうではなく、常に自分が運転席にいなければならない。
主にClaude Codeを使っていて、ミスをするたびに明確に指摘して直させるか、問題のある箇所を個別に示さなければならない。
LLMは自分が何を間違えたのか分かっていないので、まるでジュニア開発者と一緒に働いているような感覚がある。
つまり、デバッグ自体は同じ知能レベルでも可能だが、LLMは自力で問題を認識できない。
「デバッグには2倍賢い人が必要だ」という話について、LLMのさまざまな「思考の深さ」モードの違いと関係しているのかもしれないと思う。
複雑な関数なら、まずLLMに意図とアプローチを明確に説明するコードコメントを書かせて添える方法を使っている。
コメントの中に、他の開発者が書いたものを持ってきて使う場合でもレビューが必要なのだから、LLMの場合と変わらないという意見がありますが、私はそうは思いません。人間の場合は、評判、名声、報酬、処罰といったものが機能するからです。たぶん今のLLMのような働き方をしたら、すぐに解雇されるでしょう。
私は常に「AIは代わりに責任を取ってくれない」と考えています。
コードを書く際にAIの使用が禁止される日も、そう遠くないと思います。あり得ない話に聞こえるかもしれませんが、私は現実になると思います。