クリーンアーキテクチャ(Clean Architecture)
ボブおじさん(ロバート・C. マーチン)著
この本を読むと得られるもの
- ソフトウェアのアーキテクチャとは何かを理解できる
- ソフトウェアのアーキテクチャの目的を理解できる
- 優れたアーキテクチャが実践している思想や手法を理解できる
以降で、全てを紹介し切ることはできないので、私自身が特に気づきを得た部分を抜粋して紹介(全内容を見たい方はぜひ購入して読んでみてください。)
第1章 設計とアーキテクチャ
ソフトウェアアーキテクチャの目的
システムを構築、保守するために必要な人材を最小限に抑えること。逆にリリースごとに労力が増えていればその設計は優れていないと言える
後でクリーンにすればいいよ(P38,39)
- 開発者は自信過剰な競争をしている。クリーンなうまく設計されたコードが重要であることがわかっていない。(ウサギとカメ)
- 「後でクリーンにすればいいよ。先に市場に出さなければ」と考えるが、実際にはあとでクリーンにすることはない。市場からのプレッシャーが止まらないからだ。
- 短期的にも長期的にも崩壊したコードを書く方がクリーンなコードを書くよりも常に遅い(TDDを用いた実験結果)
- 生産性の低下とコストの増加を回復させる唯一の方法は、開発者にうさぎの自信過剰な思考をやめさせ、自ら生み出した崩壊に対して責任を持たせることである
第15章 アーキテクチャとは?
選択肢を残しておく
- ソフトウェアには振る舞いの価値と構造の価値という2種類の価値があり、後者の方が価値が大きい。なぜならソフトウェアをソフトにする価値だからだ
- ソフトウェアは、方針と詳細の2つの要素に分けられる。方針にはビジネスのルールや手順を含んでおり、本当の価値がある。一方詳細は、フレームワーク、データベース、通信プロトコルなどが含まれ、ソフトウェアをソフトに保つためには、この詳細部分に関してできるだけ長い期間できるだけ多くの選択肢を残すことである
まとめ
優れたアーキテクトは方針と詳細を慎重に区別して、方針が詳細を把握することなく決して依存することがないように両者を切り離す。
第16章 独立性
重複
ソフトウェアの世界では、重複は悪いものだとされている。だが、明らかに重複していたコードが異なる進化を遂げ、数年後には両者がまるで違ったものになっていることもある。これは本物の重複ではない、偽物の重複あるいは偶然の重複である。こういった重複は時間が経てば少しずつ違ったものになり、最終的には別物になる可能性が高い。したがって統一的に扱わないように注意する必要がある(共通化の罠)
第17章 境界線を引く
導入
- ソフトウェアアーキテクチャとは、境界線を引く技芸である。ソフトウェアの要素を分離し、お互いのことがわからないように制限するというものである。
- 境界線を引けば、決定を延期・確保できる(Ex. 永続化層がインメモリか、ファイルか、DBか)
あなたの境界線は何か? いつ境界線を引くのか?
- 境界線は重要なものとそうでないものの間に引く
- 重要なもの=ビジネスルール、需要でないもの=フレームワーク、DB、WEB(GUI)
プラグインの戦い
- 境界線は変更の頻度や理由が異なる箇所に引く。例えば、ビジネスルールとフレームワーク、ビジネスルールとGUIは異なる時間や理由で変更されるので、これらの間には境界線を引くべき
第19章 方針とレベル
レベル
- 優れたアーキテクチャでは、下位レベルのコンポーネントが上位レベルのコンポーネントに依存するように設計されている
- レベル定義は、入力と出力からの距離である。方針がシステムの入力と出力から離れていればそれだけレベルは高くなり、入力と出力を管理する方針はシステムの中で最下位レベルの方針になる
- Ex. 暗号化プログラムの暗号化の方針と暗号化される値の入出力に対する方針の関係
NG. 上位レベルのencryptが下位レベルのreadCharとwriteCharを直接呼び出している
function encrypt() {
while (true)
writeChar(translate(readChar()))
}
- ソースコードの依存性を上位レベルの方針に向けておけば、変更が及ぼす影響は軽減できる
- 上位レベルの方針は下位レベルの方針よりも変更の頻度が低く、変更の理由が重要である(暗号化の方針)。一方、下位レベルの方針の変更の頻度は高く、緊急性は高いものの、変更の理由はさほど重要ではない(入出力の方針)
第20章 ビジネスルール
導入
ビジネスルールとは、ビジネスマネーを生み出したり節約したりするルールや手続きのこと。(これがシステムによって生み出させれるのか、手動で生み出されるかは関係ない)
エンティティ
ビジネスルールを表したクラスやモジュール=エンティティ
ユースケース
- ビジネスルールはエンティティほど単純なものだけではない。システムを使うことで初めて発生する(手動では発生しない)ビジネスルールも存在する。エンティティとは違い、ユースケースには、こういったアプリケーション固有のビジネスルールを記述する
- ユースケースを見ただけでは、それがウェブなのかコンソールなのかということを判断することは不可能(なようになっているべき)
- ユースケースはHttpRequestやHttpResponseといった標準的なフレームワークのインターフェースから派生したものではない。ウェブのことは何も知らないし、他のユーザーインターフェースに関することも把握していない。ユースケースは、入力としてシンプルなリクエストデータ構造を受け取り、出力としてシンプルなレスポンスデータ構造を戻す
- ユースケースはエンティティに依存し、エンティティはユースケースに依存しないようにすべき
- ビジネスルールはシステムの中で最も独立していて、最も再利用可能なコードでなければいけない
第21章 叫ぶアーキテクチャ
アーキテクチャの目的
- 優れたアーキテクチャはユースケースを中心にしている
- 建築家の最大の関心ごとは家がレンガで作られていることではなく、家が使用可能であること
- 優れたアーキテクチャがあれば、フレームワーク、データベース、その他の環境の問題意思決定を延期・留保できる
フレームワークはツールであり、生き方ではない
ウェブは、提供の仕組み(IOデバイス)であり、アプリケーションがウェブで提供されているという事実は詳細であり、システム構造を支配するものではない。システムアーキテクチャは提供方法を知るべきではない。コンソールアプリケーション、ウェブアプリケーション等かどうかに関わらず問題なく提供できるようにすべきである
第22章 クリーンアーキテクチャ
クリーンアーキテクチャの5つの性質
フレームワーク非依存
システムはフレームワークの制約で縛るのではなく、フレームワークをツールとして使用しているという状態が重要
テスト可能
ビジネスルールはUI、データベース、ウェブサーバーその他の外部要素がなくてもテストできる
UI非依存
システムの他の部分を変更することなく、簡単に変更できる。例えばビジネスルールを変更することなく、ウェブUIをコンソールUIに置き換えることができる
データベース非依存
ビジネスルールがデータベースに束縛されていない。MySQLをPostgreSQLに乗り換えることができる
外部エージェント非依存
ビジネスルールは、外部のインターフェースについて何も知らない
(ウェブサーバー、サードパーティライブラリなど)
依存性のルール
縁の外側は仕組み、内側は方針である。外側で宣言された名前は、内側にあるコードで触れてはいけない。
境界線をこえる
依存性のルールに違反して円の外側にアクセスして境界線をこえる場合、依存関係逆転の原則を使ってソースコードの依存関係が、制御の流れと逆転するようにする
Ex.ユースケースからリポジトリへのアクセス
境界線をこえるデータ
境界線を超えてデータを渡すときは、常に内側の円にとって便利な形式にする。ORMなどではクエリに対してモデルのインスタンスなどを返すが、これを円の内側のユースケースやエンティティで使うべきではない
第23章 プレゼンターとHumble Object
様々な境界(humble object パターン)
- Humble Objectの代表例であるviewとpresenterはテストしやすい部分(GUIの表示に関するロジック、振る舞い)とテストしにくい部分(GUIの表示)に境界を設けて分割した典型的なパターン
- アーキテクチャの境界でこのパターンを使用すると、テスト容易性が向上する
第24章 部分的な境界
- アーキテクチャには境界が重要である一方。将来のために全ての境界を完璧に作り上げることは、YAGNIに違反しているとされるため、部分的に境界を構築するための仕組みとして、Strategyパターン、Facadeパターンを用いる方法を説明している
- 完全な境界と部分的な境界の2つのアプローチを理解し、いつどこに境界を作るのかについて決定することはアーキテクチャの役割
第27章 横断的関心事と図27-3
- サービス指向アーキテクチャ(巨大なシステムを特定の機能を持つ細かなサービスとして分け、それらを使用することでシステムのスケーラビリティや開発の利便性を向上させる目的で使用される手法)
は、本書の指すアーキテクチャにとってあまり重要ではない。単にサービスを分けたからといって、各サービス間で関数の呼び出しを行なっているにすぎない場合は結合度が強く、将来の変更に対して弱い(全ての動作に影響を与える新機能の追加に対して非常に弱い) - サービスの間に境界があるのではなく、サービス内部のクラスがそれを定義している。
- これらに対応するためには、単にサービス単位で分割するだけではなく、新機能をポリモーフィックに追加するだけで済むようにしておく必要がある。(if文の条件追加=変更ではなく、クラスの追加)
第32章 フレームワークは詳細
導入
フレームワークはアーキテクチャではない
リスク
フレームワークの作者は使用する側に対して何の責任も義務も負う必要がない。にもかかわらず極度にフレームワークに依存することは、
- フレームワークの進化する方向性が使用する側の希望から逸れるかもしれない
- 使っていた機能が廃止されたり
- 仕様変更されてしまったり
- 他の優れたフレームワークに乗り換えたい
などのリスクを負うことになる
一方的な結婚
- フレームワークの作者は、円の最も内側にフレームワークを結合させたがっている。(フレームワークのコードを継承してエンティティに組み込むなど)一度入り込んでしまえば、それを取り出すことはできなくなる。
- フレームワークの作者はフレームワークとの結婚を申し込んでいる。一度はめた結婚指輪は、ずっとあなたの指に残り続けるのだ。
解決策
フレームワークを使うことは問題ない。結合しないことが大切。常に縁の外側にあるものとして付き合う
第33章 事例:動画販売サイト
これまでに紹介されているアーキテクチャのルールや思想を適用したケーススタディ
ユースケース分析とアクター
いきなり具体的なクラス、インターフェースの設計に移るのではなくまずアクターの整理と各アクターごとのユースケースを整理、分析することが重要
第34章 書き残したこと
悪魔は実装の詳細に宿る。いくら上手い設計をしても、その実装方法の複雑さを考慮しなければ、あっという間に設計は崩れてしまう。(publicアクセス修飾子の乱用)
まとめ
いかがでしたでしょうか。本記事ではクリーンアーキテクチャ(Clean Architecture)の要約と読んだ感想について紹介させていただきました。アーキテクチャの目的である「システムを構築、保守するために必要な人材を最小限に抑える」ために必要な境界や依存性の考え方、具体的な手法について学習できる一冊になりますので、ぜひ皆さんも書籍を購入して学習してみてください。