コードはもっと安くなった
(htmx.org)- AIコーディングツールの普及によりコード作成コストは急激に下がったが、実際には生成されたコードを 理解するコスト がさらに大きくなっている現実
- LLMは非決定的で、元のソースを保存せず、出力範囲が一般的なソフトウェア全体へと広がるため、コンパイラ出力と同一視はできない
- LLMは人間が理解できる速度をはるかに超えてコードを生成するため、誰にも理解できない大規模変更を防ぐための 段階的(incremental)な利用 を推奨
- コードが安くなるときの核心的なリスクは 複雑性(complexity) であり、システム規模に応じて少なくとも幾何級数的に増加する一方、LLMは複雑性への恐れがない多作なコーダー
- 解決策として、コードを足すのではなく削除・単純化する 引き算のエンジニア(subtractive engineer) を提示し、コンピュータプログラミングの技芸を守る重要性を強調
コードが安くなった時代
- 過去1年でAIがかなり良質なコードを非常に高速かつ大量に生成するようになり、コード生成コスト は大幅に低下
- 「コーディングはそもそも問題ではなかった」という主張に対し、コーディングも問題の一部 であり、その部分がAIコーディングツールによって大きく減ったと反論
- かつてコーディング能力に誇りを感じていた開発者に対して、純粋なコーディングの重要性低下 が何を意味するのかを問いかける
理解コストの上昇(Understanding is Expensive(er))
- コードがプログラマの手から苦労して生み出されるのではなく大量生成されるとき、そのコードに対する 理解そのものが存在しない
- 理解が必要なら、コード作成後に コードを読んで 獲得しなければならない
- 一般に、他人の書いたコードを読むことは自分のコードを書くことより難しい
- 「コンパイラ出力も理解していないではないか」というAI擁護論を カテゴリエラー(category error) と規定
- コンパイラは決定的だが、LLMは設計上非決定的
- コンパイラのワークフローは元のソースコードを保存するが、LLMのワークフローはたいてい保存しない
- コンパイラ出力は機械語という狭いドメインに限られるが、LLM出力は一般化されたソフトウェアに限定されない
- 多くの場合、とりわけ ミッションクリティカルなソフトウェア では、LLM生成コードであっても開発者が基盤となるコードを理解していなければならない
- LLMは誰も追いつけない速度でコードを生産できるため、理解の速度を追い越す危険 がある
- したがって巨大な変更一覧を一度に生成するより、段階的な利用 を推奨
- 機械的なリファクタリングには適しているかもしれないが、コードベースに新しい意味論(semantics)を導入するときは極めて危険
魔法使いの弟子の罠(The Sorcerer's Apprentice Trap)
- Disney映画 Fantasia の「The Sorcerer's Apprentice」の場面を AI時代の適切な比喩 として提示
- 弟子が掃除の苦役を減らそうとほうきに魔法をかけると、ほうきはますます激しく掃除し、状況は制御不能に陥る
- 最後には魔法使い(Sorcerer)が再び現れて状況を掌握し、弟子の愚かさを叱責しながら混乱を収拾する
- この比喩の教訓は 弟子ではなく魔法使いになるべきだ ということであり、魔法使いはコードを理解していなければならない
複雑性はやはり悪い(Complexity: Still Bad)
- 人間は幾何級数や指数曲線をうまく把握できず、複利(compound interest)のようなものをおとぎ話のように信じてしまう
- コードが安くなるときの核心的なリスクは 複雑性(complexity) であり、システム規模に応じて少なくとも幾何級数的に、しばしば指数的に増加すると(証明なしに)主張
- LLM以前にも 多作なコーダー(prolific coder) は存在した
- 複雑性への恐れがない多作なコーダーは既存の問題の上にコードを積み重ね続け、どんな変更でも直した分だけバグを生む 修正不能な停滞状態 へシステムを崩壊させる
- LLMは複雑性への恐れがないうえに同時に多作なコーダーでもあるため、危険 である
引き算し、制約するエンジニア(The Subtractive, Constraining Engineer)
- LLM生成コードの危険に対応するため、引き算し、制約するエンジニア(subtractive, constraining engineer) を提案
- このエンジニアは「ノー」と言い、LLM出力を綿密にレビューし、単純化を提案し、断固として制御を維持する
- 自分が作ったコードではなく、システムから 削除した、または入り込むのを防いだコード(およびレイヤー) に誇りを持つ
- この姿勢は建設者(builder)というより 彫刻家(sculptor) に近い
- 建設者(builder)的な姿勢は システム設計レベル では依然として有効
- 優れたエンジニアはコンポーネントを効果的に組み合わせてシステムを構築できなければならない
- ただしこのレベルでも不要なコンポーネントやシステム境界を取り除き、デプロイや相互作用を単純化する 引き算の思考法 が有用
- 引き算のエンジニアは過去の大多数のコーダーとは異なるタイプであり、「ノー」と言うことや英雄的な全面書き直しよりも既存システムを磨き上げることを好む姿勢と親和性が高い
- このアプローチは、コードは安くなり、複雑性は依然として頂点捕食者(apex predator)である という二重の現実を認めつつ、コンピュータプログラミングの技芸を守る生産的な方法である
1件のコメント
Lobste.rs の意見
Peter Naur の1985年の文章 Programming as Theory Building は、今あらためて何度か読み返す価値がありそう
「LLM は複雑さを恐れられない」という表現は、誇張に近いと思う
そうした失敗パターン自体は実際にある。指示を広く与えると、LLM は階層を追加し、抽象化を生み出し、問題に対して過剰なコードをよく出す。だがその挙動は観察しやすく、レビューしやすく、意外と方向転換もしやすい。AGENTS/CLAUDE.md ファイルで望むソフトウェアのスタイルを合わせればよい
最小の変更を求め、何を削れるかを尋ね、その抽象化が見合う価値を持つかを問えばよい。不変条件、結合点、認知負荷についても尋ね、賢さを取り除く2回目のパスを要求すれば、たいていその圧力に従う。プロンプトに入れておけば最初から避けさせることもできる
危険は、LLM が複雑さをまったく尊重できないことではなく、周囲のプロセスが報酬を与えるコードの形を進んで作り出すことにある。量を報いるチームは量を受け取り、単純さを報いるチームはたいていそれも得られる
最近のモデルはたいていの人間より優れていて、今後さらに良くなるだろう。コードが良くないなら、AI 研究所にフィードバックで圧力をかけるべきだ。たとえば GPT 系は良いドキュメント作成がひどく苦手だと思う
だから「不可能だ」という表現は最適ではないかもしれないが、デフォルトでは複雑性の側に傾くいくつものバイアスがあると思う
また、何もしないより何かをする方へのバイアスもある。良いプログラマは、特定の要求を投げるマネージャーよりずっと多くの文脈を使い、代替案を示すこともある。LLM にも可能ではあるだろうが、現在の LLM は「計画中に質問する」や反復検知コードがあっても、正しい質問を投げるのが得意ではない。そういう学習データ自体もあまり多くない可能性が高い
ある意味でプロンプトエンジニアリングは、この問題群をめぐるひどいハックに近い
他方では、「これは1か月規模のプロジェクトなのでおすすめしません。この状態でコミットしてデモとして残すのはどうでしょう」といった返答を受けたあと、LLM を説得して安心させなければならなかった。どちらも1時間もかからず終わると分かっていたのにだ。ところが「いいから、まったく新しいものをやってみて。やり方は自分で見つけて」と言うと試してはくれるので、その意味では恐れがないとも言える
冗談はさておき、同意する。自分の経験とも一致している
「コードを理解するコストの方が高くなった」という話には、一般論としてはあまり同意しない
考えなしに生成された LLM コードならその通りかもしれないが、適切に導けば LLM でも読みやすく、階層のよく分かれたコードを作れる。もちろんその場合、アーキテクチャ選定の大半は人間が行うが、そもそもそうあるべきだと思う
反例として、慣れていない人が書いたコードを理解するのに LLM は非常に優れていると感じた。Claude Code に特定のコードを深く分析して各部分を説明する Markdown 文書を作らせ、さらに自分がレビューや理解を始める順序まで提案してもらえる
これは本当に価値がある
「人間はたいてい指数関数的な曲線をうまく理解できない。だから複利のようなおとぎ話を信じる」とは、複利がおとぎ話だという意味なのか? 何か読み違えているのだろうか?