目的
本記事ではClean Architecture 達人に学ぶソフトウェアの構造と設計を読んだので、それに関する感想を書いていこうと思います。
部毎のまとめは以下のページにリンクされています。
https://astro-notion-blog-c5p.pages.dev/posts/clean-arc-1/
https://astro-notion-blog-c5p.pages.dev/posts/clean-arc-2/
https://astro-notion-blog-c5p.pages.dev/posts/clean-arc-3/
https://astro-notion-blog-c5p.pages.dev/posts/clean-arc-4/
https://astro-notion-blog-c5p.pages.dev/posts/clean-arc-5/
https://astro-notion-blog-c5p.pages.dev/posts/clean-arc-6/
感想
この本を読む前は、クリーンアーキテクチャという名前だけを知っていました。また、他にもアーキテクチャを設計する際のパターンは様々存在しており、その中でも現在最も主流であるアーキテクチャパターンという印象を持っていました。
過去にいくつか、クリーンアーキテクチャについてネットやブログを調べてみたりGoのクリーンアーキテクチャ構成などをみていましたが、なぜそれを使うと嬉しいのかといった点については理解できておらず、どのような構成がクリーンアーキテクチャなのかといったところについても理解していませんでした。
実際にこの本を読んでみて本当に良かったです。ネット上にはクリーンアーキテクチャという言葉を利用した、あるベストプラクティスを提唱するような記事が出回っています。ただ、それを理解せずに使うのはあまりスマートであるとは言えません。なぜなら同じクリーンアーキテクチャを採用する構成でも、そのチームやプロダクトにおいての構成は変化するものだからです。
重要なことは、形式ばったベストプラクティスではなく、長年のソフトウェア開発の歴史において得られた経験知から生まれた不変となる原則であるということです。その不変の原則に背いていないような設計こそがクリーンアーキテクチャをクリーンアーキテクチャたらしめるのだとこの本を読んで感じました。
ではここからその原則とは何なのか?実際にクリーンアーキテクチャを使いこなすには?とった点で自らの解釈を書いていこうと思います。
原則とは何か?
一部の原則には、思想的には似たような意味なので一つの原則としてまとめるべきでは?と思われるものもあると思いますが、ここではあえて本書への登場順に分けて書いてあります。インデントされたリストにはその本質の参考となるキーワードを掲載します。
-
理想のアーキテクチャとは、求められるシステムを構築・保守するために必要な人材を最小限に抑えること
- ソフトウェアアーキテクチャの目的
-
大問題を解決するにはそれを小問題にブレイクダウンしていく必要がある。なぜなら小問題にブレイクダウンすることで独立開発・独立デプロイできるようになるから
- 独立開発可能性、独立デプロイ可能性、構造化プログラミング
-
知らなくていいものは知らない方が良い。なぜなら関係性をできるだけシンプルに保てるから
- ポリモーフィズム
- カプセル化
- インターフェース分離の原則(Interface Segregation Principle)
-
不変性のあるものを多くしたい。なぜなら変更にコストを割きたくないから
- 関数型プログラミング
-
個々のモジュール(ひとまとまりの機能を持った部品)を変更する理由がたった一つになるように設計すること
- 単一責任の法則(Single Responsibility Principle)
-
ソフトウェアを変更しやすくするために既存のコードの変更よりも新しいコードの追加によってシステムの振る舞いを変更できるように設計すること
- オープン・クローズドの原則(Open Closed Principle)
-
交換可能なパーツを使ってソフトウェアシステムを構築するなら、個々のパーツが交換可能となるように継承・派生を適切に利用する。
- リスコフの置換原則(Liskov Substitution Principle)
-
上位レベルの方針のコードは、下位レベルの詳細の実装コードに依存するべきではなく、逆に詳細側が方針に依存するべきであるという原則
- 依存関係逆転の原則(Dependency Inversion Principle)
-
再利用の単位とリリースの単位は等価にならなければならない。なぜなら等価でないと、変化が容易でないか、知らなくていいものを知らない方が良いという思想を破ってしまう
- 再利用・リリース等価の原則(REP)
-
同じ理由、同じタイミングで変更されるクラスをコンポーネントにまとめる
- 閉鎖性共通の原則(CCP)
-
コンポーネントのユーザーに対して実際には使わないものへの依存を強要してはいけない
- 全再利用の原則(CRP)
-
コンポーネントの依存グラフに循環依存があってはいけない。コンポーネント図の依存関係は有向非循環グラフであるべき。なぜなら循環依存があるとどれを変更したとしても変更が必要となり変更のコストが大きくなる。
- 非循環依存関係の原則(ADP)
-
変更しやすい意図を持ったコンポーネントは依存されないように設計して、安定度の高い方向に依存すること
- 安定依存の原則(SDP)
-
安定度(他のコンポーネントからの依存され具合)の高いコンポーネントは抽象度(コンポーネントの抽象クラスやインターフェースの割合)も高くあるべき。
- 安定度・抽象度等価の原則(SAP)
- 方針と詳細を区別して、方針が詳細を把握することなく、決して依存することがないように、両者を切り離す
- 詳細の決定をできるだけ延期・保留できるように方針をデザインする。詳細を決めると柔軟に対応しにくくなるから、後回しにすると詳細を考慮する材料が多くなるから
- コードの重複を目にした時、反射的に重複を嫌うのではなく、本物かを見極める
-
ビジネスルールこそがシステムの中で最も独立していて、最も再利用可能なコードでなければならない
- 最重要ビジネスルール
-
アーキテクチャはフレームワークに依存するのではなく、ユースケース中心に設計されるべきであり、機能満載のソフトウェアライブラリに依存していない。これによりフレームワークの制約で縛るのではなく、フレームワークをツールとして使用できる
- フレームワーク非依存
-
ビジネスルールはUI、DB、サーバー、その他の外部要因なしにテストできる
- テスト可能
-
UIはシステムの他の部分を変更することなく簡単に変更できる
- UI非依存
-
データベースを柔軟に置き換え可能、ビジネスルールはDBに束縛されてない
- データベース非依存
-
ビジネスルールは外界のインターフェースについて何も知らない
- 外部エージェント非依存
- ソースコードの依存性は内側(上位レベルの方針)だけに向かっていなければいけない
- 境界線を超えるデータは単純なデータ構造であることが大切
-
データベース、外部サービス、UIなど境界線の付近にはhumble objectを使用して、テストしにくい振る舞い、テストしやすい振る舞いを二つに分けてテスト容易性が大幅に向上させる
- humble object
- DB・Web・フレームワーク・ハードウェア・ファームウェア・GUI等の詳細なるものたちに依存しない
- チームの規模やメンバーのスキルやソリューションの複雑さ、そして時間と予算の制約などを考慮しよう
参考
クリーンアーキテクチャ設計の方法
ここでは本書を読み終えた、自分なりのクリーンアーキテクチャの設計フローに関して考察を書いていきたいと思います。これは自分なりの現在の解釈なので温かい目で見守ってください。主には本書の「事例:動画販売サイト」やIinumaさんの社内勉強会での発表を参考にしました。
- 課題の発見と問題の分析
- 問題の分析を基にした解決策の提案
-
ユビキタス言語の抽出
解決策を提案する上で、その解決方法は言語化されて内部にも外部に向けても共通認識を取るために、理解しやすいユビキタス言語を定義する。アプリ内のドメイン用語の様なもの
事業に露出する名前と内側に閉じた名前を認識として分けて設定できると良い
-
エンティティの識別
ユビキタス言語を抽出すると、ビジネスルールやビジネスデータが見えてくる。これらをエンティティとしてエンティティを識別する。ER図のようなものでデータ構造を可視化する。
コンテキストの分類等もこのタイミングで行う
-
アクターとユースケースを見つける
コンテキスト毎に、ドメインモデルを利用したフローやユースケース、そのドメインモデルの関係性を洗い出す。
-
コンポーネントアーキテクチャの検討
上述した原則に背かないように設計を行う