「Clean Architecture 達人に学ぶソフトウェアの構造と設計」を読んだのでそのまとめです。
第V部 アーキテクチャ
第15章 アーキテクチャとは?
アーキテクチャは、それを構築した人がシステムに与えた「形状」
アーキテクチャ(形状)の主な目的は、システムのライフサイクルをサポートすること
開発、デプロイ、運用、保守を容易にすること
最終的な目的はライフタイムコストを最小限に抑え、プログラマの生産性を最大にすること
ソフトウェアをソフトに保つには、できるだけ長い期間、できるだけ多く選択肢を残すことである
ソフトウェアシステムは「方針」と「詳細」に分割できる
方針は、ビジネスのすべてのルールや手順を含んでいる、ここには本当の価値がある
詳細は、方針についてやり取りするために必要なものだが、方針に影響を与えるものではない
アーキテクトの目的は、方針とは無関係に詳細を決めながら、方針を最も重要な要素と認識する形状を作ること
詳細に囚われず上位の方針を構築できれば、詳細の決定を遅延し、その分だけ適切に作るための情報が手に入る
第16章 独立性
アーキテクチャはユースケース、運用、開発、デプロイをサポートしなければならない
運用
開発
複数のチームは互いに干渉しないように、チームが独立して動けるように分割する必要がある
デプロイ
デプロイの手軽さの決定にも大きな役割を果たす
これらの懸念点とそれらを満足させる構造のバランスをうまく取る必要がある
実際にこのバランスを取ることは難しいし、ライフサイクルに応じて変化もしていく
レイヤーの切り離し、ユースケースの切り離しはバランスを上手く取ることができる原則である
さらにこれらは、ソースレベル、バイナリコード(デプロイ)レベル、実行単位レベルで切り離すこともできる
システムはモノリシックとして生まれ、単一ファイルでデプロイ、独立してデプロイ可能な単位になるまで成長し、サービスやマイクロサービスまでたどり着くことが 可能になる
その後、物事が変わったときにはモノリシックまで戻せるようになっておくべきである
第17章 バウンダリー:境界線を引く
ソフトウェアアーキテクチャとは境界線を引く技芸である
境界線は「重要なもの」と「重要ではないもの」の間に引く
第18章 境界の解剖学
アーキテクチャはコンポーネントとそれらを分離する境界によって定義される
境界を適切に超えるにはソースコードの依存関係を管理する
境界は、モノリス(ソースレベル)、デプロイコンポーネント(.dll)、スレッド、ローカルプロセス、サービスなどで存在する
第19章 方針とレベル
プログラムは「方針」を示したものであり、入力を出力に変換する方針を詳細に記述したもの
「レベル」とは「入力と出力からの距離」、離れていればそれだけレベルが高い
ソースコードの依存性はデータフローから切り離し、レベルと結びつけるべきである
同じ理由や時間で変更される方針は、単一責任の原則(SRP)と閉鎖性共通の原則(CCP)でグループ化される
上位レベルの方針は、下位レベルの方針よりも変更頻度が低く、変更の理由が重要である
下位レベルの方針は、変更頻度が高く、緊急性は高くとも理由はさほど重要ではない
第20章 ビジネスルール
ビジネスルールとは、マネーを生み出したり節約したりするルールや手続きのこと
それはコンピュータで実装されているかどうかに関わらず成り立つ
これを最重要ビジネスルールと呼ぶ
最重要ビジネスルールが必要するデータを最重要ビジネスデータと呼ぶ
これらをエンティティと呼ぶ
エンティティ
最重要ビジネスデータとそれを操作する最重要ビジネスルールをいくつか含んだもの
-
自動化されたシステムを定義・制限することで、マネーを生み出したり節約したりするルールもある
こうしたルールは手動の環境では使用されない
ユースケースからエンティティオブジェクトを参照したいと思うだろうが誘惑に負けてはいけない
この2つのオブジェクトの目的はまったく異なる、まったく違う理由で変化していく
第21章 叫ぶアーキテクチャ
建物の設計図は、それが「戸建て」であるとわかるはずだ
ソフトウェアアプリケーションのアーキテクチャもユースケースについて叫ぶべきである
優れたアーキテクチャは、ユースーケースを中心にしているため、フレームワーク、ツール、環境に依存することなくユースケースをサポートする構造を説明できる
優れたアーキテクチャは、ユースケースを強調し、周辺の関心事からユースケースを切り離す
ウェブは提供の仕組み(IO)であり、アーキテクチャは提供方法を知るべきではない
フレームワークは非常に協力であり、非常に便利なものだが、ユースケースを重視したアーキテクチャをどのように維持するか戦略をうまく策定する必要がある
上位レベルの方針が独立していれば下位レベルの詳細に依存することなくテストが可能である
第22章 クリーンアーキテクチャ
ヘキサゴナルアーキテクチャ、DCIアーキテクチャ、BCEは、「関心事の分離」という同じ目的を持つ
これらはフレームワーク非依存、テスト可能、UI非依存、DB非依存、外部エージェント非依存の特性を持つ
これらのアーキテクチャを単一の実行可能なアイデアに統合したものが例の図*1。
- 円の中心ほどレベルが高い方針であり、円の外側はレベルが低い詳細である
- アーキテクチャを動作させる最も重要なルールは、内側にだけ向かう依存性のルール
- 図の右下にあるのは、円の境界線をどう超えるかの例
第23章 プレゼンターとHumble Object
Humble Objectパターンは、テストしにくい振る舞いとテストしやすい振る舞いを分離するために生み出されたデザインパターン
Humble(控えめ)にはテストが難しい振る舞いのみが含まれ、もうひとつにテストしやすい振る舞いを含める
振る舞いをそれらに分割することがアーキテクチャの境界の定義につながる
ViewはHumbleであり、Presenterはテスト可能なオブジェクト
データベースゲートウェイ、ORM、サービスリスナーにもHumble Objectパターンが境界を作る
アーキテクチャの境界の近くにはHumble Objectパターンが潜んでいる
第24章 部分的な境界
本格的なアーキテクチャの境界はコストが高い
相互にポリモーフィックなBoundaryインターフェイス、Input/Outputのデータ構造、コンパイルやデプロイを独立させるための依存性管理が必要になる
優れたアーキテクトならコストが高いと判断すると同時にあとで必要になるかもと境界を残したいと思う
予測型の設計はYAGNIに違反しているが、部分的な境界を実装することになるだろう
部分的な境界では、独立したコンポーネントを準備したあとで同じコンポーネントにまとめたり、境界にする余地を残したStrategyパターンを使ったり、Facadeパターンで境界を作ったりする方法などがある
それぞれコストとメリットがあり、完全な境界に至るまでの代理として適切な場合もある
境界がうまく設定できなければ劣化していく可能性もある
アーキテクチャの境界をいつどこに作るのか、完全な境界なのか部分的な境界なのか決めるのはアーキテクトの役割である
第25章 レイヤーと境界
境界はあらゆるところに存在する
アーキテクトはそれがいつ必要になるか気を配らなければならない
境界を完全に構築しようとするとコストが高くつくことを認識する必要がある
境界を無視するとあとから追加するコストが非常に高くなることも認識する必要がある
アーキテクトは未来に目を向けなければいけない
頭を使って推測し、コストを評価し、境界がどこに、完全なのか部分的なのか、無視したほうがいいのかを判断する必要がある
さらに1回決定ではなく、進化するシステムに注意を払い常に見張る必要がある
第26章 メインコンポーネント
Main コンポーネントは究極的な詳細(最下位レベルの方針)でエントリーポイント
DIはMainに対し依存関係を注入し、Mainが依存関係を散りばめる
Mainは初期状態や構成を設定し、外部リソースを集め、アプリケーションの上位レベルの方針に制御を渡すプラグインである
第27章 サービス:あらゆる存在
アプリケーション振る舞いを分離するだけのサービスは単なる高価な関数呼び出しにすぎない
サービスは、アーキテクチャにおいては重要な要素ではない
第28章 テスト境界
テストはシステムの一部であり、システムの一部としてうまく設計すべき
システムの一部として設計されていないテストは、保守が難しくなる
常にテストがシステムのコンポーネントに依存する
変化しやすいものに依存しないテスト容易性のための設計が、システムとテストの結合の問題を解決する
テストをアプリケーションから分離するためにテストAPIを用いる
第29章 クリーン組込みアーキテクチャ
組込みの世界ではファームウェアを少なくしソフトウェアを多くする必要がある