DRY修正とは何か──言葉の意味と進め方を紐解く

現場ではDRY に反しているから直してほしい、DRY 修正をお願いしたいといった会話がよく出てくる。一方で、DRY 修正と一言で述べても、何をどこまでやればよいのかは人によって幅がある。

この記事の目的は、次の問いに答える形で内容をつなげることである。

  • DRY 修正とは具体的に何を指すのか
  • どのような重複が問題となり、どう見つけるのか
  • 修正時にどのような手法があり、何に気をつけるのか
  • LLM や AI を使う開発では、何が足を引っ張りやすいのか

以下では、まず DRY 原則の意味を押さえたうえで、修正が指しうる作業の範囲を広げて見ていく。そのあと検出・手法・実践手順・ツール・チームの仕組みへと進む。

まず押さえる:DRY 原則と「DRY 修正」のイメージ

DRY, Don't Repeat Yourselfは、プログラミングにおいて情報や知識をシステム内の単一箇所に確実に保持し、重複を排除するという設計の指針である。1999 年に Andy Hunt らのThe Pragmatic Programmerで広く知られるようになり、同じルールが複数箇所にばらけていると変更コストや不整合が増えやすいという問題意識が背景にある。対比として WET, Write Everything Twice などやDRY の行き過ぎへの批判も議論されている。

DRY 違反とは、同じビジネスルールやロジックが複数箇所にちぐはぐな形で実装されている状態を指すことが多く、保守性を下げる要因となる。対象はソースコードに限らない。設計図・データ定義・ドキュメント・プロンプトなど、知識が重複して散乱している状態も DRY の観点では問題になりうる。特に LLM や AI 支援の開発では、既存コードを十分参照できないまま似た処理が増えやすく、気づかないうちに重複が広がりやすいという側面がある。

ここまでを踏まえると、この記事でいう DRY 修正 は、ざっくり次のような意味にまとめられる。

DRY 原則に従い、システム内の知識の重複を減らすための設計判断とリファクタリング、すなわち抽出・共通化・整理のこと。

その中には、静的解析やレビューで重複を見つけること、関数やモジュールへの抽出、ライブラリ化、設定への寄せ集めなど、さまざまな具体策が含まれる。ただし抽象化には結合度の上昇などのトレードオフもあるため、チームやプロダクトの状況に応じて、どこまで DRY に寄せるかを調整することも、健全な修正の一部である。

用語の整理:重複の種類と、DRY がきつく効くところ

DRY 原則, Don't Repeat Yourselfは、情報の重複を減らし、知識をできるだけ一意に保つというソフトウェア設計の考え方である。コピー&ペーストの禁止だけではなく、ビジネスルール・データ定義・ドキュメント・テストなど、知識の重複全般を減らすことが狙いだと言われている。

DRY と対になる発想として、WET, Write Everything Twice や Write Everything Thrice などや AHA, Avoid Hasty Abstractions なども知られている。WET は、文脈ごとにあえて重複を残し独立性を保つ考え方である。例えばバリデーションがサービスごとに微妙に違うなら、無理に一つにまとめないという具合である。DRY は万能ではなく、重複がはっきりしていて、まとめてメンテナンスする前提がそろっているときに共通化が効きやすいという整理がよくされる。

重複の種類として、次のような分け方がある。

  • コード重複:同じ、またはよく似た処理が複数箇所にある状態。SQL 文や関数のコピペなど。必ずしもすぐ DY 違反とは言えないが、抽出や共通化の候補になりやすい。
  • 設計重複:似た役割のコンポーネントが分散している状態。例として、差の小さいマイクロサービスが並んでいるなどがある。
  • 知識重複:ルールや仕様が複数の実装に分散している状態。DRY がもともと強く効かせたいのはここで、例えば同じ認証ルールがサービスごとに別実装されるのは典型的な知識重複として、どちらかに寄せるあるいは共通モジュールにまとめるといった修正の対象になる。

テンプレートやジェネリクス、DB の正規化など、言語や設計の世界でも「一か所に寄せる」発想は広く使われており、知識重複を減らすことは信頼性や保守性に効く、という説明がよくされます。

DRY 違反をどう見つけるか

重複を洗い出す主な経路は、静的解析ツール、コードレビュー、メトリクスである。

  • 静的解析ツール SonarQube、PMD/CPD、SpotBugs、ESLint などには、コピペに近い重複コードを検出する機能があることが多い。SonarQube は言語横断で類似コードを拾い、重複率、Duplication% としてレポートする例もある。GitHub の Sider や Clang-Tidy なども、クローン検出に近い機能を持つ。コード行のうち重複が占める割合を数値化し、閾値を超えたら課題にするといった運用が可能である。

  • メトリクス 重複率のほか、保守性指数やテストカバレッジとあわせて見ることがある。Codacy などでも重複が多いとサイズ・複雑度・工数が増えやすいと説明されており、Duplication はチームの健全性を見る指標の一つとして扱われる。リファクタリングの前後で重複率がどう変わったかを追うのにも使える。

  • コードレビュー レビュー項目に同様の処理や定義が他にないか、文字列や定数のコピペが増えていないか、共通化の候補はないかを入れておくと、ツールが拾いにくい知識重複にも気づきやすくなる。LLM が出したコードは、既存ロジックと重複していないか、意識的に確認しておく価値がある。

  • 動的解析 テストのカバレッジと照らして、重複したコードが実際にどれだけ実行パスに乗っているかを見るといった使い方もある。

ソースコード以外にも、データベースや API 仕様・ドキュメントの変更履歴を追うとよいという話がある。CloneTracker のように Git と連携していつどこでコピペが増えたかを可視化する仕組みもあり、機能追加のたびに重複の妥当性を話し合いやすくなる。

DRY 修正で取りうる手法(とトレードオフ)

DRY 違反を減らす代表的手法を、短く整理する。いずれもメリットだけでなくデメリットもあるので、それがまさに DRY 修正の設計判断になる。

手法概要メリットデメリット
抽出, Extract Method/Class重複処理を関数・メソッド・クラスに切り出す。コード量が減り、変更箇所がまとまりやすくなる。再利用が明示的になる。呼び出し元と抽出先の結合が強まる。影響範囲が広がる。過剰な一般化のリスクがある。
共通ライブラリ化共有処理をパッケージやライブラリにまとめる。一か所のメンテで複数機能に反映しやすくなる。バージョン管理や互換維持が必要。単一障害点やモノリス化の懸念がある。
テンプレート / ジェネリクス型パラメータやテンプレートで似たコードをまとめる。インラインの重複を減らせる。言語に依存する。複雑になると読みにくくなる。
メタプログラミングマクロやコード生成で共通部分を埋め込む。強い抽象化で大量の冗長を削れる。学習コストとデバッグ難度が上がりやすい。
DSLドメイン向けの言語や記法でルールを一か所に寄せる。仕様の言い回しを揃えやすくなる。設計・実装コストが高くなりがち。
ポリシー化 / 設定化定数やルールを設定ファイルや DB に出す。環境差分やルール変更を一か所で扱いやすくなる。コードと設定の対応を追う手間が増える。

単純な抽出やライブラリ化は手順が分かりやすく効果も出やすい一方、DSL やメタプログラミングはコストとリスクが大きくなりがちである。抽象化すれば変更は一か所にまとまりやすいが、依存が強くなり小さな変更でも波及しやすいというトレードオフがよく言われる。マイクロサービスでは、あえて重複を残してサービス間の独立性を優先するという選択もある。

設計例の図示(Mermaid)

機能 A と B が同じ処理 X を二重に持っているとき、共通モジュールに寄せるイメージである。

flowchart LR
  subgraph Before
    A[機能A] --> D(重複処理X)
    B[機能B] --> D
  end
  subgraph After
    A --> E(共通処理X)
    B --> E
  end

After では共通モジュールだけ直せば A ・ B の両方に反映しやすくなる。

LLM / AI 支援コーディングで増えやすい重複

AI でコードを書く場面では、通常の開発とは少し違う重複リスクがある。LLM は開発者が書いた既存の関数やライブラリを常に参照しているわけではないので、同じロジックを再生成させてしまうことがある。Copilot 利用者の抽象化に時間をかけたのに、AI がすぐに似たコードを出すので既存を直すより生成し直した方が早いという話は、その緊張関係を表している。

また、文脈が長く保持されないため、チームが過去に書いた汎用コードを踏まえずに、別ファイルや別サービス向けに再び一から似た実装が増えることもある。プロンプトがバラバラだと、プロンプト自体の重複やテンプレ肥大化も起きやすく、出力の構造も似通いがちです。

一方で、将来の分岐が大きい、チームやリリースのタイミングがずれるといった状況では、無理に一つにまとめず独立した記述を残した方が保守しやすいという指摘もある。AI がDRY を徹底せよと言ってきても、要件を踏まえて判断することが大切である。

AI 支援では開発速度が優先されがちなので、リファクタリングを計画しテストで守りながら重複をコントロールする仕組みを用意しておくというのが DRY 修正の現実的な線になる。

実践的な進め方とテスト

DRY 違反が見えたら、次のような順序で進めると安全です。

  1. 重複の識別と分類 知識重複か、コードの表面的な重複かを分ける。知識重複は優先度を上げやすく、単なる定型の繰り返しは次のメンテのタイミングまで待つという切り分けもある。コード以外に、ドキュメント・DB 定義・プロンプト設計も洗い出しの対象にする。

  2. 影響範囲の評価 バージョン、権限、環境、他機能への波及を確認する。共通処理にまとめると他モジュールへ影響が広がる場合は、分割やコピー維持を一時的に選ぶこともある。

  3. ステージングやローカルでの検証 変更後も振る舞いが変わっていないか確認する。AI が生成したコードを直す場合は、仕様やテストとの整合も確認する。テストが薄いなら、まず既存動作を記録するリグレッションテストから始める。

  4. ユニット / 統合テストの充実 まとめたロジックが元々のケースをすべて満たすかをテストで担保する。境界条件やエラー処理が落ちていないかも見る。

  5. バックアップとロールバック 大きな変更では戻せるポイントと手順を決めておく。CI で落ちたら差し戻せるようにしておくと安心である。

  6. 振り返り 静的解析の重複メトリクスやカバレッジの変化を見て、レビューで新たな重複が入っていないか確認する。

AI を多用する開発では、モデルやプロンプトの変更が続きやすいので、CI で重複や定型パターンをある程度自動チェックする試み、Evals や Promptfoo なども参考になる。

コード例:重複除去のイメージ

Python と TypeScript で、INSERT が重複していた例を共通関数に寄せると次のようになります。

# Before: 重複したSQL挿入処理
def add_user(id, name):
    db.execute(f"INSERT INTO users (id, name) VALUES ({id}, '{name}')")
def add_product(id, name):
    db.execute(f"INSERT INTO products (id, name) VALUES ({id}, '{name}')")
# After: 共通関数に抽出してDRY化
def insert_record(table, id, name):
    db.execute(f"INSERT INTO {table} (id, name) VALUES ({id}, '{name}')")
def add_user(id, name):
    return insert_record("users", id, name)
def add_product(id, name):
    return insert_record("products", id, name)
// Before: 重複したSQL挿入処理
function addUser(id: number, name: string) {
  db.execute(`INSERT INTO users (id, name) VALUES (${id}, '${name}')`);
}
function addProduct(id: number, name: string) {
  db.execute(`INSERT INTO products (id, name) VALUES (${id}, '${name}')`);
}
// After: 共通関数に抽出してDRY化
function insertRecord(table: string, id: number, name: string) {
  db.execute(`INSERT INTO ${table} (id, name) VALUES (${id}, '${name}')`);
}
function addUser(id: number, name: string) {
  return insertRecord("users", id, name);
}
function addProduct(id: number, name: string) {
  return insertRecord("products", id, name);
}

ツール・自動化・メトリクス

DRY 修正を支える例は次のとおりです。

  • 重複コード検出
    前述の静的解析に加え、GitHub Actions などの CI 用クローン検出もあります。Java なら PMD CPD、JS/TS なら ESLint のルールなど。AI 向けレビューで DRY チェックを掛け始めている製品も出てきています。

  • CI / CD ルール 重複率が閾値を超えたら失敗にする、PR テンプレに重複の確認や共通化の検討をチェック項目として入れるといった運用である。

  • メトリクス 重複率以外の指標や、テストカバレッジとのバランスも見る。Codecov などで可視化し、修正の効果を共有しやすくする。

  • LLM 支援ツール PromptFoo や Langfuse などで、プロンプト内の重複フレーズ検出や、生成コードの冗長パターン解析、CI 連携が進んでいるという話がある。

チームで続けるために

DRY を個人の努力だけにしないために、次のような仕組みが効きます。

  • コード所有権:共通ライブラリやインフラの責任者を決め、同じ重複に複数人がバラバラに手を出さないようにする。
  • レビュー基準:PR のチェックリストに DRY 関連の項目を入れる。違和感のある重複は必ずコメントできるようにする。
  • 教育とガイドライン:DRY の意義に加え、抽象化しすぎの弊害やあえて複製する例も共有し、バランスの取り方を揃える。
  • ドキュメント:プロンプトや設定をバージョン管理し、再利用できるフレーズ集を用意する。

CI だけに頼らず、ペアプロやペアレビューで AI 生成コードの冗長さを人が拾うのも有効である。

チェックリストと、ゴールの持ち方

短期的には、はっきりした重複から少しずつ手を付け、テストと CI の重複検出を並行して強くしていく方法がある。AI を使うなら、プロンプトに既存の関数やライブラリを明示させる、重複生成を避ける指示を足すといった設計も有効である。

中長期的には、共通サービスや API、DSL、ポリシー管理などでビジネスロジックを一か所に寄せていく検討と、レビュー文化やテンプレートの整備が効いてくる。

PR 用チェックリストの例:

  1. 新規のコードやドキュメントに、既存と重複するロジック・定数・設定がないか確認したか
  2. 似た機能が他にある場合、共通化を検討し、残すならコメントで理由を書いたか
  3. 抽出・統合後もテストが通るか、必要なら追加・修正したか
  4. 静的解析で Duplication の問題が出ていないか確認したか
  5. AI 用プロンプトが冗長になっていないか、テンプレ再利用できないか見直したか

最後に、ゴールは DRY という言葉を盲信することではなく、重複による将来の手直しコストと抽象化や統合のコストのバランスを取ることだと考えてよいと思う。原則を手がかりとしつつ、ビジネスとメンテの計画に沿って設計していくという姿勢が、実務での DRY 修正の落としどころになる。

参考資料、優先度順:以下は DRY の原典やブログ、OSS 関連などを参照して整理した内容である。詳細は各 URL で確認できる。

https://en.wikipedia.org/wiki/Don%27t_repeat_yourself
https://www.faros.ai/blog/ai-generated-code-and-the-dry-principle
https://thevaluable.dev/dry-principle-cost-benefit-example/
https://blog.codacy.com/code-quality-metrics
https://arxiv.org/html/2502.04073v1
https://news.fixstars.com/3891/
https://dev.to/rakbro/beyond-dry-when-ai-generated-duplication-improves-maintainability-1daf

本記事の更新情報(版権管理)

  • 2026-04-05-01
  • 2026-04-05-02
  • 2026-04-05-03
  • 2026-04-05-04
  • 2026-04-05-05
  • 2026-04-06-06

関連記事