Open9
クリーンアーキテクチャ
メモ
切り離し方式
- レイヤー切り離し
- (UIや、データベース、クエリ言語などの) 技術的要素 ビジネスロジック UIは独立して変更されるはずである
- システムは水平レイヤーで分割されている
- 水平レイヤー(UI、アプリケーション特有のビジネスルール、アプリケーションに依存しないビジネスルール、データベースなど)
- ユースケース切り離し
- insertとdeleteと比較して変更の頻度は違うものである
- なので分割されるべきである
- ユースケースは水平レイヤーを垂直に分割したもの
- UIの一部、アプリケーション特有のビジネスルール後イブ、アプリケーションに依存してないビジネスルールの一部、データベースなど)
- 変更する理由の違いでシステムの要素を切り離すと独立性が保たれるため、古いものに影響を与えずに新しいものを追加できる
- insertとdeleteと比較して変更の頻度は違うものである
- 切り離し方式
- 運用で、多く帯域が必要なものとそうでないもので分離できる
- UIやデータベースがビジネスルールから分離されていれば、異なるサーバーで実行できる
- これを別名マイクロサービスという
- 運用で、多く帯域が必要なものとそうでないもので分離できる
- 独立した開発
- 分離すれば独立して開発ができる
- 独立デプロイ
- も可能
- 重複
- 同じような画面が必要な2つのユースケースがあったときに共通化したくなる
- これは偶然の一致なので共通化するべきではない
- 共通化すると、分離するのが大変
- 同じような画面が必要な2つのユースケースがあったときに共通化したくなる
- 切り離し方式
- ソースレベル(実行ファイル)
- デプロイレベル(DLLやjarファイル分割など)
- サービスレベル(マイクロサービスなど)
バウンダリー
- 境界線を引く
- 技術的要素を分離することで、ビジネスルールに集中できる
方針とレベル
- 例 暗号化処理の際に IOの変更でコードの変更をさせないようにするべき
- 暗号化処理が上位 であり IOは下位である
- 上位に下位が依存するようにする
ビジネスルール
- ビジネスルールはデータベースやフレームワークなどの他の技術的要素から独立しており、それらの変更により変更されるべきではない
叫ぶアーキテクチャ
- アーキテクチャはフレームワークではなく、システムそのものについての情報を伝える必要性があり
- フレームワークの複雑さがなくてもテストが可能な状態でなければならない
クリーンアーキテクチャ
- 依存性ルール
- 依存関係は内部だけに向かっていかなければならない
- エンティティ
- ビジネスルールをカプセル化したものの
- 関数 オブジェクトでも構わない
- どこからでも利用できる
- 最上位のルール
- 他のものから影響を受けない(ようにする)
- ビジネスルールをカプセル化したものの
- ユースケース
- アプリケーション固有のビジネスルールが含まれている
- ユースケースは動きを示している(例えば本を借りる、本を返すなどの動詞に当たる)
- ユースケースは独立している
- アプリケーション固有のビジネスルールが含まれている
- インターフェイスアダプター
- ユースケースやエンティティなどの便利なフォーマットからデータベースや、ウェブなどの外部のエイジェントに変換するアダプター
- controllerやrepositoryのことっぽい (図には、Gateway, Controller, Presentersが記述されている)
- Gatewayは外部とのやり取り(外部APIなど)
- Repositoryはデータベースとのやり取りという認識
- Controllerはユースケースにデータを流す役割 (入力側)
- Presentersはユーザのわかりやすい形式に変換し、UIなどに変換する役割 (出力側)
- フレームワークとドライバ
- 一番外で、あまりコードを記述しない
4つの円だけ?
- 必要ならば足しても引いても良い
境界線を超える
- 制御の流れはcontroller(入力)→usecase(処理)→presenter(出力)になっている
- ただこの通りに実装すると、ユースケースがpresenterに依存してしまう
- DIP(依存性逆転の原則)を利用して、解決する
- ただこの通りに実装すると、ユースケースがpresenterに依存してしまう
- 境界線を超えるデータ
-
境界線を超えるのは独立した単純なデータ構造であること
- SQLの行をそのままオブジェクトにマップするような仕組み(行構造)は依存性ルールに違反している
- そのため境界線を超える際には、中心園にとって便利な構造にする
-
やはりController入力 Presenterが出力を行うような形になっている。
UseCaseがinteractorの役割を行い、Controller,Presenterのinterfaceを介して入出力を行う
ただこちらの記事でも指摘されている通りPresentersは最近のウェブフレームワークとの相性が悪い。
https://nrslib.com/clean-architecture/#outline__5_1_3 こちらの記事がわかりやすい
HumbleObject
- ユニットテストし易いものとしにくいもので分離したもの
- し易いもの
- Presenter(Viewへの変換ロジック)
- しにくいもの
- View
- UIやデータベース、外部APIや、UnityのmonobihaiverみたいなやつやMinecraftのspigot
- こちらをHumbleというらしい(?)
- テストしにくいものは実装を控えめにする
- し易いもの
- 他のサービスと通信する必要がある場合でもHumbleObjectパターンがサービスの境界を作成する
Unityの話だがわかりやすい
部分的な境界
- 今は必要ないが、後で必要になるかもしれない境界
- YAGNIに違反していがやっぱり後で必要になるかもしれない
- 片方だけの分離
- 双方向の分離はコストが高い
- Strategyパターン
- interfaceが境界
- Strategyの実装が利用される側に依存してしまうことがある
- 開発者が規律を持って実装する必要がある
- Facadeパターン
- 依存性逆転を断念
- facadeクラスが境界
- Service変更時にClinetも変更する必要性がある可能性がある
- こちらも利用される側に依存してしまうことがある
レイヤーと境界
-
UI、ビジネスルール、データベース などの3つコンポーネントで分離されているが、本当にこれだけなのか?
- ゲームで考えてみると
- 複数の言語の対応 (Language)
- チャットの方式(TextDelivery)
- データの保存方式(Data Storage)
- 通信方式(Network) (ローカルかマルチか)
- 複数の境界があるはず
- APIコンポーネントだけで考えるとシンプルである
- ゲームで考えてみると
-
サーバー処理とクライアント処理でも分けることができる
- 例えばPlayerManagementとMoveManagementがあり、
- PlayerMangement (ユーザのステータス 空腹 Hp 健康状態) 上位 サーバー処理
- MoveManagement( FoundFoodやFellInPit などのイベント) 下位 クライアント処理
- PlayerManagementがMoveManagementに対してマイクロサービスのAPIを提供する
- 例えばPlayerManagementとMoveManagementがあり、
-
アーキテクチャの境界は様々な部分に存在する
-
完全な境界はコストが高い
-
コストが高いならば、必要になるまで境界を作成する必要はない(YAGNI)
- ただそうすると追加が必要になったときの切り離しコストが高くなる
- なので未来を予想して推測するべきである
- 境界が必要になる場所、境界がないために、発生している問題などを感じ取る
メインコンポーネント
fun main() {
}
の部分
- 一番詳細
- 下位
- クリーンアーキテクチャの図の外側
- 上位レベルのための読み込みや制御を渡す
サービス
- サービスがお互いに分離されているようにみえる
- 誤った分離
- サービス感で渡されるっデータレコードに新しいフィールドが追加されると、その新しいフィールドを利用を扱うすべてのサービスを変更することになる
- データの解釈も強く合意する必要がある
- データレコードと強く結びついている
- 結果的に間接的に相互に結びついている
- 誤った分離
サービスの分割はすべての動作に影響を与える新機能の追加に対して非常に弱い
-
救世主のオブジェクト
- Template Method Storategyパターンを利用している
-
横断的関心事
- アーキテクチャの境界はサービスとサービスの中間ではなく
- サービスを横断すること
- サービスがシステムのアキテクチャの境界を定義してうrのではなく、サービス内部のコンポーネントが定義している
テスト境界
- テストをシステムの一部なのか?
- 結論違う
- 詳細なので円の外側
- 下位
- テスト容易性のための設計
- システムと結合したテストはこわれやすい
- 脆弱なテスト問題
- 変化しやすいものに依存しない
- GUIに依存したテストは脆弱だ
- システムと結合したテストはこわれやすい
クリーンアーキテクチャの本質は境界をうまく定義することで、コードを疎にすることができ、システムの変更を柔軟に行うことができることを主張しているのだと思う。ただし境界を作りすぎるとつなげるコストがかかり大変であることも指摘している。
積極的に境界を見つけ出して、境界がない事による複雑さをなくすように呼びかけている。