ソフトウェア設計

デザインパターンはなぜ必要で、なぜ盲信してはいけないのか(実務向けまとめ)

「デザインパターンは今でも勉強すべきですか?」という質問は、開発者コミュニティでよく見かけます。

読了 7 分
デザインパターンはなぜ必要で、なぜ盲信してはいけないのか(実務向けまとめ)のカバー画像

「デザインパターンは今でも勉強すべきですか?」という質問は、開発者コミュニティでよく見かけます。

一方では「基礎だから必ず身につけるべき」と言い、別の側では「最近の言語なら半分は必要ない」と言います。どちらにも一理あるため、かえって迷います。

結論から言えば、デザインパターンは十分に学ぶ価値があります。ただし「パターンを適用すること」自体が目的になった瞬間、コードを壊す近道になってしまいます。

この記事では、デザインパターンがなぜ必要なのか、そしてなぜ盲信してはいけないのかを順に見ていきます。


デザインパターンとは

デザインパターンとは一言でいえば、繰り返し現れる設計上の問題を解決する、検証済みの方法をまとめたカタログです。

出発点は、GoF(Gang of Four)が1994年の著書『Design Patterns』で23個のパターンを整理したことです。Singleton、Factory、Observer、Strategyなどの名前はすべてここから生まれました。

重要なのは、これらのパターンが誰かの机上で発明されたものではない点です。数多くのプロジェクトで開発者が似た問題を似た方法で解決していることを観察し、そこに名前を付けてカタログ化したものなのです。

だからデザインパターンの本質は「新しい技術」よりも「整理された経験」に近いのです。


なぜ必要か 1 — チームの共通語彙

デザインパターンの最大の実用的価値は、コードではなくコミュニケーションにあります。

「このクラスはインスタンスを1つだけ保持し、どこからでもアクセスできるようにして、初期化は最初のアクセス時まで遅らせよう」と説明する代わりに、「Singletonでいきましょう」の一言で済みます。

コードレビューで「ここはObserverパターンのほうがよくないですか?」という一言にどれほどの情報が込められているか考えてみてください。パターン名は非常に圧縮率の高い言語です。

この語彙を知らないと、チームの会話や技術文書、オープンソースコードのコメントを読む速度がすべて落ちます。技術面接でデザインパターンが繰り返し聞かれる理由もここにあります。


なぜ必要か 2 — フレームワークを読む鍵

私たちが毎日使うフレームワークは、すでにデザインパターンの集合体です。

  • iOSのUITableViewDelegateDelegateパターン
  • NotificationCenterとCombineのpublisherはObserverパターン
  • SwiftUIのViewプロトコルの組み合わせはCompositeパターンに近く
  • URLSession.sharedSingletonです

パターンを知っていれば、初めて見るフレームワークAPIでも「なるほど、この構造か」と設計意図を逆算できます。ドキュメントを読む時間が短くなるだけでなく、書かれていない部分まで予測できるようになります。

Delegate、Observer、Singleton、Factory、Strategyのデザインパターンブロックで組み立てたiOSアプリ画面のイラスト
Delegate、Observer、Singleton…毎日使うフレームワークはすでにパターンの組み立て品です

なぜ必要か 3 — 検証済みの解決策を再利用する

同じ問題をゼロから考えて解くのと、数十年かけて磨かれた解決策を出発点にするのとでは、スタート地点が違います。

たとえば「オブジェクト生成ロジックがあちこちに散らばり、修正のたびに漏れが出る」という問題はFactoryパターンが、「状態が変わるたびに複数の画面を更新しなければならない」という問題はObserverパターンがすでに扱ってきました。

パターンには解決策だけでなく、その解決策のトレードオフまで整理されています。「Singletonはグローバル状態なのでテストが難しくなる」といった副作用もパターンの一部です。先人が踏んだ地雷の位置まで地図に示されているようなものです。


それでも、なぜ盲信してはいけないのか

ここまで読むと、デザインパターンは万能に見えます。問題は、パターンを「知った直後」に起こりがちです。

ハンマーを持つと、すべてが釘に見える

パターンを学ぶと、どこにでも適用したくなります。これが有名な**ゴールデンハンマー(golden hammer)**の罠です。

設定値を1つ読むだけのコードにAbstract Factoryをかぶせ、分岐が2つしかないロジックにStrategyパターンを導入し、1つのクラスで済む仕事を3つのインターフェースと4つの実装クラスに分割したりします。

パターンは複雑さを減らすための道具ですが、十分に複雑でない問題に使うと、パターン自体が新たな複雑さになります。初めてコードを見る人が実際のロジックを探すために6つのファイルをまたがなければならないなら、それは設計ではなく迷路です。

言語が進化するとパターンは消える

GoFの23パターンは、1994年当時のC++とSmalltalkを前提に整理されたものです。その多くは言語機能に取り込まれました。

// 1994年式:Strategyパターン — プロトコル + 実装クラス群
protocol SortStrategy {
    func sort(_ numbers: [Int]) -> [Int]
}
final class AscendingSort: SortStrategy {
    func sort(_ numbers: [Int]) -> [Int] { numbers.sorted(by: <) }
}

// 最近は Swift: クロージャ1つで同じ目的を達成
let sorted = numbers.sorted(by: >)

関数を値として渡せる言語では、StrategyやCommandパターンの多くがクロージャ1行で済みます。Swiftのenumや値型、プロトコルのデフォルト実装も、かつてはパターンで解決していた問題を構文レベルで解決します。

パターンは「言語がまだできないことを、人が構造で補ったもの」と見ることもできます。したがってパターン一覧を時代を超えた正解として暗記すると、言語がすでに解決した問題を数十年前の方法で解くコードが生まれます。

パターンが目的になる瞬間

最も危険な兆候は、設計の議論が「この問題をどう解くか」ではなく「どのパターンを使うか」から始まることです。

パターンは問題を解く過程でたどり着く終着点に近く、出発点ではありません。リファクタリングの文献でも、「最初からパターンを組み込まず、コードがその方向の圧力を受けたときにパターンへリファクタリングする」ことが勧められています。

デザインパターン適用判断フローチャート — 問題の反復性とトレードオフを確認し、単純なまま維持するかパターンへリファクタリングするかを選択
パターンは出発点ではなく、圧力が生じたときにたどり着く終着点に近いものです

では、どう使えばよいのか

まとめると、バランスの取り方は次のとおりです。

学ぶときは、解決策より先に問題を見てください。 各パターンが「どのような状況で」登場したのかを覚えておけば、その状況でないときに使わずに済みます。パターン学習の半分は「いつ使わないべきか」を学ぶことです。

適用するときは、最も単純なコードから始めてください。 重複が3回発生し、実際に変更要求が入り、今の構造が負担になったときにパターンへリファクタリングしても遅くありません。将来の柔軟性のために今日複雑さを買うのは、たいてい割に合いません。

読むときは、積極的に活用してください。 他人のコードやフレームワーク、オープンソースを読むとき、パターンの知識は副作用のない純粋な利益です。盲信の危険は「使うとき」に生じ、「読むとき」には生じないからです。


まとめ

  • デザインパターンは、繰り返される設計問題を解く検証済みの解決策のカタログであり、発明ではなく観察の産物です。
  • 必要な理由:チームの共通語彙、フレームワーク設計を読む、トレードオフまで整理された検証済みの解決策
  • 盲信してはいけない理由:単純な問題に適用するとパターン自体が複雑さになり(ゴールデンハンマー)、言語の進化で消えるパターンも多く、パターンが目的になると設計が逆転するからです。
  • 実務の原則:問題から出発して単純なコードで始め、圧力が生じたらパターンへリファクタリングする。読む用途では惜しみなく活用する。

あわせて読みたい