人柄は良いがビギナーレベル

育児とプログラミングに追われる毎日

Clean Architecture 第12章 コンポーネント

この記事について

覚え書き

コンポーネントとは、デプロイの単位のことである。

動的にリンクされたファイルを実行時にプラグインできる。これが我々のアーキテクチャにおけるソフトウェアコンポーネントだ。

まとめ

  • デプロイ単位を意識してコンポーネントを作成していきたい
  • デプロイ単位は差し替え可能な単位であることに注意したい

Clean Architecture 第11章 DIP:依存関係逆転の原則

この記事について

覚え書き

ソースコードの依存関係が(具象ではなく)抽象だけを参照しているもの。それが、最も柔軟なシステムである。

このルールを絶対のものとして守り続けるのは明らかに現実的ではない。 ... 依存したくないのは、システム内の変化しやすい具象要素だ。

  1. 変化しやすい要素(ビジネスルールの詳細、実装の詳細)に依存しないように具象を参照せずに抽象を参照するようにする
  2. 抽象を参照することで具象を置換しやすくなり柔軟なシステムになる

抽象コンポーネントにはすべての上位レベルのビジネスルールが含まれる。具象コンポーネントには、これらのビジネスルールが操作する実装の詳細が含まれる。

  1. 下記を意識することで利用しやすい抽象、変更しやすい具象を作成していきたい
  2. 抽象にはビジネスルールを記載する
  3. 具象にはビジネスルールの操作(実装の詳細)を記載する

まとめ

  • 利用しやすい、安定した抽象(インターフェイス)を設計することで詳細を置換しやすくなるように設計していきたい
  • テストを書く際には抽象を利用して、テストをパスするように具象を実装する開発手順でやってみて「抽象にはビジネスルール」「具象には実装の詳細」を実現してみたい

Clean Architecture 第10章 ISP:インターフェイス分離の原則

この記事について

覚え書き

インターフェイス分離の原則(ISP)は言語の問題であり、アーキテクチャの問題ではないと考える人もいるかもしれない

必要としないモジュールに依存することは一般的に有害とされる。ソースコードの依存関係に置いては、再コンパイルや再デプロイを強制されるので明らかに有害であることがわかる。だがさらに上位のアーキテクチャレベルにおいても有害なのだ

  1. モジュールレベルではインターフェイス分離の原則に則ることで不要なコンパイルやデプロイを軽減することができる(静的言語に限定された話し)
  2. アーキテクチャレベルでのインターフェイス分離の原則のメリットは?
    1. 例> アプリケーションがフレームワークに依存しており、フレームワークがデータベースに依存している場合、データベースが更新されたらフレームワーク、アプリケーションを更新しなければならない
    2. フレームワークがデータベースに依存していることで利用していないデータベースの機能の更新でもフレームワークを更新しなければならない
    3. フレームワークがデータベースに依存していなければデータベースの更新だけで済むはず

まとめ

  • モジュール間のみではなくフレームワークやツール間での影響についても意識できるようにしたい
  • 変更が発生しないのであれば依存させたり、変更が頻発するのであればインターフェイスを利用したりして疎結合にするなど状況によって使い分けられるようになりたい

Clean Architecture 第9章 LSP:リスコフの置換原則

この記事について

覚え書き

アーキテクチャの観点からリスコフの置換原則(LSP)を理解するにはこの原則に違反した時にシステムのアーキテクチャに何が起こるのかを考えてみるのが一番だ。

RESTfulサービスのインターフェイスが置換可能になっていないせいで、アーキテクトは複雑な仕組みを追加することになってしまった。

  1. 違反の例としてRESTful APIのパラメータ名がユーザーごとに違った場合を例に挙げている
  2. 1つのRESTful APIを1つのサービスで実装しているため、ユーザーごとのパラメータ取得処理を作るとアーキテクトが複雑になってしまう
  3. 1つのRESTful APIに応答するサービスをユーザーごとに作成すればアーキテクトが複雑にならない
  4. この例ではパラメータ名の切り替えなのでRESTful APIに応答するサービスを作成するのと、データベースにURIをキーにする設定を登録するのでは差異がないように感じる
    1. サービスを分けることによってユーザーごとの差分には対応しやすくなる
    2. SRP:単一責任の原則に関連して一つのユーザーに対応するためシンプルになる(複雑なアーキテクトにならない)

今ではインターフェイスと実装に関するソフトウェア設計の原則になっている。

対象となるインターフェイスにはさまざまな形式がある。Java風のインターフェイスは、それを実装したクラスをいくつも作れる。Rubyであれば、同じメソッドシグネチャを共有するクラスをいくつも作れる。ウェブであれば、同じRESTインターフェイスに応答するサービスをいくつも作れる。

  1. リスコフの置換原則はクラスとインターフェイスに限った話ではなく、言語、アプリケーションの種類に関係なくユーザーとの接点で発生するもの
  2. ウェブの話は意識できていなかったので普段から気付けるようにしたい

まとめ

  • ユーザー(人、サービス、クラス)に対するインターフェイスではIFで分岐せず、置換可能にすることで複雑なアーキテクト(実装)にならないようにしたい

Clean Architecture 第8章 OCP:オープン・クローズドの原則

この記事について

覚え書き

言い換えれば、ソフトウェアの振る舞いは、既存の成果物を変更せず拡張できるようにすべきである、ということだ。

アーキテクチャは、いつどのような理由でどのように変更するかを考えて機能を分割する。そして、分割した機能をコンポーネントの階層構造にまとめる。上位レベルにあるコンポーネントは、下位レベルのコンポーネントが変更されたとしても、変更する必要はない。

  1. SRP:単一責任の原則により機能を変更する理由を一つのアクターに対する責務に限定することで変更機能を最小限にとどめる
  2. 機能の中身を役割ごとにコンポーネントを分ける
  3. コンポーネントDIP:依存関係逆転の原則を利用してビジネスロジックが詳細の処理(ControllerやPresenter、Database)に影響されないようにする
    1. 詳細の処理がビジネスロジックに対して依存する=変更した時に変更したくないものに依存する(依存されたコンポーネントは変更の影響を受けない)
    2. 詳細の処理がビジネスロジックに対して依存するのはビジネスロジックインターフェイス
    3. インターフェイスに依存することでビジネスロジックを変更したときに詳細の処理に変更が発生しないようにする

まとめ

  • SRP:単一責任の原則により仕様変更が発生しても一つの機能にしか影響が出ないようにした上で、DIP:依存関係逆転の原則により実装の変更が発生しても他のコンポーネントに影響が出ないようにするからこそOCP:オープン・クローズドの原則を実践できるのかなと感じた

Clean Architecture 第7章 SRP:単一責任の原則

この記事について

覚え書き

SOLID原則の単一責任の原則とは別ものである。

  • SOLID原則の単一責任の原則は「ひとつの関数はたったひとつのことだけを行うべき」ではない。
    • この原則はSOLID原則ではないだけで原則として存在する
  • モジュールを変更する理由はたった一つだけであるべきである。

モジュールはたったひとつのアクターに対して責務を負うべきである。

  • モジュールに複数のアクターに対する処理が存在すると同じ動詞でも計算方法が異なる変更が発生しやすい
    • 異なるアクターへのバグが発生しやすくなる
    • 似たような長い名前のメソッドが増える

アクターの異なるコードは分割するべきという原則だ。

 

これらの問題にはさまざまな解決策がある。いずれも関数を別のクラスに移動するというものだ。

  • アクターの異なるメソッドをそれぞれアクターごとのクラスに移動する
    • アクターごとのクラスを作成することで修正時の影響を小さく抑える
  • アクターごとにクラスがあるとビジネスルールと実態が乖離してしまう場合はFacadeパターンを利用する
    • ビジネスルールのクラスからアクターのメソッドを呼び出すようにする

まとめ

  • クラスはアクターごとに作成して動作に一貫性を持たせられるようにしようと思った。
  • アクターが複数存在するビジネスルールなどはFacadeパターンを利用して変更の単位は、呼び出し先のクラスで抑えられるように気をつけようと思った。

Clean Architecture 第6章 関数型プログラミング

この記事について

覚え書き

競合状態、デッドロック状態、並行更新の問題の原因が、すべて可変変数にあるからだ

  • 並列処理を容易に行うためには不変であるべき

不変性に関する最も一般的な妥協となるのは、アプリケーションまたはアプリケーションのサービスを「可変コンポーネント」と「不変コンポーネント」に分離することである

  • 全てを不変にすることはできなくても可変と不変を分離する努力はしようと思った

まとめ

  • 不変にすることで並列処理における悩みが減ることがわかった
  • スコープが広い変数は並行更新などのリスクが大きくなるため、できるだけ小さいスコープで変数を利用することが並列処理の問題を発生させないコツだと感じた