人間が保守できるようにコードを書く – AI生成の重複リスク

人間が保守できるようにコードを書く – AI生成の重複のリスク

TL;DR

LLM でコードを生成する際に DRY などのベストプラクティスを強制しないと、重複した条件分岐がリポジトリの新たな「スタイル」になり、モデルはそれらのパターンを再現し続け、将来的な保守が困難になる。明示的なレビューコマンド、プロンプト、静的解析を追加すればコードベースをクリーンに保てる。


作者が示す問題点

作者は、LLM に対して同じアクセスチェックロジックをさまざまな場所(ルートハンドラ、バックグラウンドジョブ、API エンドポイント、Webhook)に繰り返し追加するよう依頼するワークフローを説明している。生成されたスニペットは次のようになる:

if (user.isActive && user.hasPermission('read') &&
    !user.isSuspended && account.status === 'open') {
    // do a thing
}

共有ヘルパーを抽出する代わりに、作者はコードが動作しテストが通るのでそのままコピーをマージしてしまう。短期的な便利さが長期的なリスクを隠蔽し、似たようなエンドポイントへの新たなリクエストごとに同じ条件分岐のコピーが増えて、重複パターンが強化される。リファクタリングが後で要求されたとき、LLM はリポジトリが現在持つ 5 つのコピーすべてをそのまま残すだけになる。

重要なポイント: 各ショートカットがコードベースにマージされるたびに、モデルが学習して繰り返すシグナルとなり、一度きりの臭いが広範なスタイルへと変わってしまう。


LLM が悪いパターンを増幅する理由

  1. コンテキスト駆動生成 – LLM は開いているファイルや直近のコミットを読み取り、既存コードを将来の提案のテンプレートとして扱う。
  2. パターン強化 – 重複スニペットが多いほど、それらを再現するバイアスが強くなる。
  3. 保守性の概念がない – モデルはプロンプトに対して「動くコード」を最適化するだけで、長期的な可読性や抽象化は考慮しない。

"LLMs are sponges that soak up everything you do and repeat it back to you. So make sure it's good." – Original post


コミュニティ提案の緩和策

1. チェックリスト付きレビューコマンドを追加

  • Markdown ファイルを作成(例: .claude/commands/review.md)。
  • 「新しいコードが既存ロジックを重複させていないか」など具体的なチェック項目を列挙。
  • マージ前にコマンド(/review)を実行すると、エージェントがプランを生成し違反をフラグする。

"Agents don’t care that they just got a wall of generic feedback, they happily look into all the bullet points. I added ‘ensure the new things aren’t duplicating code that already exists elsewhere’ and it gave me such a surprise – it really truly started planning cleanups!" – cadamsdotcom

2. 最終コード品質チェックのプロンプト

大きな変更後にモデルに以下を確認させる:

  • 関心の分離
  • 残っている実験的コードの不存在
  • ドキュメントとの一貫性

"Now do a final code check. Is everything tidy and do the components adhere to the principle of separations‑of‑concerns?" – planb

3. 静的解析をベースラインとして導入

Linters やコードスメル検出ツール(例: Credo、Rubocop、ESLint)を CI パイプラインに組み込む。LLM は報告された具体的な問題を修正するよう依頼でき、決定的な安全網になる。

"Better yet, add tooling like static code analyzers … Verify against a mechanical baseline, with LLM judgement layered on top as‑needed." – chickensong

4. 定期的なモデルベースのスメル検出を実行

開発者の中には、コードベースを別の LLM(または専用のスメル検出モデル)に定期的に走らせ、重複パターンを表面化させる人もいる。

"I continually run codebases through different models to have them look for bad code smells like repeated code. That’s been pretty effective." – carimura


反論とニュアンスのある見解

  • LLM は保守性を向上させることもある – コメント投稿者の一人は、AI がコードを関心の分離やテスト容易性の面で改善したと指摘している。

    "AI has made my code more human‑maintainable. They’ve been complaining about obsolete comments, separation of concerns, testability…" – andai

  • すべての重複が悪いわけではない – プロジェクト初期は過度な抽象化が逆効果になることがある。パターンが安定するまで重複は許容できる。

    "When you start a project not everything is DRY, and you don’t start pulling out shared helpers until they’re called for." – chickensong

  • LLM は既存の抽象化を無視することがある – クリーンな抽象が存在しても、モデルはしばしばロジックをゼロから再実装する。

    "The frontier LLM does neither, it just steams ahead re‑implementing things from scratch…" – davnicwil

  • 人間の discipline が不可欠 – エンジニアチームが継続的にレビュー・プロンプトを適用できるかは楽観的すぎるという声もある。

    "The idea that an LLM‑fueled group will collectively have this discipline is… bemusing and saddening." – MattyRad


AI 支援開発の実践チェックリスト

  1. レビュー用チェックリストを定義(重複検出、DRY、命名規則など)。エージェントが読める場所に保存。
  2. マージ前に /review を実行し、出力を必須のコードレビュー項目として扱う。
  3. CI に静的解析ステップを追加し、新たなスメルが出たらビルドを失敗させる。
  4. 定期的に LLM スメルスキャンをスケジュールし、ドリフトを検出。
  5. 類似ロジックを追加する際は抽象化を明示的に指示:
    • "Create a shared helper hasReadAccess(user, account) and use it in all new endpoints."
  6. 意図をコードコメントに残すことで、モデルが実装だけでなく理由も参照できるようにする。

結論

LLM は動くコードを素早く生成するのが得意だが、規律あるチェックがなければ重複した保守性の低いパターンを固定化してしまう。モデルをチームメンバーとして扱い、レビューコマンド、品質プロンプト、静的解析といった明示的な指示を与えることで、コードベースをクリーンに保ち、AI が悪い習慣を学習するのを防げる。

Sources