Prism Architectureのコミュニケーションパターン
読書時間: 約15分
はじめに
レイヤー間のコミュニケーションは、あらゆるアーキテクチャの重要な側面です。Prism Architectureは、関心の分離を保ちながら実用的なデータフローを可能にする、クリーンで保守性の高いコミュニケーションを確保するための特定のパターンを使用しています。このドキュメントでは、Prism Architecture全体で使用される主要なコミュニケーションパターンについて説明します。
基本的なコミュニケーション原則
Prism Architectureは、レイヤー間のコミュニケーションについていくつかのコア原則に従っています:
インテントベースのコミュニケーション
直接的なメソッド呼び出しの代わりに、コンポーネントはどのようにそれが起こるべきかではなく、何を起こしたいかを表現することでコミュニケーションします:
- 明確な目的: 各コミュニケーションには明示的な目的があります
- 自己完結型: リクエストには必要なすべての情報が含まれています
- 実装の分離: リクエスト側は実装の詳細を知る必要がありません
- 追跡可能性の向上: 操作の流れを追跡しデバッグしやすくします
双方向データフロー
Prism Architectureは、データが複数の方向に流れる必要があることを認識しています:
- 下向きフロー: 情報と状態が上位レイヤーから下位レイヤーへ流れます
- 上向きフロー: リクエスト、コマンド、インテントが下位レイヤーから上位レイヤーへ流れます
- オーケストレーションによる調整: Orchestration Layerがほとんどのクロスレイヤーコミュニケーションを仲介します
レイヤーアクセスルール
コミュニケーションは、どのレイヤーが互いにコミュニケーションできるかについての特定のルールに従います:
- すべてのレイヤーがCore Layerにアクセスできる
- Domain LayerはCore Layerにのみアクセスする
- Orchestration LayerはCore、Domain、Infrastructure、Commonレイヤーにアクセスできる
- Infrastructure LayerはCoreとCommonレイヤーにアクセスできる
- Presentation LayerはCore、Orchestration、Commonレイヤーにアクセスできる
- Common LayerはCore Layerにのみアクセスできる
パッケージ配送モデル
Prism Architectureはレイヤー間のコミュニケーションに「パッケージ配送」モデルを採用しています:
パッケージコンセプト
コミュニケーションオブジェクト(IntentとState)は配送パッケージのように機能します:
- パッケージテンプレート: Common Layerで定義されています
- パッケージ作成: テンプレートを使用して発信元レイヤーで作成されます
- パッケージ配送: アーキテクチャを通じて適切な宛先に送信されます
- パッケージ処理: 各レイヤーは必要なデータのみを抽出します
- パッケージの不変性: パッケージは作成後に変更することができません
このモデルは、データとリクエストがアーキテクチャを通じてどのように移動するかを理解するための直感的な方法を提供します。
主要なコミュニケーションパターン
1. Intentパターン
Intentパターンは上向きコミュニケーション、特にPresentation LayerからOrchestration Layerへのコミュニケーションに使用されます。
動作原理
- Intent作成: コンポーネントは達成したいことを表現するIntentオブジェクトを作成します
- Intent伝播: Intentはコンポーネント階層を上に伝播します
- Intent処理: 上位のコンポーネントがIntentを処理するか、適切なハンドラに転送します
- 結果通信: 結果は状態更新を通じて通信されます
Intentフロー図
Common Layer内のIntent編成
すべてのIntentタイプは、構造化された編成でCommon Layerで定義されています:
Common/
├── Intent/
│ ├── Base/
│ │ └── BaseIntent.swift # すべてのIntentの基本インターフェース
│ ├── UI/
│ │ ├── LoginIntent.swift # UI固有のIntent
│ │ └── ProductIntent.swift
│ ├── Application/
│ │ ├── OrderIntent.swift # アプリケーション操作Intent
│ │ └── UserIntent.swift
│ └── Data/
│ ├── FetchIntent.swift # データ操作Intent
│ └── PersistIntent.swift
主要な特性
- Intentは作成後は不変です
- 操作を実行するために必要なすべてのデータを含みます
- 明確で説明的な名前を持ちます(例:
RegisterUserIntent
、UpdateProfileIntent
) - アプリケーション内で一貫した命名パターンに従います
- すべてのIntent定義はCommon Layerに存在します
- 実際のIntentオブジェクトは発信元レイヤーで作成されます
2. Stateフローパターン
Stateフローパターンは下向きコミュニケーション、特にOrchestration LayerからPresentation Layerへのコミュニケーションに使用されます。
動作原理
- State作成: コンポーネントは現在の状態データを含むStateオブジェクトを作成します
- State伝播: 状態が下に流れる際、各レベルは必要なものを抽出します
- State消費: 下位レベルのコンポーネントは関連する状態を消費します
- UI更新: UIコンポーネントは受け取った状態に基づいてレンダリングします
Stateフロー図
Common Layer内のState編成
すべてのStateタイプは、構造化された編成でCommon Layerで定義されています:
Common/
├── State/
│ ├── Base/
│ │ └── BaseState.swift # すべてのStateの基本インターフェース
│ ├── UI/
│ │ ├── LoginState.swift # UI固有のState
│ │ └── ProductState.swift
│ ├── Application/
│ │ ├── OrderState.swift # アプリケーション操作State
│ │ └── UserState.swift
│ └── Response/
│ ├── OrderResponse.swift # 操作レスポンスState
│ └── UserResponse.swift
主要な特性
- Stateオブジェクトは作成後は不変です
- 各レイヤーは必要なStateのみを抽出します
- State変更は予測可能な方法でUI更新をトリガーします
- すべてのState定義はCommon Layerに存在します
- 実際のStateオブジェクトは発信元レイヤーで作成されます
3. Domain Eventパターン
Domain Eventパターンは注目すべき出来事のコミュニケーション、特にDomain LayerからOrchestration Layerへのコミュニケーションに使用されます。
動作原理
- イベント生成: 重要なことが起きた時にドメインコンポーネントがイベントを生成します
- イベント公開: イベントは中央イベントバスまたはディスパッチャーに公開されます
- イベントサブスクリプション: 関心のあるコンポーネントが関連イベントをサブスクライブします
- イベント処理: サブスクライバーがイベントを処理し、適切なアクションを取ります
イベントフロー例
主要な特性
- イベントは過去形で命名されます(例:
UserRegistered
、OrderPlaced
) - イベントは不変で、何が起きたかに関する関連データを含みます
- 複数のサブスクライバーが同じイベントに反応できます
- イベントはコンポーネント間の疎結合を可能にします
4. Repositoryパターン
Repositoryパターンはデータアクセスコミュニケーション、特にOrchestration LayerとInfrastructure Layer間のコミュニケーションに使用されます。
動作原理
- Repository定義: Core Layerがリポジトリインターフェースを定義します
- Repository実装: Infrastructure Layerがこれらのインターフェースを実装します
- Repository使用: Orchestration Layerがインターフェースを通じてリポジトリを使用します
- データ取得/保存: リポジトリがデータアクセスの詳細を処理します
Repositoryフロー例
主要な特性
- リポジトリはデータアクセスの詳細を抽象化します
- コミュニケーションにはCore Layerエンティティを使用します
- データソース(データベース、APIなど)の詳細を隠蔽します
- データソースに関係なく一貫したインターフェースを提供します
- Common Layerの定義を使用してStateオブジェクトを作成することがよくあります
クロスレイヤーコミュニケーション例
これらの図はIntentとStateオブジェクトが特定のレイヤー間でどのように流れるかを示しています。
PresentationからOrchestration
InfrastructureからOrchestration
主要境界間のコミュニケーション
Presentation ↔ Orchestration
PresentationとOrchestrationレイヤー間の主要なコミュニケーションは次のようなものです:
- Intent: Presentationは操作をリクエストするためにIntentを送信します
- State: Orchestrationはレンダリング用のStateをPresentationに提供します
- Event: Orchestrationは重要な変更をPresentationに通知します
Orchestration ↔ Domain
OrchestrationとDomainレイヤー間のコミュニケーションは次のようなものです:
- メソッド呼び出し: OrchestrationはDomainサービスメソッドを直接呼び出します
- Domain Event: DomainはOrchestrationが処理するイベントを生成します
- 検証結果: DomainはOrchestrationに検証結果を返します
Orchestration ↔ Infrastructure
OrchestrationはInfrastructureと主に次のようなもので通信します:
- Repositoryインターフェース: Coreで定義され、Infrastructureで実装されます
- サービスインターフェース: Infrastructureによって実装される技術的サービスインターフェース
- Query Service: 最適化されたデータ取得のための特殊なサービス
- Response State: InfrastructureはStateオブジェクトにラップされたデータを返します
コミュニケーションにおけるCommon Layerの役割
Common LayerはPrism Architectureのコミュニケーションパターンにおいて重要な役割を果たします:
主要な責任
- 定義ポイント: Common LayerはすべてのIntentとStateタイプを定義します
- 組織化された構造: 異なるタイプのための明確なフォルダ構成を提供します
- 型安全性: レイヤー間の型安全なコミュニケーションを確保します
- 境界強制: レイヤー間の依存性違反を防ぎます
- 共有語彙: アプリケーションの共通コミュニケーション言語を作成します
一般的なコミュニケーションの課題と解決策
課題1: 複雑なオブジェクトグラフ
複雑な関連データを扱う場合:
- 解決策: 必要なすべての関連データをStateオブジェクトに含める
- 利点: 複数の個別リクエストの必要性を減らします
課題2: クロス機能コミュニケーション
機能が互いに通信する必要がある場合:
- 解決策: Orchestration Layerを通じてコミュニケーションをルーティングする
- 利点: 機能間の明確な分離を維持します
課題3: 非同期操作
完了までに時間がかかる操作を処理する場合:
- 解決策: 進行状況と完了を通信するためのState更新を使用する
- 利点: UIは応答性を維持し、ユーザーに進行状況を表示できます
IntentとStateのランタイムプロセス
コミュニケーションのベストプラクティス
- Intentオブジェクトを使用: Intentを単なるメソッド呼び出しではなく、明示的なオブジェクトにします
- 不変State: 予期しない変更を防ぐためにStateを不変に保ちます
- 明示的Event: イベントには何が起きたかを明確に表現する名前を付けます
- 組織化された構造: すべてのコミュニケーションタイプにCommon Layer編成に従います
- 明確な所有権: 各レイヤーは、自身が発信元となるコミュニケーションオブジェクトを作成します
- 選択的抽出: レイヤーはコミュニケーションオブジェクトから必要なものだけを抽出すべきです
- 最小限の変換: 必要な場合にのみデータを変換します
結論
レイヤー間の効果的なコミュニケーションは、クリーンで保守性の高いアーキテクチャを維持するために不可欠です。Prism Architectureはインテントベースのコミュニケーション、Stateフロー、およびイベントパターンを使用して、関心の分離を維持しながらコンポーネント間の明確で予測可能な相互作用を作成します。
すべてのIntentとStateタイプをCommon Layerで定義し、パッケージ配送モデルに従うことで、Prism Architectureはアプリケーション全体を通じたデータと操作の自然な流れをサポートする一貫した効率的なコミュニケーションシステムを作成します。