【概要】
「Clean Architecture 達人に学ぶソフトウェアの構造と設計」 は下記の通りの構成となっています。
第I部 イントロダクション
第II部 構成要素から始めよ:プログラミングパラダイム
第III部 設計の原則
第IV部 コンポーネントの原則
第V部アーキテクチャ
第VI部 詳細
この記事では「第IV部 コンポーネントの原則」の中から更に「第13章 コンポーネントの凝集性」をピックアップして内容をまとめます。
また私はアーキテクチャに対する知識が浅い人間のため間違いがあればスポンジ製のマサカリを投げていただけると幸いです。
(私ごとではございますが、Qiita初投稿のため至らぬ点がありましたら申し訳ございません)
【対象読者】
この記事の対象読者は下記のいずれかに当てはまる方を想定しています。
- CleanArchitectureを読破済みで内容を再確認したい方
- これからCleanArchitectureを読む方で内容のあらましを知りたい方
- SOLID原則などクラス単体の設計原則を理解している方
【本題】
CleanArchitectureの「第12章 コンポーネント」にて、
コンポーネントとは、デプロイの単位のことである。システムの一部としてデプロイできる、最小限のまとまりを指す。Javaならjarファイル、Rubyならgemファイル、.NETならDLLなどがそれにあたる。
と述べられています。
なお本書ではデプロイという単語とリリースという単語が出現します。私の認識では両者とも同じ意味で扱われていると思います。
コトバンクによると凝集性とは、
社会学的には集合体の統合性の強さをさす概念
とあります。つまりコンポーネントの凝集性とはコンポーネントに含まれるクラスの統合性の強さを指します。
コンポーネントの凝集性を高めるためには、
- 不要なものに依存しないこと
- 同じタイミング、同じ理由で変更されるものはひとまとめにすること
が重要である。これらを遵守し、コンポーネントの凝集性を高めるために本章では3つのコンポーネントの凝集性に関する3つの原則を扱っています。
再利用・リリース等価の原則(REP)
再利用の単位とリリースの単位は等価になる
コンポーネントとはデプロイの単位であると定義していました。つまり再利用の単位とコンポーネントは等価になると言い換えられます。なぜ等価であるべきかを分かりやすくするために、再利用の単位がコンポーネントより大きい場合と小さい場合に分別して考えてみます。
- 再利用の単位がコンポーネントより大きい場合
- 再利用するのに必要なクラスが他のコンポーネントに含まれている、つまり凝集性の高いクラスが他のコンポーネントに含まれていることになります
- 再利用の単位がコンポーネントより小さい場合
- 再利用するのに不必要なクラスがコンポーネント内に含まれている、 つまり凝集性の低いクラスが他のコンポーネントに含まれていることになります
どちらにしてもコンポーネントの凝集性を低下させてしまうため再利用の単位とコンポーネントは等価にすべきです。
閉鎖性共通の原則(CCP)
同じ理由、同じタイミングで変更されるクラスをコンポーネントにまとめること。変更の理由やタイミングが異なるクラスは、別のコンポーネントに分けること。
これは単一責任の原則をコンポーネント向けに言い換えたもので、「コンポーネントを変更する理由が複数あるべきではない」ということを示す原則です。
変更箇所を1つのコンポーネントに閉じることで、変更後にデプロイする必要があるのはそのコンポーネントだけになり、そのコンポーネントに依存していないコンポーネントは際デプロイは不要となります。
ここで考え方として重要なのは、「同じ理由、同じタイミングで変更されることが多いクラスは1つのコンポーネントにまとめておくべき」ということです。
全再利用の原則(CRP)
コンポーネントのユーザーに対して、実際には使わないものへの依存を強要してはいけない
コンポーネントを再利用する際、一つのクラスだけを再利用するということはめったになく、複数のクラスと組み合わせて再利用されることがほとんどである。この時、そうしたクラス群は1つのコンポーネントにまとめるべきという原則です。
例えばコンテナクラスとそれに対応するイテレータがあるとします。再利用する場合コンテナクラスのみを再利用するのではなく、イテレータのみを再利用するわけでもありません。コンテナクラスとイテレータを組み合わせて再利用します。したがって、コンテナクラスとイテレータは同じコンポーネントに含めるべきです。
また全再利用の原則はどのクラスを同じコンポーネントにまとめるべきかだけを説いているのではなく、どのクラスを同じコンポーネントに含めるべきではないかも説いています。
コンポーネントのユーザーに対して、実際には使わないものへの依存を強要してはいけない。要するに全再利用の原則はインターフェース分離の法則をコンポーネント向けに言い換えたものだと言えます。
3つの原則の相反関係
再利用・リリース等価の原則、閉鎖性共通の原則、全再利用の原則をまとめると下記の通りです。
- 再利用・リリース等価の原則
- 再利用の単位とコンポーネントを等価にし、再利用されるクラスを全て同じコンポーネントに集めることでコンポーネントの凝集性を高める
- 閉鎖性共通の原則
- 変更される理由が等しいクラスを全て同じコンポーネントに集めることでコンポーネントの凝集性を高める
- 全再利用の原則
- ともに再利用されることのないクラスを他のコンポーネントに配置することでコンポーネントの凝集性を高める
再利用・リリース等価の原則と閉鎖性共通の原則は包含関係にあり、どちらも凝集性を高めるために1つのコンポーネントに含まれるクラスを多くする方向に働きます。一方で全再利用の原則は凝集性を高めるために1つのコンポーネントに含まれるクラスを少なくする方向に働きます。
したがってアーキテクトは自身が抱えるプロジェクトを考慮して落とし所を見つける能力が問われます。それぞれの原則を違反した場合に受ける損害をまとめたのが下記の図になります。ノードが原則をノードの対辺の記述が原則を違反した時の存在を表しています。
例えば開発初期の段階では再利用性よりも開発しやすさが求められ、再利用・リリース等価の原則よりも閉鎖性共通の原則が重要視されるため図の右側に位置します。しかしプロジェクトが進み別のプロジェクトから再利用されるようになると再利用性が求められ、再利用・リリース等価の原則が重要視されるため図の左側へとシフトしていくでしょう。
【終わり】
私なりにコンポーネントの凝集性の原則についてまとめてみました。ここにはCleanArchitectureの記述だけでなく私なりの考えも含めさせていただきました。例えば私はリリースとデプロイを同じ意味で取り扱っていますが筆者の考えとは異なるかもしれません。そのため概要にも書かせていただきましたが私の考えに誤りがある場合はスポンジ製のマサカリを投げていただけると幸いです。