Clean Architecture
第3章 パラダイムの概要
構造化プログラミング:直接的な制御の移行に規律を課す → goto文を削除
オブジェクト指向プログラミング:間接的な制御の移行に規律を課す → 関数ポインタを削除
関数型プログラミング:代入に規律を課す → 代入を削除
プログラミングパラダイムはプログラマから能力を削除している
何をすべきかではなく,何をすべきでないかを規定
第4章 構造化プログラミング
プログラムに定理のユークリッドの階層を構築することを目的に「分割統治」を阻害する無秩序なgoto文をやめ,goto文をうまく使ったif/then/elseなどの「選択」,do/whileといった「反復」の制御構造のみを使用する.それにより証明可能な単位に分割できるのではないかというアプローチから始まった.2つの制御構造に順序処理を組み合わせた3つ「順序」「選択」「反復」は幸いにあらゆるプログラムの構成要素たりうることが特定されていた.
定理のユークリッドの階層の構築は達成されなかったが,goto文を廃止し,制御構造を導入することで機能分割が可能となり,TDDとして反証可能なプログラミングが可能となった.TDDは数学(証明可能)よりも科学(反証可能)に類似している.
第5章 オブジェクト指向プログラミング
OOPとは何か?
よくカプセル化・継承・ポリモーフィズムがあげられるがそれら自身が全てではない.c言語において既にそれらは実現可能であった.
カプセル化: ヘッダファイルで実現可能
継承: 型のキャストで実現可能
ポリモーフィズム: 関数ポインタをメンバーとした構造体を利用で実現可能
ポリモーフィズムを利用したプラグインアーキテクチャはIOデバイスの非依存性サポートには使われたが,個人のプログラムには採用されなかった.関数ポインタを使うのは危険だったからだ.OOは関数ポインタを秘匿し,プラグインアーキテクチャを圧倒的に使いやすくした.
OOの面白い性質として,依存関係の逆転がある.従来のソフトウェアは依存関係と制御の流れが一致していた.OOではインターフェースに依存することで依存関係(継承関係)が制御の方向と逆転する
https://gyazo.com/94a4ad4d7de0e777da0033bd20cf2b19
https://gyazo.com/8f352662b3bf6fb690052286697d7582
ここからOOの最も重要な点は「ポリモーフィズムを使用することで,システムにあるすべてのソースコードの依存関係を絶対的に制御する能力」である.
第6章 関数型プログラミング
競合状態・デッドロック状態・並行更新の問題の原因が全て可変変数にある.
全てを不変にするのは難しい→可変部分と不変部分に分ける
並行更新・競合状態
→トランザクショナルメモリ 処理の始まりと終わりで参照部分を比較し,異なっていればやり直し
But. 従属変数が複数になると並行更新やデッドロックの問題発生
イベントソーシング: 十分な記憶容量と処理能力があれば,変更可能な状態を持つ必要がない
例: Bitcoin トランザクションモデル
第7章 SRP: 単一責任の法則
Single Responsibility Principle
モジュールはたったひとつのアクターに対して責務を負うべきである。
↓違反例とその解決例(Facade Pattern)
https://gyazo.com/95edb03f558b530ea55f2f9a5c212c04
https://gyazo.com/2f6100697df2655c83c7cec481c4aef9
コンポーネントレベルでの同様な原則は閉鎖性共通の原則(CCP)と呼ばれる.
第8章 OCP: オープン・クローズドの法則
ソフトウェアの構成要素は拡張に対しては開いていて、修正に対して閉じていなければならない
変更されやすいもの → 変更されにくいもの
下位 → 上位 で参照させる
インターフェースを使って依存関係を制御する.
コンポーネント同士は一方向のみでの参照
→ 下位レベルの変更に強くなる
https://gyazo.com/6aae7fe131f40729db2e2547d14efc46
第9章 LSP: リスコフの置換原則
あるクラスのメソッドを利用している処理は,その子クラスや孫クラスの同じメソッドでも同様の処理が行えるように.
ポリモーフィズムを考えれば当然
第10章 ISP: インターフェイス分離の法則
違反とその解決例
https://gyazo.com/65c06c1ac19a150250ead7f40ad32a2f
https://gyazo.com/dfe5a776d2069bed7776709c1cd161b1
分離されていなければ,無駄な依存関係により,関係のない部分の修正に関しても再コンパイル・デプロイが必要になりうる.
動的型付けオブジェクト指向の利点
Javaのような静的型付け言語は、importやuseやincludeといった宣言をプログラマに強要する。ソースコードに書かれたこれらの宣言がソースコードの依存性を作り出し、そのために再コンパイルと再デプロイが必要になってしまう。RubyやPythonのような動的型付け言語では、こうした宣言はソースコードには存在せず、実行時に推論される。つまり、再コンパイルや再デプロイを強制するソースコードの依存性は存在しないのだ。このあたりが、静的型付け言語よりも動的型付け言語のほうが柔軟で疎結合なシステムを作れる最大の理由である。
第11章 DIP: 依存関係逆転の法則
具象ではなく抽象のみを参照.ゆるく言えば,より変化しにくい部分を参照するようにする
変化しやすい具象クラスを参照・継承しない
具象関数をオーバーライドしない
変化しやすい具象を名指しで参照しない
Abstract Factoryパターンを使って実際での住み分けを行う
https://gyazo.com/191df1ea2aaeaa0a278e4f94edacb17b
第13章 コンポーネントの凝集性
再利用・リリース等価の原則(REP)
「コンポーネントを再利用するには、コンポーネントのリリース単位で行う」 (再利用するコンポーネントの互換性確認のため)
閉鎖性共通の原則(CCP)
「同じ理由/タイミングで変更されるクラスを同じコンポーネントにまとめる,変更の理由やタイミングが異なるクラスは別のコンポーネントに分ける」
Single Responsibility Principleのコンポーネント版
コンポーネントを変更する理由が複数あるべきでは無い
全再利用の原則(CRP)
「コンポーネントのユーザーに対して実際には使わない者への依存を強要してはいけない」
Interface Segregation Principle
CCP, CRPから得られる一つのコンポーネントにまとめるべきクラスやモジュールの判断
同じタイミングで変更されることが多いクラス
変更の種類が似ているクラス
一緒に用いられることが多いクラス
<-> コンポーネントの,あるクラスだけを使う場面が想定される時,それは切り離されているべき
コンポーネントを大きくする REP, CCP <-> 小さくするCRP
自身のソフトウェアの落としどころを見つけるのがアーキテクトの腕の見せ所 (プロジェクトの初期段階は右側に位置する傾向)
https://gyazo.com/4a474723b4cacf2466010aa4d63b7759
第14章 コンポーネントの結合
大勢の開発者が同じソースコードを変更するとき,誰かの変更が誰かの変更を呼び,いつまでもソフトウェアが完成しない状況を回避する2つの解決策
週次ビルド
中規模プロジェクトに適用 (大規模になるほどワークしなくなる)
週の最初の4日間: 他の開発者が何をどう変更したかを一切無視する
金曜日: 全員の変更を統合してシステムをビルド
非循環依存関係の原則 (ADP)
「コンポーネントの依存グラフに循環依存があってはいけない」
コンポーネントごとにリリース管理を行う → コンポーネントの依存管理が大切 → 循環依存をなくす
循環依存のコンポーネントが発生すると,そこが巨大なコンポーネントのようになってしまう
https://gyazo.com/d2cfff4007a496172ccf676959fd53f9
解決方法
DIPを適用する
https://gyazo.com/0948b5234aa604630150e0b360e8b123
両方が依存する新しいコンポーネントを作る
https://gyazo.com/f5fe148d68e6577098e3200348a8ef4c
要件の変更 → コンポーネントの構造の変更
トップダウンにコンポーネントの構造を設計するのは不可能
コンポーネント図: ビルド可能性・保守性を見るための地図 → コンポーネントの依存構造はシステムの論理設計に合わせて育てていく
理解できていないところ
第3章
ALGOL言語の関数呼び出しのスタックフレームをヒープに移動できること、そのことにより関数から戻ってきたあとでも関数で宣言したローカル変数が存在し続けられることに気づいた.
第12章
ローダとリンカが微妙に理解しきれていない