皆さんこんにちは! 最近作ろうとしているアプリを Clean Architecture で実装しようと思い立ちました。
しかしどういうものかを忘れてしまっていたため、今回は備忘録がてらブログにまとめようと思います。
Clean Architecture はシステムアーキテクチャ
アーキテクチャは大別すると、以下2つがあります。
- GUIアーキテクチャ
- システムアーキテクチャ
GUIアーキテクチャは UI と モデル を分けるというところにフォーカスしたアーキテクチャです。 一方、システムアーキテクチャは上記にとどまらず、システム全体の構造に着目したものになります。
Clean Architecture は後者です。
4つの登場人物、配置と依存関係のルール
Clean Architecture には重要なコンポーネントと呼ばれる登場人物が4人います。 それがこれらです。
- Entity
- Use Case
- インタフェースアダプタ
- フレームワークとドライバ(DB含む)
システム構造は同心円状に層を形成していて、若い交番のものから順に内 -> 外に配置されます。 依存関係のルールとして、外から内 の方向に依存させる決まりがあります。
円の外側に行くほど、より抽象度が高くなります。 内側のアプリケーションとは切り離されたシステム部分は、変わりやすい外部にあるフレームワークなどの変更から守られます。
Entity
Entity は処理方法に依存しないビジネスロジックでデータ構造やメソッドの集合体です。 同心円の中心に位置しており、依存先を持ちません。(Use Caseや他の層がこのロジックを使って何をするかを気にしない)
e.g. 銀行の利子計算ロジックがEntity、そろばん or 計算機で行う計算作業はEntityの外側の層が担当する
Use Case
Entityを使用し、アプリケーション固有のビジネスロジックを実現します。 アプリケーション固有のビジネスロジックとは構築対象のアプリケーションにのみ有効な処理という意図があります。
Entity のみに依存します。
これに対し、Entityは複数のアプリケーションに使われる普遍のものと言う考えとは対照的です。 複数のアプリケーションとは将来作りうるアプリケーションという意味もあるので今回1つだけアプリを作るという場合でも考慮は必要です。
Use Case層には UIに関する処理は記述しません。
入出力のためのポート(出入り口)はありますが、それがどう使われるかについては気にしません。
インタフェースアダプタ
自身と接するレイヤーに対してデータやイベントを変換する役割を担います。 具体的には Use Case や Entity で扱っているデータ表現、SQL や UI用のデータを相互に変換します。
Presenter や Controller がこの役割を担います。
Use Caseに依存します。
フレームワークとドライバ
UI、DB、デバイスドライバ、WebAPI クライアントなどがこの最外層に該当します。 環境、顧客により最も影響を受けるのがこの層です。
インタフェースドライバに依存します。
特定の条件下でのみ有効なコードがここに集まり、代表例としては Flutter や React Nativeでのネイティブコードはこのレイヤーに配置されます。
以下についてもこの層で扱われるということを認識する必要があります。
- UIや実装先のOS種類
- フレームワークの種類
よって、UIKit や Alamofire などのこの層で扱われます。
...
...
...
このように、4つの登場人物を厳密に分けることによって、外層の実装が変わったとしても内部のコアの部分がクリーンに保たれるのが Clean Architecture を用いる利点となります。