AIがコードを書く時代に、Sandi Metzが再浮上する理由

ソフトウェア工学抽象化DRYコード品質AIプログラミング

データソース:HN + Lobsters · HN

深夜二時、あなたはdiffの中のif is_premium and not is_trial and billing_cycle == 'annual'という行を見つめ、カーソルを「Request Changes」の上に置いたまま、なかなかクリックできない。プルリクエストのタイトルは「customerとbrokerの割引計算ロジックの統合」。二つのコードブロックは確かにほとんど同じに見える——レコードを一件読み込み、パーセンテージフィールドを更新し、データベースに書き戻す。あるエンジニアがこの「重複」を発見し、entity_typeパラメータを持つ統一メソッドを抽出した。きれいで、合理的で、DRYに見える。

しかしあなたは知っている——customerの割引は明日から段階価格計算に変わり、brokerのコミッションロジックは今後二年間変わらない。今無理に統合すれば、表面的には重複を排除したように見えるが、実際には進化の方向が完全に異なる二つの概念を溶接してしまっている。これこそがSandi Metzが十年前に警告した罠である。2026年6月、彼女の記事は409ポイント、272コメントを獲得してHNの首位に再登場した——AIが一度に五百行の「正しく見える」コードを生成できる時代に、この原則はかつてないほど再検討を必要としている。

Sandi Metzが描いた腐敗の地図

Metzは2014年のRailsConf講演で初めて「duplication is far cheaper than the wrong abstraction(重複は誤った抽象化よりはるかに安価である)」と発言し、2016年にブログ記事としてまとめた。彼女の論証は極めて素朴で、いかなる理論的枠組みにも依存しない——彼女は誰もが経験したがほとんど誰も命名しなかった退化プロセスを描写したに過ぎない:

プログラマーAが重複コードを発見する。彼は共通メソッドまたはクラスを抽出し、すべての重複箇所を置き換え、満足して立ち去る。時間が経ち、新しい要件が到来する。既存の抽象化は「ほとんど」十分だ。プログラマーBが引き継ぎ、既存コードへの敬意から、彼は一から作り直さず、メソッドにパラメータを追加し、さらにメソッド内部に条件分岐を追加する。そして三つ目の要件、四つ目のパラメータ、五つ目のif-else。八ステップ目で、あなたが登場し、数千行のもつれ合った条件ロジックを前に、どの分岐がどの呼び出し元に属するのかを理解しようとする。

Metzの提示する解法も同様に簡潔だ:抽象化をインラインに戻し、各呼び出し元に自分が本当に必要なコードだけを保持させ、その後ゼロから観察する——どの類似性が本物で、どれが単に「似ているだけ」なのかを。

この一節が貫通力を持つのは、プログラマー集団の中のほぼ宗教的な信念を打ち破るからだ:重複は悪であり、重複を排除することは公理的に正しいと。

DRYの歴史的負債:データベースからコードベースへの誤訳

DRY原則はAndy HuntとDave Thomasが1999年の『達人プログラマー』で提唱した。原文の表現は:「Every piece of knowledge must have a single, unambiguous, authoritative representation within a system(システム内のあらゆる知識の断片は、単一で、曖昧さがなく、権威ある表現を持たなければならない)。」重点は「知識」にあり、「文字」にはない。SQLクエリ、ビジネスルール、設定値——これらは知識である。たまたま似ている二つのforループは、おそらくそうではない。

しかし業界は伝播の過程でこの区別を徐々に圧縮していった。「Don’t Repeat Yourself(自分を繰り返すな)」は「重複するコード行を出現させるな」になった。ヒューリスティックな原則が硬直的ルールに格上げされた結果、本来存在すべきでなかった大量の抽象化が生まれた:汎用Repository基底クラス、万能Processorメソッド、パラメータ表がビジネスロジックより長いservice関数。

Metzが行っていることは本質的にDRYの再校正である:彼女が反対しているのは**「時期尚早なDRY」**だ。この点はHNの議論でも繰り返し強調された——「この記事は抽象化するなと言っているのではなく、抽象化を強要するなと言っているのだ」。

「誤った抽象化」を識別する工学的シグナル

HNのコメント欄では、複数のエンジニアが誤った抽象化を認識するための自分なりの基準を共有した。「このコードは同じことをしているのか、それとも単に同じように見えるだけか?」——これが最も頻繁に引用された核心的判断基準である。以下のシグナルが重なって現れる場合、抽象化はほぼ確実に誤っている:

パラメータ駆動の条件分岐。 メソッドがブール値や列挙型パラメータを受け取り、内部でif-elseを使ってほとんど重ならないコードパスに分岐する。新しいパラメータが一つ増えるごとに、呼び出し元が理解しなければならない状態空間は乗算的に増大する。

一つの呼び出し元の動作を変更する際に、他の呼び出し元のために「つじつま合わせ」のコードを書かなければならない。 これは呼び出し元間に真の共変関係が存在しないことを意味する。それらはたまたま今日似たコードを走らせているだけだ。

抽象化に自明の存在理由がない。 健全な抽象化は、呼び出し元を見なくてもその責務を理解できる。毎回それを読むたびに三つの呼び出し元のコンテキストを遡らなければこのロジックが何をしているのか理解できないなら、その抽象化は既に最大の価値——認知的負荷の低減——を失っている。

新機能を追加するとき、真っ先に思いつくのがこの抽象化を迂回することであり、再利用することではない。 これが最も信頼できるシグナルである。人間の直感はしばしば、後付けの理屈による説明よりも早く構造的問題を捕捉する。

HNの核心的論争:単一真実源 vs. 局所性

今回のHN議論では、二つの高評価コメントが論争の境界を精確に画定した。

ユーザーlg5689の主張は「抽象化優先」派の中核的根拠を代表している:「常に単一真実源原則に従うべきだ。もし二つの重複コード箇所が分岐したときにバグを構成するなら、リファクタリングすべきである。重複はコード内に見えない長距離結合を作り出す。」この論理はきれいな工学的直感から来ている:同じビジネスルールが二つの場所に分散しているとき、将来ある日誰かが一方を変更してもう一方を忘れたら、バグが埋め込まれる。

ユーザーjonahxの返答はMetzが本当に関心を持つシナリオを指している:「根本的に、この記事が議論しているのは、真実源がいくつあるのかまだわからない状況だ。これら二つの場所は同じアルゴリズムを使っているのか、それともわずかに異なるバージョンなのか?さらに重要なのは、同じ種類の理由で変更されるのか?最も重要なのは、誤った抽象化は局所性を破壊する——そしてそれは実際にコードを修正するときにあなたが唯一本当に関心を持つ特性だ。私はただこの一つの修正をしたいだけで、システムの無関係な部分への副作用を心配したくない。」

両方のコメントに理があるが、適用されるシナリオが異なる。もし二つの場所が同じ不変の事実——同じ税率、同じ暗号化アルゴリズム、同じデータ検証ルール——を表していると確信できるなら、抽象化は正しい選択であり、単一真実源の便益は抽象化自体のコストをはるかに超える。

問題は、この業界では「二つのコードブロックが同義かどうかを見抜く」能力を過大評価していることにある。Metzが挙げた例:二つの計算は似ているように見える——customerレコードを読み込み、割引パーセンテージを更新する;brokerレコードを読み込み、コミッションパーセンテージを更新する。それらは今日たまたまどちらも「エンティティ読み込み-パーセンテージ更新」パターンである。しかしcustomer割引のビジネスロジックはいつでも段階計算に変更される可能性があり、brokerコミッションは引き続き単一パーセンテージのままだ——なぜならこれら二つのフィールドの法的、契約的、会計的性質は完全に異なるからだ。

「同じに見えるコード」と「同じ真実を表すコード」の間の線は、ほとんどのエンジニアが認めるよりはるかに引きにくい。

AIコード生成がこの問題をいかに増幅するか

これこそが、AIプログラミングツールが大面積で使用されるようになった後、Metzの記事が再び首位に押し上げられた理由である。

LLMはコード生成において二つの構造的傾向を持つ。第一に、それは本来的に「見かけ上の重複を排除する」方向に傾く。一つのプロンプトで二つの類似した機能モジュールを生成するとき、モデルは訓練データから最も「標準的な」統合方法を抽出し、パラメータ表現を持つ抽象化を出力する。customerとbrokerのビジネス境界が何かを尋ねたりはしない——それは要件議論に参加していないのだ。統計的に最適な共有表現を見つけたに過ぎない。

第二に、より微妙でより危険なのは、LLMが生成する誤った抽象化が異常に滑らかだということだ。命名は合理的で、インデントは整然とし、パラメータの並びには論理的感覚がある。人間のエンジニアが書いた粗悪な抽象化にはしばしば異臭がある——命名がぎこちなく、構造が緩く、それが無理に適応しようとしているのを感じ取れる。LLMの誤った抽象化はプロフェッショナルで、自信に満ち、非の打ちどころがないように見える。レビュアーは通過させやすい。

HN議論で複数のコメント投稿者がこの緊張を指摘した。ある者は「LLMは天然の反抽象化マシンだ」と言う——なぜならビジネス意味論を理解せず、表面的パターンしか理解しないからだ。ある者は「LLMが複製のコストを大幅に引き下げたので、抽象化にははるかに高い論証の閾値が必要になった」と言う。さらに鋭い観察もある:「私が最も多くの時間をかけて考えているのは、既存のコードベースが実際にどのように動作するかをLLMにどう説明し、かつ誤解によって歪められないようにするかだ。」

興味深い工学的現象として:AI生成の大量のコードは抽象化よりも複製に傾く傾向がある。理由はモデルがMetzの原則を理解しているからではない——逐次リクエスト間でファイルを跨ぐ持続的記憶を欠いているのだ。前のセッションで似たようなものを書いたことを知らない——関連コードをコンテキストウィンドウに詰め込まない限り。結果として、AI生成物の中には「抽象化されるべきに見えるが抽象化されていない」コードブロックと「既に抽象化されているが抽象化の方向が完全に間違っている」コードブロックの両方が大量に存在する。二種類の誤りが同じリポジトリに集中する——これがおそらくAI支援プログラミングがメンテナーにもたらす新しい日常である。

二つの誤りの間で選択する

Metzの立場はしばしば「複製は抽象化より良い」と単純化されるが、これは公平ではない。彼女が実際に意味しているのは:もし複製と誤った抽象化の間で選択しなければならないなら、複製を選べ。 これは二次の原則である——何が正しいかを教えるのではなく、何が正しいか確信がないときに、どちらの方向の誤りの方がコストが低いかを教える。

HNの高評価コメントは実用的な操作準則を提供している——「三回ルール」:一回目の出現、書き留める。二回目の出現、重複を許容するが観察を始める。三回目の出現、抽象化を検討する——そして本当に変化している軸に沿ってのみ抽象化する。この準則は重要な前提を含意している:真のパターンが浮かび上がるための時間が必要だ。コードがリポジトリでしばらく走った後、どの呼び出し箇所が同調して変化し、どれが分かれていくかが識別可能になる。

別のコメント投稿者の総括はより鋭い:「DRYの反対は重複ではない、WETだ——Write Everything Twice(すべてを二回書け)。二回書いて、観察せよ。三回書いてから手を動かせ。」

データの後の工学的判断

HNの投票データ——409ポイント、272コメント——は、この問題がエンジニア集団の中でまだ癒えていない裂け目に触れたことを示している。誰もがDRYが誤用されうることを知っている。問題は、世代を重ねた新人エンジニアが入社時に受ける教育が、依然として「重複の排除」をコードレビューにおいて挑戦不可能な優先事項として扱っていることにある。

AIがあなたに代わってコンプライアントなコードを書ける時代において、真に稀少な能力はもはや「どのように抽象化するか」ではなく、「いつ抽象化するか」である。後者が必要とするのはテクニックではなく、忍耐、業務領域への持続的観察を通じて形成された判断力、そして埋没費用を前に抽象化を解体し戻す冷静さである。Metzの原句は今日にこだまする:「誤った抽象化に直面したとき、前進する最速の方法は後退することだ。」

この問題に究極の答えはない。筆者はこの二派の論争に絶対的立場を取らない。抽象化はソフトウェア工学における数少ない真に基盤的価値のある概念の一つだが、その価値はタイミングとコンテキストに高度に依存する。本文は抽象化を複製で置き換えることを提唱するものではない。指摘したいのはより狭い判断である:コードが人間と機械によって交互に産出される新常態において、「少し待ってから抽象化する」コストは我々が長らく考えてきたよりも低いかもしれず、「間違って抽象化してから解体する」コストは我々が予想してきたよりも高いかもしれない。


筆者注:本文はSandi Metzの原文、2026年6月のHN議論および関連工学的文献の整理と分析に基づき、絶対的な技術的助言を構成するものではない。工学的意思決定は具体的なコンテキスト——チーム規模、事業段階、コードベース年数、テストカバレッジ——との統合を必要とし、これらの変数のいずれか一つが本文の判断の方向性を反転させる可能性がある。