kanachi-blog

notionでの公開記事をastro-notion-blogを使って公開するよ

【Clean Architecture 第Ⅳ部】コンポーネントの原則

目次

コンポーネント

コンポーネントとは?

デプロイの単位となる最小限のまとまりのこと

コンポーネントの簡単な歴史
  1. 昔はプログラムをメモリ上のどの場所にどのように配置するかはプログラマが指定する必要があった。その当時は、プログラムはリロケータブルでなかった。ライブラリ関数はアプリケーションに組み込んで、ひとつのプログラムとしてコンパイルしていた。その結果、コンパイラの処理時間は増えていた。
  2. それを短縮するために、あらかじめライブラリ関数をコンパイルして、そのバイナリをメモリにロードしていた。ただし、アプリケーションに変更があるたびにメモリにアプリケーションとライブラリ関数が断片化されていた。
  3. リロケータビリティ(再配置可能性)の登場

    コンパイラが作ったバイナリコードを修正して、スマートローダがそのコードをメモリの任意の場所に適切に配置できるようにした

    ここから発展して、リロケータブルなバイナリのメタデータとして関数名を参照できるようになり、外部参照、外部定義、リンクローダができるようになった。

    💡
    リンクローダとは

    リンクローダは、名前からも推測できるように、リンキングとローディングの両方の機能を持つプログラムやツールを指す。

    1. リンキング: リンキングは、複数のオブジェクトファイルやライブラリを一つの実行可能ファイルに結合するプロセスです。この際、外部参照と外部定義の解決が行われ、各オブジェクトファイルやライブラリのコードやデータが適切に結合されます。
    2. ローディング: ローディングは、実行可能ファイルをメモリに読み込むプロセスです。こうすることで、プログラムがCPUによって実行される準備が整います。
  4. リンカの登場

    リンクローダはプログラムが、巨大化するにつれて、処理時間が長くなる問題があった。なぜなら、外部参照するライブラリが膨大である時に、外部参照の解決やオブジェクトファイルの結合、再配置に時間がかかっていた。

    結局、ロードとリンクは別のフェーズに分離され、リンクの処理をリンカと呼ばれる別のアプリケーションに切り出された。

  5. マーフィーの法則vsムーアの法則

    マーフィーの法則のようにプログラムは、コンパイルとリンクに使える時間を使い切るまで肥大化する。と思われていたが、集積回路のトランジスタ数は約2年ごとに倍増するというムーアの法則により、そのリンカの処理速度に対する問題はなくなった。

コンポーネントの凝集性

再利用・リリース等価の原則(REP)
  • 再利用の単位とリリースの単位は等価にならなければならない
    • なぜならリリースの単位でないと再利用ができないから
  • コンポーネントを形成するクラスやモジュールは凝集性のあつグループでなければならない
  • コンポーネントを形成するクラスやモジュールはまとめてリリース可能でなければならない
閉鎖性共通の原則(CCP)
  • 同じ理由、同じタイミングで変更されるクラスをコンポーネントにまとめる
    • 単一責任の原則のコンポーネント版
    • 変更の理由が異なるクラスは別コンポーネントに分ける
全再利用の原則(CRP)
  • コンポーネントのユーザーに対して実際には使わないものへの依存を強要してはいけない
    • インターフェース分離の原則を一般化したもの

この3つの原則は相反するところがあるので、開発の状況にも応じて適度にバランスを考慮して構成を考える。

コンポーネントの結合

非循環依存関係の原則(ADP)
  • コンポーネントの依存グラフに循環依存があってはいけない
    • コンポーネント図の依存関係は有向非循環グラフであるべき

コンポーネントの構造は要件の変更に伴って変化する。

なので常に非循環であるように注視する必要がある。

したがって、コンポーネントの構造をプリジェクトの開始時にトップダウンで設計するのは不可能。

システムの論理設計に合わせて変化しながら育てていくのが重要

安定依存の原則(SDP)
  • 安定度の高い方向に依存すること
  • 変更しやすい意図を持ったコンポーネントは依存されないように設計する
安定度の指標
  • ファン・イン:依存入力数。コンポーネント内のクラスに依存している外部のコンポーネント数を表す。
  • ファン・アウト:依存出力数。コンポーネント内にある、外部のコンポーネントに依存しているクラスの数を表す。
  • I(Instability):不安定さ。I = ファンアウト/(ファン・アウト + ファン・イン)
    • 0が最も安定
    • 1が最も不安定
安定度・抽象度等価の原則(SAP)
  • コンポーネントの抽象度は、その安定度と同程度でなければいけない
    • 安定度の高いコンポーネントは抽象度も高くあるべき

理由

  • 上位レベルの方針は安定度が高くされるべき
  • そうすると、方針を表現しているソースコードは変更しづらくなり、柔軟性に欠けるものになってしまう
  • 抽象クラスやインターフェースを用いると拡張がしやすくなる
抽象度の計測
  • Nc:コンポーネント内のクラスの総数
  • Na:コンポーネント内の抽象くらすとインターフェースの総数
  • A:抽象度、A = Na / Nc
    • 0であれば抽象クラスやインターフェースが存在しない
    • 1であれば抽象クラスやインターフェースしかない
抽象度と安定度の関係

できるだけ、コンポーネントは主系列上に載せるか、そこに近づけるようにする