『クリーンアーキテクチャ』再読(6):境界

Tommy Cheese | · 読了目安:4 分

境界とは何か

ソフトウェアアーキテクチャの設計は、それ自体が境界を引く技術です。

境界の役割は、ソフトウェアをさまざまな要素に分け、境界の両側の依存関係を制約することです。プロジェクトの初期に境界を引くと、一部の意思決定をできるだけ先送りし、将来その決定がシステムの中核となる業務ロジックを妨げないようにできます。境界を引くことは、アーキテクチャ内の不要な結合を減らす、またはなくすことにも役立ちます。システムの結合、とりわけ早すぎる未熟な意思決定による結合は、最も人的資源を消費する部分です。採用するフレームワークやデータベースなどの詳細は、そのような決定の例であり、後回しにすべきです。

では、境界はどのように引けばよいのでしょうか。次の基本原則に従えます:

  • 境界は、互いに無関係なものの間に引きます。たとえばGUIと業務ロジックです。入出力であるGUIは業務ロジックにとって本質的ではなく、業務ロジックにはさまざまなGUI実装を組み合わせられます。
  • 境界線は、システムの変更の軸に沿って引きます。境界の両側にあるコンポーネントは、異なる理由で、異なる頻度で変化するべきです。その軸を判断する指針には、モジュール/クラスレベルのSRPとコンポーネントレベルのCCPがあります。

境界を引くことの重要性と、その考え方がわかったので、次は実際に境界を引く基本的な手順を考えます:

  1. まずシステムをコンポーネントに分割します。一方は中核となる業務ロジックのコンポーネント、もう一方は中核業務とは無関係ですが、必要な機能を提供するプラグインです。
  2. ソースコードを変更し、中核ではないコンポーネントが、中核の業務ロジックのコンポーネントに依存するようにします。

境界を引くことは、依存性逆転の原則と安定度・抽象度の原則を具体的に適用することです。依存関係の矢印は、低レベルの具象実装から高レベルの抽象へ向かうべきです。

境界を詳しく見る

システムのアーキテクチャは、一連のソフトウェアコンポーネントと、それらの間にある境界によって定義されます

境界にはさまざまな形があります。この章では、境界を越える呼び出しを例に、その構造を考えます。

実行時の境界を越える呼び出しとは、境界線の片側にある関数が、もう片側の関数を呼び出し、同時にデータを渡すことです。これを適切に構成するには、ソースコードの依存関係を適切に管理する必要があります。管理しなければ、一つのモジュールのソースコードが変わるだけで、他のモジュールのソースコードも変更や再コンパイルが必要になり、再デプロイしなければならないことがあります。境界を明確にすることは、このような事態を減らすのに役立ちます。

境界を越える呼び出しには、ソースコードレベル、デプロイレベル、サービスレベル、そして物理的な境界という分類があります。

ソースコードレベルの境界を越える呼び出し

ソースコードレベルの境界を越える呼び出しは、モノリシックアーキテクチャに見られます。この種のアーキテクチャでは、一般に何らかの動的なポリモーフィズムを使って内部の依存関係を管理する必要があります。

最も単純なのは、低レベルのクライアントが高レベルのサービス関数を呼び出す形です。この依存関係の向きは、実行時とコンパイル時で一致し、どちらも低レベルのコンポーネントから高レベルのコンポーネントへ向かいます。

(元の図は現在ありません)

一方、高レベルのコンポーネントにあるクライアントが、低レベルのコンポーネントにあるサービスを呼び出す場合は、動的なポリモーフィズムを使って依存関係を逆転させる必要があります。図のServiceインターフェースは、ある種のSPIです。

(元の図は現在ありません)

デプロイレベルの境界を越える呼び出し

デプロイレベルの境界を越える呼び出しでは、デプロイ可能な各単位を、扱いやすいファイル形式にまとめます。この点を除けば、デプロイレベルで分離されたコンポーネントは、モノリシックな構造とほぼ同じです。

デプロイレベルの境界を越える呼び出しには、物理的な境界も関わります。別々にデプロイされた単位が通信するには、物理的な境界を越える必要があるためです。一般的な物理的境界には、動的リンクライブラリ、スレッド、ローカルプロセスなどがあります。

サービスレベルの境界を越える呼び出し

サービスは、システムアーキテクチャで最も強い境界の形です。一つのサービスは一つのプロセスです。アーキテクチャの境界を引く際には、通信回数をできるだけ抑える必要があります。このレベルの通信は、大きな遅延に対応できなければなりません。それ以外は、ローカルプロセスと同じルールをサービスレベルにも適用できます。つまり、低レベルのサービスを高レベルのサービスの「プラグイン」にします。

comments powered by Disqus