クリーンアーキテクチャを読んだ

2021/08/19 02:19

読書


[クリーンアーキテクチャ](https://www.amazon.co.jp/Clean-Architecture-%E9%81%94%E4%BA%BA%E3%81%AB%E5%AD%A6%E3%81%B6%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%81%AE%E6%A7%8B%E9%80%A0%E3%81%A8%E8%A8%AD%E8%A8%88-Robert-C-Martin/dp/4048930656)を読んだのでメモとして残す。 ただし、所々省略していたりそもそもメモってない箇所もあるので悪しからず。 ## 一部 **1章** - ソフトウェアアーキテクチャの目的は「求められるシステムを構築・保守するために必要な人材を最小限に抑えること」 - 結果的に、クリーンなコードを書いた場合の最遅よりも、クリーンでないコードを書いた時の最速の方が遅くなっていく **2章** 省略 --- ## 二部 **3章** 3つのパラダイムは、それぞれ「何をすべきか」よりも「何をすべきでないか」、という意図を伝えている これらのパラダイムは、アーキテクチャの「コンポーネントの分離」「データ管理」「機能」という関心事に対応している - 構造化プログラミング - オブジェクト指向プログラミング - 関数型プログラミング **4章(構造化プログラミング)** - 反証可能(テストすることが可能)なプログラミングの単位を作成する能力が重要 - テストはバグが存在しないことは証明できず、バグが存在してることを示すものである - **機能分割** - プログラムを再帰的に分割して、証明可能な小さな機能する必要がある - 証明可能な小さな機能が正しくないことを、テストを使って証明する **5章(オブジェクト指向(OO)プログラミング)** OOとは:ポリモーフィズムを使用することで、システムにある全てのコードの依存関係を絶対的に制御する能力 --- ## 三部 SOLID原則について 目的 - 以下のような性質を持つ中間レベルのソフトウェア構造を作ること - 変更に強いこと - 理解しやすいこと - コンポーネントの基盤として、多くのソフトウェアシステムで利用できること - 中間レベル:コードレベルよりも上に適用されるもので、モジュールやコンポーネントで使うソフトウェア構造の定義に役立つ - SOLID原則 - 単一責任の原則(SRP):クラスに任せる責任は一つのみにすること - オープン・クローズドの原則(OCP):ソフトウェアのエンティティ(クラス、モジュール、関数)は拡張に対して開き、修正に対して閉じていなければならない - リスコフの置換原則(LSP):スーパークラスは、そのサブクラスで代用可能でなければならない - 要はサブクラスの型を知る必要がないようにし、サブクラス側にoverride を強制するようにしろということ - インターフェース分離の原則(ISP):クライアントが利用しないメソッドへの依存を強制してはならない - 依存性逆転の原則(DIP) - 高水準モジュールは低水準モジュールに依存してはならない。両者は、抽象化に依存するべきである。 - 抽象化は、詳細に依存してはならない。詳細は、抽象化に依存するべきである。 **7章(**単一責任の原則**)** リファクタリングとかでいう「どのモジュールも一つのことのみ行うべき」という原則とは異なる(これはリファクタリングの方の原則) **8章**(オープンクローズドの原則) - 拡張に対して開いていて、修正に対して閉じていないといけない - ちょっとした修正のために大量の書き換えが発生しないようにするのが重要 - 上位コンポーネントは、下位コンポーネントの修正に対して無関心であるべき **9章**(LSP: リスコフの置換原則) - スーパークラスとサブクラスは置換可能でないといけない - サブクラスの入力のパターンは、基本クラスの入力のパターンよりも緩い - 厳しくなってしまうと、利用者側はサブクラスを使う際に厳密な入力(引数)が求められてしまうことになる - サブクラスの出力のパターンは、基本クラスの入力のパターンよりも厳しい - 緩くなってしまうと、利用者がサブクラスの挙動について詳細を知る必要が出てきてしまう 参考: [https://qiita.com/yuki153/items/142d0d7a556cab787fad](https://qiita.com/yuki153/items/142d0d7a556cab787fad) [https://qiita.com/yuu341/items/1a45048950f3b5b76bdc](https://qiita.com/yuu341/items/1a45048950f3b5b76bdc) **10章**(ISP:インターフェース分離の原則) - クライアントは使用しないインターフェースの実装を強制されるべきではない - インターフェース実装時は、それぞれのクラスに必要な箇所のみを抽出したインターフェースを作れ、ということ 参考: [https://zenn.dev/chida/articles/882aad07effa5c](https://zenn.dev/chida/articles/882aad07effa5c) **11章**(依存関係逆転の原則) ソフトウェアの変更時は、具象の変更で収まるようにし、抽象の変更は極力しないようにするのが原則 - 変化しやすい具象クラスを参照しない - 代わりに抽象インターフェースを参照するようにすること(変更が少ないため、何らかの変更に巻き込まれて自分も修正しないといけない、ということが減る) - 変化しやすい具象クラスを継承しない - 具象関数をオーバーライドしない - 変化しやすい具象を名指しで参照しない 参考: [https://techracho.bpsinc.jp/hachi8833/2019_05_09/62314](https://techracho.bpsinc.jp/hachi8833/2019_05_09/62314) rubyの例あり [https://madogiwa0124.hatenablog.com/entry/2019/11/08/211648](https://madogiwa0124.hatenablog.com/entry/2019/11/08/211648) **12章**(コンポーネント) コンポーネントとはデプロイの単位→rubyならgemファイル インタプリタ型言語ならソースファイル **13章**(コンポーネントの凝集性) コンポーネントの凝集性に関わる3つの原則。 アーキテクトに対して以下の3つの原則をバランスよく取り入れることが重要 - 再利用・リソース投下の原則(REP)→再利用性のためのグループ化 - コンポーネントを再利用するには、コンポーネントのリリース単位で行う - 再利用の単位とリリースの単位は同じになる - 閉鎖性共通の原則(CCP)→保守性のためのグループ化 - 同じ理由、同じタイミングで変更されるクラスをコンポーネントにまとめること。 - 単一責任の原則の言い換え→コンポーネントを変更する理由が複数あるべきではない - 全再利用の原則(CRP)→不要なリリース作業を減らすための分割 - 1つのクラスのみを再利用することはほぼなく、複数のクラスと組み合わせて使われることが大半のため、そういったクラス群は1つのコンポーネントにまとめる 参考: コンポーネントに関する6つの原則(13・14章合わせて) [https://qiita.com/NagaokaKenichi/items/65c149ba92580fce5be2#全再利用の原則crpthe-common-reuse-principle](https://qiita.com/NagaokaKenichi/items/65c149ba92580fce5be2#%E5%85%A8%E5%86%8D%E5%88%A9%E7%94%A8%E3%81%AE%E5%8E%9F%E5%89%87crpthe-common-reuse-principle) **14章**(コンポーネントの結合) - 非循環依存関係の原則(ADP) - コンポーネントの依存構造に循環依存があってはいけない - 依存関係のグラフが有向非循環グラフ(循環構造が存在しない有向グラフ)で表されているか - 安定依存の原則(SDP) - 安定度の高いコンポーネントに依存するという原則 - 多数のコンポーネントから依存されたコンポーネントは変更しづらい、そのためこういったコンポーネントは安定度が高いと考えらえれる - 基本的には抽象度の高いレイヤーに依存するべきなので、安定度の高い=抽象度の高いと言い換えられる - 安定度・抽象度評価の原則(SAP) - コンポーネントの抽象度は、その安定度と同程度でなければならない - 安定度の高いコンポーネントは抽象度も高くあるべきで、安定度の高さが拡張の妨げになってはいけない - 安定度が低いことによってその内部の具体的なコードが変更しやすくなるため、安定度の低いコンポーネントはより具体的であるべき --- ## 五部 **15章(アーキテクチャとは)** アーキテクチャの形状の目的は、「できる限り長い期間、できるだけ多くの選択肢を残せるようにすること」 - 残すべき選択肢とは、重要ではない詳細のこと - **アーキテクトは、方針・詳細を区別して、方針が詳細を把握・依存することないようにする必要がある** - 方針:重要なもの、優先度高 - 詳細:重要でないもの、優先度低 - 詳細は決定を延期・留保することができる その他 - 早い段階から**デプロイ周り**の戦略を考える必要がある - アーキテクチャが優れていれば、自ずと運用方法は明確になる --- **16章(独立性)** 省略 **17章(バウンダリー)** ソフトウェアアーキテクチャに境界線を引くために、まずシステムをコンポーネントに分割する。この中のいくつかのコンポーネントがコアのビジネスルールとなる。 個人的に、DBの構成等はビジネスルールに密接に結びつくと考えていたので、DBの決定は遅らせることができる、というのは目から鱗 **18章(境界の解剖学)〜21章まで省略** **22章(クリーンアーキテクチャ)** アーキテクチャの目的 = 関心事の分離 クリーンアーキテクチャが生み出すシステムについての特性 - フレームワーク非依存 - アーキテクチャはソフトウェアのライブラリに依存しない - そのため、フレームワークに依存せず、単なるツールとして利用できる - テスト可能 - ビジネスルールはUI、データベース、webサーバ、その他の外部要素がなくてもテスト可能 - UI非依存 - ビジネスルールを変更することなく、ウェブUIをコンソールUIに置き換えることができる - データベース非依存 - どのデータベースにも置き換えることが可能 - 外部エージェント非依存 - ビジネスルールは、外界のインターフェイスについて何も知らなくていい - 下図について 円の外側は仕組み、内側は方針 アーキテクチャを動作させる重要なルールは「依存性のルール」 - ソースコードの依存性は、内側(上位レベルの方針)だけに向かっていなければならない - つまり、円の内側は外側について何も知らなくていい - エンティティ - 企業全体の最重要ビジネスルールをカプセル化したもの - ページのナビゲーションやセキュリティに変更があったとしても、エンティティが影響を受けることはない - ユースケース - アプリケーション固有のビジネスルールが含まれている - ソフトウェアが何ができるのか、を示す - ドメイン駆動設計でいうところのアプリケーションサービス - インターフェースアダプター - 入力、永続化、表示を担当するオブジェクトが所属する - 永続化とはデータの保存、表示は結果の表示を表す - 一般的な MVC フレームワークや単体テストクラスなどはこのレイヤーに所属する - フレームワークとドライバ - データベース操作オブジェクトやウェブフレームワークなど - このレイヤーではあまりコードは書かない - 境界線を越えるには - 図の右下がそれを表している - 例:ユースケースから円の内側にあるインターフェースを呼び出すようにして円の外側にあるプレゼンターを呼び出すなどする ![CleanArcitecture.png](https://drive.google.com/uc?export=view&id=1LQkqHUhAgz7qAt4B9F-bPsYjKu_kgJci) - 参考: [https://gist.github.com/mpppk/609d592f25cab9312654b39f1b357c60](https://www.notion.so/609d592f25cab9312654b39f1b357c60) [https://qiita.com/nrslib/items/a5f902c4defc83bd46b8#enterprise-business-rules](https://qiita.com/nrslib/items/a5f902c4defc83bd46b8#enterprise-business-rules) [https://www.slideshare.net/AtsushiNakamura4/clean-architecture-release](https://www.slideshare.net/AtsushiNakamura4/clean-architecture-release)

リファクタリング(第二版)を読んでいる

2021/01/20 18:21

読書


<h3>第一章</h3> <p><b><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%EA%A5%D5%A5%A1%A5%AF%A5%BF%A5%EA%A5%F3%A5%B0">リファクタリング</a>全体</b></p> <ul> <li><p>機能追加がしにくい場合は、機能追加がしやすい構造になるように<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%EA%A5%D5%A5%A1%A5%AF%A5%BF%A5%EA%A5%F3%A5%B0">リファクタリング</a>してから機能を追加すること</p></li> <li><p><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%EA%A5%D5%A5%A1%A5%AF%A5%BF%A5%EA%A5%F3%A5%B0">リファクタリング</a>する前に、対象のコードの入出力結果が変更されてないかを確認するテスト群を用意する</p> <ul> <li>リファクタは、各種テストを通過するかを細かくチェックしながら進行する</li> <li>こうすることで、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%EA%A5%D5%A5%A1%A5%AF%A5%BF%A5%EA%A5%F3%A5%B0">リファクタリング</a>に失敗しても直前の状態に戻れる</li> </ul> </li> <li><p>ローカル変数の数を減らす方向で考える</p></li> <li></li> </ul> <p><b>関数の抽出</b></p> <ul> <li>意味のある塊については関数に抜き出す <ul> <li>抽出した際にスコープ外となる変数は引数として要求する</li> <li>関数内で変化する値はその関数の戻り値とする</li> </ul> </li> </ul> <h3>第二章</h3>