Clean Architecture


感想
改めてこういうテーマの本を読むと「めっちゃわかるー!」ってなる内容もありつつ、「ここってこういう意味だったんか」みたいな発見もありつつ読めてて楽しい。
全体
- どんな言語でも Architecture のルールは同じ。
- #アイゼンハワーのマトリクス で言うと、コードの振る舞いは「緊急かつ重要でない(左下)」または「緊急かつ重要(左上)」になり、アーキテクチャは「重要かつ緊急でない(右上)」または「緊急かつ重要(左上)」に入る。
- #オブジェクト指向プログラミング(OO, Object-Oriented)は、ポリモーフィズムを使うことで、システムの依存関係を絶対的に制御する。#依存関係逆転 がこれ。依存関係の逆転を利用することで、「ルールに依存した」システムを作ることができる。
3つのパラダイム
- #関数型プログラミング →直接的な制御の移行に規律を設ける。
- #オブジェクト指向プログラミング →間接的な制御の移行に規律を設ける。
- #構造型プログラミング →代入に規律を設ける。
- これら3つのパラダイムは、何かに規律を設ける=何を「やるべきでない」かを定めて制御する。
#SOLID原則
- #単一責任の原則:「何か1つのことだけ行うべき」と解釈されることがあるが、実際は「何か1つのモノやモジュール(これらをアクターとも言えるもの)に対しての責任を負い、その1つのアクターのためだけに変更されるべき」と言うもの。
- #オープン・クローズドの原則:「システムは拡張に対して開かれて、変更に対して閉じられたものであるべき」と言うもの。つまり、新機能の追加などに対しては開かれていて、既存の機能を変更するような場合には閉じられているべき。
- #リスコフの原則:元々は「継承」の使い方の指南だったが、現在ではインターフェースと実装に関する設計の原則になっている。
- インターフェース分離と #オープン・クローズドの原則 はコンパイル型言語の方がよりわかりやすそう。コードを変更するとコンパイルが必要、というあたりも上手く言えそう。
コンポーネントの原則
- メモリが高価だった時代はプログラムの再配置が難しいため、プログラムをメモリ上のどこに配置するかはプログラマ自身が決めることだった(そういう命令を書く必要があった)。
- コンポーネントの凝集性に関する原則には、#再利用・リリース等価の原則、#閉鎖性共通の原則、#全再利用の原則 の3つ。この3つは全て100%達成するのではなく、バランスよく適用させる必要がある。
- #非循環依存関係の原則:コンポーネントの依存関係グラフに循環依存があってはならないというもの。循環依存があると、依存が複雑になって他のコンポーネントの影響を受けやすくなるのでよくない。
- #安定依存の原則:安定度の高い方向に依存するべきというもの。安定度が高い=他のコンポーネントからの依存(ファン・イン)が自身の依存(ファン・アウト)の数より多いということ。
- #安定・抽象度等価の原則:コンポーネントの抽象度はその安定度と同程度でなくてはならないというもの。安定度と抽象度はだいたい等しくなる(SAP)。
「優れたアーキテクチャは決定しない数を最大化するべき」
- DBを決定しなければ、設計しながらより適したDBを選択できるし、デバイスを決めなければどんなデバイスでも対応できるものを作れる、みたいな理屈。
- 決定を先送りにする=詳細を決めなかった部分は必然的に抽象になる。
- 切り離しを適切に行い独立したプログラムを設定することは大切だが、最初から100%行えるわけではないので常に最適な形を考える必要がある。
- 自然なのは「ドメインにはデータベースのことを知らせ、データベースがないとドメインルールが存在できない」という状態。つまり、先にデータベースを決めちゃって、ドメインルールがそっちに引っ張られちゃうから。
- データ構造(DTOなど)はメソッドの引数に使われがち。この定義は、関数を呼び出す側で行われる。
- 依存性は、データの流れ(例:文字列を読む→変換する→文字列を保存する)から切り離してレベル(上位レベル、下位レベル)と紐づけられる。この場合、下位から上位に依存する。例えば、エンティティ(ビジネスに対して不可欠なデータを指す)とユースケースでは、エンティティの方が上位。
#叫ぶアーキテクチャ
- アーキテクチャは、それを見た瞬間にどんなシステムなのかわかるようになっているべき。最初にパッと一言で言うとよい「これは会計システムだ」VS「これはRailsで作られてます」。
- フレームワークはあくまでツールで、これを前面に推すような形式になるべきではない。
- 図:#TheCleanArchitecture ↑改めて見るとこれ何言いたいことがめっちゃわかる。内部から外部のものを呼んではいけないし、外部は内部のものに依存している。
- 優れたアーキテクチャならテストもしやすい。というか、テストもちゃんとアーキテクチャとして設計されているはず。
- 各種開発の境界を超えるときは、DBのレコードそのまま渡したりせず、何かしらのオブジェクトやDTOに入れてやりとりをする。
- プロジェクトの開始時から「必要になる」と予測して開発の設計をするのは、YAGNIに違反しているという見方もある→必要が来て確実に必要になる部分があって、そういう部分については予測して適用していくことも必要。
- 100%最初から全部設計し切れるのではなく、常に様子を見ての都度設計で外れがないか意識するのが大切。
- main コンポーネントは、レイヤーとしては最下層なので、一番汚い仕事を引き受けることになる。
- アーキテクチャの境界は、サービスとサービスの中間にあるのではなく、1つのサービスを横断する形で存在する。コンポーネントに分割している。
- テストもシステムコンポーネントの一部として設計しなければ、保守が難しくなる。
詳細とフレームワーク
- 組み込み開発のボトルネックの話。ハードウェアとかファームウェアにソフトウェアが引っ張られがちだな、みたいな(ファームウェア:ハードウェアを動かすためのコード)。
- ファームウェアのコードをソフトウェアのコードに混ぜてはいけない。
- データベースは詳細なので下位に位置する。ウェブ(Webブラウザやアプリケーションを表示するソフトウェア)も詳細。詳細はアーキテクチャから切り離すべき。
- フレームワークも詳細と言える。アンクル・ボブはフレームワークに依存することをかなり嫌っている。フレームワークをソフトウェアのコアには使わず、プラグインの形で使える状態にするのが望ましいとのこと。現代のフレームワークにはあまり依存し過ぎない思想(フレームワークに依存しきるのは、できなくはないけど正規の使い方ではない場合が多い)。