2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【リファクタリング】似たような実装が増えすぎた時の対処法と、共通化の判断基準

Posted at

こんにちは、ファインディで開発部長をしているhamです。
この記事は🎄ファインディエンジニア #3 Advent Calendar 2025 13日目の投稿です。

この記事では、継続してソフトウェア開発をしていると発生しがちな「似たような実装が増える」について、対処法と共通化の判断基準についてお話しします。

はじめに

ソフトウェア開発を長く続けていると、ソースコードの中に「双子」や「三つ子」、あるいは「クローン軍団」のような似た実装が量産されていることに気づく瞬間があります。

「最初は1つしかなかったはずなのに、気がついたら似たような処理が大量にある……」

疎結合(Coupling)の観点では、それぞれが独立しているため悪くないように見えますが、凝集度(Cohesion)や再利用性、そして何より保守性の観点では大きな問題を抱えています。

今回は、なぜこのような「重複実装」が生まれてしまうのか、そしてそれをどのように技術的・プロセス的に解消していくべきかについてまとめます。

なぜ「コピペ実装」は量産されるのか

開発者のスキル不足や怠慢が原因だと思われがちですが、実は 「責任感」と「恐怖心」 が原因であるケースが多々あります。

ある機能に改修が必要になったとき、既存のメソッドを汎用的に修正しようとすると、そのメソッドを利用している全ての機能への影響範囲(デグレ) を調査しなければなりません。

copy-and-paste.png

  • 「既存の機能は絶対に壊したくない」
  • 「納期が迫っており、全量テストをする時間がない」
  • 「影響範囲が見えない(テストコードがない)」

こうした心理的圧力が働くと、エンジニアは最も安全な策を選びます。すなわち、「既存のコードをコピーして、新しい名前をつけ、そこだけを修正する」 という方法です。

これは短期的には「安全なリリース」を保証しますが、長期的には「技術的負債」という利子が積み上がっていきます。

重複実装が招く3つのリスク

  1. 修正漏れ(バグの温床)
    ビジネスロジックに変更があった際、Aは直したが、コピーであるBとCを直し忘れるという事故が多発します
  2. 可読性の低下(認知負荷)
    新しく参画したメンバーは、似たようなメソッドが並んでいるのを見て「どれを使えばいいのか?」「微妙に何が違うのか?」を解読するのに膨大な時間を費やします
  3. 変更への恐怖の増大
    コード量が増えれば増えるほど、システム全体の見通しが悪くなり、余計に「どこも触りたくない」という状況が悪化します

対処法:コピペ地獄からの脱出ステップ

すでに増えてしまった重複コードを整理するには、段階的なアプローチが必要です。

Step 1. まずは「壊れていないことを証明する手段」を用意する(テストコード)

「既存を壊すのが怖い」のが根本原因ですから、「壊れていないことを証明する手段」 なしに共通化に着手してはいけません。

リファクタリングを行う前に、重複しているAとBの両方に対して、現在の挙動を保証する自動テスト(単体テスト等)を書きます。テストがGreen(成功)になって初めて、共通化のスタートラインに立てます。

Step 2. 「3回の法則 (Rule of Three)」に従う

プログラミングには 「2回までは重複を許容し、3回目で初めてリファクタリング(共通化)する」 という経験則があります。

2つだけなら「偶然似ているだけ」の可能性があり、無理に共通化すると逆にコードが複雑になる(早すぎる最適化)リスクがあるからです。3回同じ処理が出てきたら、それは間違いなく「パターン」です。このタイミングで共通化を行いましょう。

Step 3. 「継承」と「委譲」を武器として使い分ける

共通化のアプローチには大きく分けて「継承」と「委譲」の2つがあります。どちらかが絶対的な正解というわけではなく、状況に応じた使い分けが重要です。

A. 継承(Inheritance)が適しているケース

「親クラス=骨組み」を作り、子クラスで「肉付け」をするアプローチです。
代表的なのが Template Method パターン です。

  • どんな時?:
    • 処理の「大まかな流れ(手順)」は完全に固定されていて、その一部のステップだけを少し変えたい場合
    • 「AはBの一種である(Is-a関係)」が明確に成り立つ場合
  • メリット:
    • コード量が少なく済み、直感的に実装しやすい
  • デメリット:
    • 親クラスと子クラスが密結合になるため、親の変更が全子クラスに影響する

B. 委譲(Delegation / Composition)が適しているケース

「部品」を作って、それを本体に「持たせる(または渡す)」アプローチです。
代表的なのが Strategy パターン です。

  • どんな時?:
    • 処理の一部を、実行時などに柔軟に切り替えたい場合
    • 「AはBを持っている(Has-a関係)」の場合
    • 将来的に組み合わせのバリエーションが増えそうな場合
  • メリット:
    • 疎結合であり、個々の部品(クラス)を単体テストしやすい
  • デメリット:
    • クラス数が増え、構成が少し複雑になる

判断のポイント:
迷ったら 「委譲(Strategy)」 を選ぶ方が安全です。継承は一度実装すると後から剥がすのが大変ですが、委譲は比較的変更に強い構造だからです。「どうしても処理のフローを固定化したい」という強い理由がある時だけ継承を選びましょう。

重要な判断基準:「偶然」か「本質」か

最後に、「本当に共通化すべきか?」 という判断基準についてです。
全ての似ているコードが悪ではありません。以下の問いかけをしてみてください。

「片方の要件が変わったとき、もう片方も必ず同じように変わるべきか?」

  • YESの場合(本質的な重複):
    • 例:消費税計算、特定のバリデーションルールなど
    • 対策: 共通化すべき(DRY原則)
  • NOの場合(偶然の重複):
    • 例:ユーザー画面の商品リストと、管理画面の商品リスト
    • 対策: 共通化しない
    • 今はたまたま表示項目が同じでも、「管理画面には原価を出したい」となった瞬間、無理な共通化が足枷になります

まとめ:ボーイスカウト・ルールでいこう

大量の重複コードを一度に全て解消しようとすると、開発が止まってしまいます。

「ボーイスカウト・ルール(来た時よりも美しくして去る)」 を適用し、機能追加やバグ修正でそのファイルを開いたついでに、周辺の重複を1つだけ解消する。

地道ですが、テストという命綱をつけて、少しずつ「借金」を返済していくことが、健全な開発現場を取り戻す最短ルートです。

AIエージェントという新たな選択肢

近年、AIエージェント(Claude Code、GitHub Copilot Agent、Cursor など)の登場により、リファクタリング作業をAIに任せるという選択肢も現実的になってきました。

  • 重複コードの検出と共通化の提案
  • テストコードの自動生成
  • 影響範囲の分析と安全なリファクタリングの実行

人間が方針を決め、AIが手を動かす——このハイブリッドなアプローチを取り入れることで、「地道な返済」のスピードを大幅に加速できる時代になっています。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?