SOLID原則
ソリッドげんそく
変更に強いオブジェクト指向設計のための5原則。クラス設計の判断基準を与える。
概要
SOLID原則は、オブジェクト指向設計のための5つの原則 — 単一責任の原則(SRP)、開放閉鎖の原則(OCP)、リスコフの置換原則(LSP)、インターフェース分離の原則(ISP)、依存性逆転の原則(DIP)— の頭文字を並べたものです。Robert C. Martin(通称 Uncle Bob)が2000年前後にまとめた原則群で、2000年代に SOLID という語呂で広まりました。
これらはアルゴリズムでもツールでもなく、クラス設計の場面で「どちらの分け方が良いか」を判断するための基準です。共通のゴールはひとつ、「変更に強い」構造を作ること。つまり仕様変更が起きたとき、修正が1か所に収まり、既存の動くコードを壊さずに済む設計です。その意味で SOLID は、結合度と凝集度という古典的な物差しを、オブジェクト指向のクラスとインターフェースの言葉で実践指針に翻訳したものだと言えます。
なぜ生まれたか
1990年代、オブジェクト指向言語は広く普及しましたが、クラスを使えば自動的に良い設計になるわけではないことも明らかになっていました。継承の乱用や巨大クラスによって、あらゆる変更が広範囲に波及する「硬いソフトウェア」、直すたびに予想外の場所が壊れる「もろいソフトウェア」、一部だけ再利用したくても引きはがせない「動かせないソフトウェア」— Martin はこうした設計腐敗の症状を診断し、それを防ぐための処方箋として原則群を整理しました。
ポイントは、ソフトウェアが腐敗する原因を「変更」に見定めたことです。要求は必ず変わる。変わったときに設計が壊れないためには、変わりやすい部分と変わりにくい部分を分離し、依存の向きを制御する必要がある — 個々の原則はすべて、この一点から導かれています。
詳細
5つの原則
単一責任の原則(SRP: Single Responsibility Principle) — クラスを変更する理由は1つでなければならない、という原則です。ここでいう「理由」は変更を要求してくる関係者(アクター)のことで、経理の都合と現場の都合で同じクラスが書き換えられるなら分割すべき、と読みます。凝集度の高さをクラス単位で言い直した原則です。
開放閉鎖の原則(OCP: Open-Closed Principle) — ソフトウェアの構成要素は「拡張に対して開き、修正に対して閉じている」べきだという原則です。新しい振る舞いを追加するとき、既存のコードを書き換えるのではなく、抽象(インターフェース)の新しい実装を足すだけで済む構造を目指します。
リスコフの置換原則(LSP: Liskov Substitution Principle) — サブタイプは、基底型が使われている場所にそのまま差し替えても、プログラムの正しさを壊してはならないという原則です。継承関係は「is-a に見えるか」ではなく「基底型の契約(事前条件・事後条件)を守れるか」で判断します。有名な反例が「正方形は長方形を継承できるか」問題です。
インターフェース分離の原則(ISP: Interface Segregation Principle) — 利用者に、使わないメソッドへの依存を強制してはならないという原則です。何でもできる太いインターフェースは、利用者を無関係な変更に巻き込みます。利用者ごとの小さなインターフェースに分割します。
依存性逆転の原則(DIP: Dependency Inversion Principle) — 上位モジュール(業務ロジック)は下位モジュール(DB アクセスやメール送信などの詳細)に依存してはならず、双方が抽象に依存すべきだという原則です。ソースコード上の依存の向きを、処理の流れとは逆向き(詳細→抽象)にできることが、オブジェクト指向の核心的な力です。
「変更に強い」とは何か
5原則がそれぞれ守っているものを並べると、共通の構図が見えてきます。SRP と ISP は「変更理由の異なるものを同居させない」— つまり高凝集を守ります。OCP・LSP・DIP は「変わりやすい詳細への依存を、安定した抽象への依存に置き換える」— つまり疎結合を守ります。合わせると、変更が起きたとき修正すべき場所が1つに定まり、その修正が抽象という防火壁で堰き止められる構造になります。
この構造はテストのしやすさとも直結します。抽象に依存するクラスは、テスト時に実装を偽物(モック)に差し替えられるからです。DIP を実際のコードで実現する定番の手法が依存性注入であり、デザインパターンの多く(Strategy、Observer、Template Method など)は SOLID を特定の場面に適用した具体例と読むことができます。
原則の暴走 — 過剰抽象化という落とし穴
SOLID の最大の落とし穴は、原則を「常に従うべきルール」と誤読することです。実装が1つしかないのに全クラスにインターフェースを用意する、起きるかどうか分からない変更に備えて抽象層を重ねる — こうした過剰抽象化は、間接参照だらけでコードを追えなくし、かえって変更を難しくします。抽象は1枚挟むごとに読解コストがかかる投資であり、変更が実際に見込まれる軸にだけ張るべきものです。
実務的な使い方は、最初から完璧な抽象を設計することではなく、変更要求が来て設計の痛み(同じ修正の繰り返し、波及する差分)を感じたときに、SOLID を診断名として使い、リファクタリングで構造を直すことです。原則は設計の完成図ではなく、コードレビューや設計判断の場で「なぜこの分け方が良いのか」を説明するための共通言語だと捉えるのが健全です。