コンポーネントとは
コンポーネントとは、デプロイ単位のことであり、システムの一部としてデプロイできる最小限のまとまりを指す。例えば、Javaならjar、Rubyならgem、.NETならDLL等がそれにあたる。あらゆる言語において、コンポーネントがデプロイの基準となる。よくできたコンポーネントは常にデプロイできる状態を保っているため、個別に開発を進めることができる。
本記事では「コンポーネントの凝集性に関する原則」3つと「コンポーネントの結合に関する原則」3つを取り上げる。
コンポーネントの凝集性に関する原則
凝集性とは、機能と機能の関わり具合の尺度を指す。凝集性が高い(機能と機能の関わり具合が低い)ほど良いプログラムとされる。
※密接に関係するものは1つに集め、関係しないものは分けるという考え方がベースとなる。
再利用・リリース等価の原則(REP:The Reuse/Release Equivalence Principle)
「コンポーネントを再利用するには、コンポーネントのリリース単位で行う」という原則。
言い換えると「再利用の単位とリリースの単位は等価になる」という原則。
※例えば、Javaのクラスを修正した場合、クラス単位ではなくjar単位でリリース・再利用を行うのが理想。
考え方としては重要なのは「コンポーネントに含まれるクラスは、すべてが再利用されるか、すべてが再利用できないかのどちらかにすべき」ということ。
閉鎖性共通の原則(CCP:The Common Closure Principle)
「同じ理由、同じタイミングで変更されるクラスをコンポーネントにまとめること。変更の理由やタイミングが異なるクラスは、別のコンポーネントに分ける」という原則。
これは、単一責任の原則(SRP)をコンポーネント向けに言い換えたもので「コンポーネントを変更する理由が複数あるべきではない」としている。変更箇所が1つのコンポーネントに閉じていれば、変更後にデプロイする必要があるのはそのコンポーネントだけになり、そのコンポーネントに依存していないコンポーネントは再デプロイは不要となる。
考え方としては重要なのは「同じ理由、同じタイミングで変更されることが多いクラスは1つのコンポーネントにまとめておくべき」ということ。
全再利用の原則(CRP:The Common Reuse Principle)
「1つのクラスだけを再利用するということはめったになく、複数のクラスと組み合わせて使われることがほとんどのため、そうしたクラス群は1つのコンポーネントにまとめる」という原則。
この原則は、どのクラスをひとまとめにすべきかということと、どのクラスをひとまとめにすべきではないかを表現している。
コンポーネント凝集性のテンション図
各原則は相反するところがあるため、アーキテクトはこれらの原則をバランスよく取ること。
コンポーネントの結合に関する原則
非循環依存関係の原則(ADP:Acyclic Dependencies Principle)
「コンポーネントの依存グラフに循環依存があってはならない」という原則。
コンポーネント間で循環依存がある場合、コンポーネント単独でのデプロイ、リリースができずその部分が温床となりコンポーネント間での不整合が発生する。そのため(アプリケーションが成長するにつれてコンポーネントの依存構造も細かく変わっていくので)、循環依存が生まれないよう適切に管理する必要がある。なお、コンポーネント間での依存は、具象クラスレベルではなく、インターフェース等の抽象レイヤーで依存すること。
安定依存の原則(SDP:Stable Dependencies Principle)
「安定度の高い方向に依存すること」という原則。
「安定度の高い」とは、変更がしづらいということ。多数のコンポーネントから依存されたコンポーネントは(変更することの影響が大きいので)変更しづらい、そのためこういったコンポーネントは安定度が高いと考えらえれる。また、基本的に抽象度の高いレイヤーに依存すべきなため、「安定度の高い方向に依存」とは、言い換えると抽象度の高いレイヤーに依存せよとも言える。
安定度・抽象度等価の原則(SAP:Stable Abstractions Principle)
「コンポーネントの抽象度は、その安定度と同程度でなければならない」という原則。
つまり、安定度の高いコンポーネントは抽象度も高くあるべきで、安定度の高さが拡張の妨げになってはいけない。一方、安定度が低いことによってその内部の具体的なコードが変更しやすくなるため、安定度の低いコンポーネントはより具体的であるべきである。