Clean Architectureを読んで、軽くまとめた
本記事は、「Clean Architecture 達人に学ぶソフトウェアの構造と設計」という書籍を読んだ感想です。また、以前この書籍の「第22章 クリーンアーキテクチャ」をプレゼンする機会があり、その時に作成したメモが残っていたので、加筆修正してブログ記事として供養させていただきます。
読んだ感想
率直な感想として、読んで良かったです。
私は一通りプログラミングを学びましたが、本職はプログラマーではありません。普段は設計など考えない趣味のコードしか書いておらず、「良くないコード」を自覚しつつも、何が良くないのかが明確に説明できなかったので、少しモヤモヤしながらプログラミングをしていることもありました。
本書を読んだことで設計が出来るようになった訳ではありませんが、設計に対する理解が少し深まったことで、以前より「良くないコード」の何が良くないかが分かるようになり、モヤッとしながらコードを書き続けることが減りました。
実は、私は最初はこの本に対して少し懐疑的でした。というのも、クリーンアーキテクチャについてGoogleで検索すると、内容の矛盾を指摘した記事など批判的な内容のものがいくつか見つかったからです。ただ、そもそも読まないことにはなんの議論も出来ませんし、批判的なことが書かれていても本の価値は否定されていません。(読まず嫌いは良くない)
ユーモアのある語り口調で読んでいて楽しかったです。
ボブおじさん、ありがとう。
以下、第22章 クリーンアーキテクチャのメモです。
クリーンアーキテクチャまとめ
過去のアーキテクチャ
いずれのアーキテクチャも「関心ごとの分離」という同じ目的を有しており、ソフトウェアをレイヤーごとに分離することでその目的を達成している。
- ヘキサゴナルアーキテクチャ
- DCIアーキテクチャ
- BCE
最低限のレイヤー
最低限のレイヤーとしては次の二つがあげられる
- ビジネスルールのレイヤー
- ユーザーとシステム間のインターフェースとなるレイヤー
特性
これらのアーキテクチャは以下の特性を持つシステムを生む。
- フレームワーク非依存:機能満載なライブラリに依存しない(そのライブラリに縛られた設計をしない)
- テスト可能:ビジネスルールは外部要素(UI、データベース、ウェブサーバ、そのほか外部要素)がなくてもテストができる。
- UI非依存:UIを他の部分に影響を与えず変更できる(GUIからCUIへの変更など)
- データベース非依存:データベースを他の部分に影響を与えず変更できる(SQLからNoSQLへの変更など)
- 外部エージェント非依存:ビジネスルールは、外の世界のインターフェイス(DB,UI,Webなど)について何も知らない
クリーンアーキテクチャとは、アーキテクチャを単一実行可能なアイデアに統合したもので、それが良く知られた4重の円で表現される。
クリーンアーキテクチャという概念をどう捉えるかについては、大きく分けて二つの意見があります。 一つは、前述の図に登場する用語や概念を用いて、4層レイヤーから成るAPアーキテクチャを指す場合です。ほとんどのシチュエーションではこちらの意味で使われます。 一方で、クリーンアーキテクチャで重要とされる「依存性のルール」、「関心の分離」、「依存関係逆転の法則(DIP)」などに着目し、図には拘らない方が良いという意見もあります。実際に提案者は、図は概要であり、クリーンアーキテクチャは4層以上にもなりうると述べています。
図の円は概要を示したものである。したがって、この4つ以外は認めないというルールはない。
-- Robert C.Martin,角 征典,高木 正弘. Clean Architecture 達人に学ぶソフトウェアの構造と設計 (Japanese Edition) (Kindle の位置No.3161-3165). Kindle 版.
クリーンアーキテクチャ
クリーンアーキテクチャのレイヤーは4重円で表現され、内側から順に
エンティティ < ユースケース < インターフェイスアダプター < フレームワークとドライバ
の4層になっている。
依存性のルール
-
円の中央に近づくほどレベル(抽象度?)が上がっていく
-
円の外側は仕組み、内側は方針
-
ソースコードの依存性は、内側(上位レベルの方針)だけに向かっていなければいけない
-
円の内側は外側について何も知らない
-
外側で宣言された名前に、内側で触れてはいけない
- 関数
- クラス
- 変数
- その他名前付きのソフトウェアエンティティ
-
データフォーマットも同様
4つのレイヤー
エンティティ(レイヤー)
企業全体の最重要ビジネスルールをカプセル化したもの。
エンティティ自体はアプリケーションから使用できるならなんでも良い。(メソッドを持つオブジェクトでもデータ構造と関数でも)
外部からの影響を全く受けない
ユースケース(レイヤー)
アプリケーション固有のビジネスルールが含まれている。
システムの全てのユースケースがカプセル化・実装されている
- エンティティに入出力するデータの流れを調整する
- ユースケースの目的を達成できるように、エンティティに指示を出す
外部からの影響を受けないし、エンティティにも影響を与えない
ただ、アプリケーションの操作の変更された場合、ユースケースレイヤーのソフトウェアに影響を与えることはある。
もちろん、ユースケースの詳細が変更されたら、ユースケースレイヤーのコードも一部影響を受ける。
インターフェイスアダプター
ユースケースレイヤーやエンティティレイヤーに便利なフォーマットから、外部エージェントに便利なフォーマットにデータを変換するアダプター
※ここでのフォーマットとは、粒度の小さいデータのこと? (jsonの中身の形の変換など)
GUIのMVCアーキテクチャを保持するのはこのレイヤー
- モデル:ただのデータ構造
- コントロール:ユースケースとのインターフェイス
- ビュー:UIとのインターフェイス
ユースケースレイヤーやエンティティレイヤーに便利な形式(form)から、DBに便利な形式(form)にデータを変換するアダプター
※ここでの形式とは、粒度の大きいデータのこと? (jsonからCSVへの変換など)
データベースがSQLならば、すべてのSQLはこのレイヤーに含める。
外部サービスなどの外部の形式から、ユースケースやエンティティが使用する内部の形式にデータを変換するアダプターも含まれる。
要するにデータの変換は全てここで行う。
フレームワークとドライバ
フレームワークとツールで構成されている。
例えば、ウェブフレームワークやデータベース。
このレイヤーにはコードをあまり書かない。
書く場合は一つ内側とやりとりするグルーコードくらい。
このレイヤーには詳細が詰まっている。ウェブも詳細、データベースも詳細。
4つの円だけ?
4つ以外認めないというルールはないが、依存性は常に内側を向けるべきであり、内側ほど抽象度と方針のレベルは高まる。
境界線を越える
境界線を越えることがあっても、内側が外側に依存するようなことがあってはならない
コントローラを操作して、ユースケースレイヤーを通り、プレゼンターに出力する場合を考える。
ユースケースはプレゼンターを呼び出したいが、直接呼び出しはできない。
そこで、ユースケース内のインターフェイスを呼び出すようにし、円の外側にあるプレゼンターがインターフェイスを実装する
インターフェイスとはこういこうことをしたいと書かれたルールみたいなものなので、ユースケースに含まれる。そして、実装を外側でしてあげれば依存することはない。
境界線を越えるデータ
境界線を越えるデータは独立した単純なデータ構造であることが重要。
そのレイヤーで使われるデータのまま渡すのではなく、渡されるれるレイヤーが使いやすいデータの形式で渡す。
参考文献
Discussion