CleanArchitecture達人に学ぶソフトウェアの設計と構造 ~コンポーネントの凝集性とコンポーネントの結合編

[Clean Architecture 達人に学ぶソフトウェアの設計と構造](https://www.amazon.co.jp/Clean-Architecture-%E9%81%94%E4%BA%BA%E3%81%AB%E5%AD%A6%E3%81%B6%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%81%AE%E6%A7%8B%E9%80%A0%E3%81%A8%E8%A8%AD%E8%A8%88-Robert-C-Martin/dp/4048930656)を読んだ。

本書では1部で設計とアーキテクチャの違いと目的はなにか、それが提供する２つの価値について
2部では3つのパラダイム(構造化プログラミング・オブジェクト指向プログラミング・関数型プログラミング)についてそれぞれで触れたあとで
第３部以降で設計の原則・コンポーネントの原則・アーキテクチャ全体という流れで書かれている

本書の設計の原則に関する記事はすでに多くあるため、この記事では書かれていたコンポーネントの6つの原則についてどういった内容が述べられていたか自分なりの表現を交えてまとめる。

ちなみに設計の原則について、社内の方が[記事](https://qiita.com/BlueEventHorizon/items/a0144ef9ac20e587d288)を書いていました。
理解しやすかったのでぜひ。

## コンポーネントの凝集性の３つの原則

### 再利用・リリース等価の原則(REP)
> 再利用の単位とリリースの単位は等価になる

２つの観点がある

 - コンポーネントは単なるクラスやモジュールの集まりではなく、コンポーネントには一貫するテーマや目的があり、クラスやモジュールはそれを満たすものでなければいけない。つまりそれらは凝集性のあるグループでなければいけない。
これは後述する閉鎖性共通の原則と重なる。

 -  ひとつのコンポーネントを形成するクラウやモジュールは、まとめてリリース可能でなければいけない。同じバージョン番号を共有し、同じリリースプロセスを経て、同じリリースドキュメントを持っているという事実は、作者にとってもユーザーにとっても合理的なはず。


### 閉鎖性共通の原則(CCP)
> 同じ理由、同じタイミングで変更されるクラスをコンポーネントにまとめる。変更の理由やタイミングが異なるクラスは、別のコンポーネントに分ける。

単一責任の原則をコンポーネント向けに言い換えたもの。コードを変更しなければいけないときに、一つのコンポーネントに変更箇所がまとまっている（閉じている）ほうが、変更後にデプロイする必要があるのはそのコンポーネントのみになりありがたい。


### 全利用の原則(CRP)
> コンポーネントのユーザーに対して、実際には使わないものへの依存を強要してはいけない

一緒に用いられることが多いクラスやモジュールは同じコンポーネントにまとめよう、という考え。
この原則では、ひとつのクラスだけを再利用することはめったになく、他のクラスと組み合わせて再利用可能な抽象として用いることが多いため、そうしたクラスを同じコンポーネントにまとめるように説いている。
またどのクラスを同じコンポーネントにまとめるべきかだけを言ってるのではなく、どのクラスを同じコンポーネントにまとめるべきではないかも教えてくれる。
→ つまり全再利用の原則はインターフェイス分離の原則を一般化したものであり、どちらも不要なものには依存しないことを説いている



### 凝集性おわり
再利用・リリース等価の原則と閉鎖性共通の原則は包含関係にあり、どちらも一つのコンポーネントを大きくする方向に働く。
一方で全利用の原則は、その逆で一つのコンポーネントを小さくする方向に働く。
したがってアーキテクトは開発チームの現在の懸念事項に見合った落とし所をみつける必要がある。
開発初期では、再利用性よりも開発のしやすさのほうが重要であるため、閉鎖性共通の原則を重視すべきだと述べている。
しかし例えばプロジェクトが進み別のプロジェクトから利用される頃にはそれは不適切になっているかもしれない。コンポーネントの構造は再利用性重視へと変わるべき。
つまり開発時の利便性と再利用性はトレードオフの関係にあるため、適宜判断する必要があるようだ。

![テンション図.png](https://qiita-image-store.s3.amazonaws.com/0/261386/1546c273-af53-2bce-c957-e87f0a82c883.png)
* 辺にある記述は、反対側の頂点にある原則を無視したときにかかるコスト
参照元：https://qiita.com/NagaokaKenichi/items/65c149ba92580fce5be2

## コンポーネントの結合の3つの原則

コンポーネントの関連を扱うもの。
開発の利便性と論理的な設計のトレードオフが発生する。

### 非循環依存関係の原則
> コンポーネントの依存グラフに循環依存があってはいけない

<img width="413" alt="スクリーンショット 2018-09-23 15.34.11.png" src="https://qiita-image-store.s3.amazonaws.com/0/261386/ef6cb30d-210f-4b5e-d7fd-4531827490ca.png">

<img width="365" alt="スクリーンショット 2018-09-23 15.34.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/261386/d3114b50-5ce2-5ca1-0b55-8588151918a7.png">

参照元： http://www.atmarkit.co.jp/fdotnet/designptn/designptn07/designptn07_02.html

- 循環依存による弊害
    - コンポーネントを切り離すのが難しくなる
    - ユニットテストやリリースが難しくなる
    - モジュールの数が増えるにつれ、ビルド時の課題も幾何級数的に増加する
    - システムのリリース時にコンポーネントのビルドの順番を決めるのが難しくなる

コンポーネント間での依存が発生したときは、具象クラスレベルではなく、インターフェース等の抽象レイヤーで依存することで解消する


### 安定依存の原則
>  安定度の高い方向に依存する

「安定度の高い」とは、変更がしづらいということであり、多数のコンポーネントから依存されたコンポーネントは（変更することの影響が大きいので）変更しづらいため、安定度が高いと定義されている。
つまり、安定依存の原則は変更することを意識して作られた(不安定な)パッケージが、変更しにくい(安定している)パッケージに依存されてはいけないということであり、言い換えれば「抽象に依存せよ」と言える。

### 安定度・抽象度等価の原則
> コンポーネントの抽象度は、その安定度と同程度でなければいけない

この原則は安定度と抽象度の関係についての原則だ。
安定度の高いコンポーネントは抽象度も高くあるべきで、安定度の高さが拡張の妨げになってはいけないと主張している。一方、安定度の低いコンポーネントは具体的なものであるべきだとしている。安定度が低いことによって、その内部の具体的なコードが変更しやすくなるからである。
したがって、コンポーネントの安定度を高くしようと思えば、拡張できるようにインターフェイスと抽象クラスで構成すべきである。安定度が高くて拡張可能なコンポーネントは柔軟になり、アーキテクチャへの制約も少なくなる。
この安定度・抽象度等価の原則と安定依存の原則の組み合わせが、コンポーネント版の依存関係逆転の原則に相当する。前者では安定度が抽象度と連動するものだと言い、後者では安定度が高くなる方向に依存すべきであると言っているからだ。つまり、抽象度が高くなる方向に依存すべきということになる。

### 結合おわり
ここには書くことができなかったが、本書ではコンポーネントの安定度や抽象度を数値で明確に区別する方法も記載されている。

## 参照
http://hamasyou.com/blog/2004/07/22/4797323361/