メインコンテンツまでスキップ

UIアーキテクチャ比較

読了時間: 約12分

はじめに

このドキュメントでは、PrismUI(Prism Architectureで推奨されるプレゼンテーション層パターン)と他の一般的なUIアーキテクチャパターンとの詳細な比較を提供します。これらの違いを理解することで、アプリケーションにどのUIアーキテクチャを実装するかについて、情報に基づいた判断ができるようになります。

代替アーキテクチャとの比較ドキュメントがアーキテクチャ全体のアプローチに焦点を当てているのに対し、このドキュメントは特にUIアーキテクチャパターンとそれらがより広範なPrism Architectureとどのように統合されるかを扱います。

UIアーキテクチャパターンの概要

PrismUI

PrismUIはPrism Architectureにおける推奨のプレゼンテーション層パターンであり、コアアーキテクチャのドメイン中心アプローチと特に連携するように設計されています。

主な特徴:

  • UIコンポーネント階層を反映した階層的プレゼンター構造
  • UIからプレゼンターへのインテントベースの通信
  • プレゼンターからUIへの単方向の状態フロー
  • UI状態管理と視覚的コンポーネントの明確な分離
  • 宣言的UIフレームワーク(SwiftUI、React、Flutter)との互換性

MVVM(Model-View-ViewModel)

MVVMはUI(View)をそのロジック(ViewModel)とデータ(Model)から分離します。

主な特徴:

  • ビューモデルがモデルデータをビュー用に変換
  • ビューとビューモデル間の双方向データバインディング
  • ビューモデルはビューを直接参照しない
  • WPF、Xamarin、SwiftUI、Angularアプリケーションで人気

Redux/Flux

ReduxとFluxパターンは単方向データフローと単一の真実の源を強調します。

主な特徴:

  • 中央ストアがアプリケーション状態を管理
  • アクションが状態変更を記述
  • リデューサーがアクションに応じて状態変更を決定
  • 単方向データフロー
  • Reactやその他の最新のJavaScriptフレームワークでよく使用される

MVC(Model-View-Controller)

MVCはアプリケーションを3つの相互接続されたコンポーネントに分離します。

主な特徴:

  • コントローラーがユーザー入力を処理し、モデルを更新
  • モデルがデータとビジネスロジックを表現
  • ビューがユーザーにデータを提示
  • コンポーネント間の双方向通信
  • 多くのフレームワークで使用される伝統的なパターン

MVP(Model-View-Presenter)

MVPはテスト容易性に重点を置いたMVCの進化形です。

主な特徴:

  • プレゼンターにUIロジックが含まれ、ビューを更新する
  • ビューは受動的で、ユーザーアクションをプレゼンターに転送する
  • モデルはデータとビジネスロジックを表現する
  • プレゼンターはビューとモデルの間を仲介する
  • UIロジックを分離してテストするのに適している

Composable Architecture

コンポーザブルアーキテクチャは、コンポーザビリティと予測可能性に焦点を当てた新しいパターンです。

主な特徴:

  • 状態と振る舞いが小さな単位から構成される
  • 副作用が明示的に処理される
  • 状態変更が予測可能で追跡可能
  • 強力な型安全性
  • SwiftとKotlinアプリケーションで人気

詳細な比較

Prism Architectureとの統合

パターン統合のしやすさPrism層との互換性アーキテクチャの一貫性
PrismUI優れている - Prism向けに設計オーケストレーション層との直接統合Prism原則との完全な一貫性
MVVM良い - 類似する概念インテントシステムとの適応が必要データフローモデルとの部分的な一貫性
Redux/Flux中程度 - 異なるメンタルモデル重要なアダプター層が必要一貫した単方向フローだが実装が異なる
MVC低い - データフローが矛盾きれいに統合するのが難しいPrism原則と一貫性がない
MVP良い - 類似した受動的ビューの概念階層に適応させる必要がある分離モデルとの部分的な一貫性
Composable中程度 - 概念的に整合統合用のアダプターが必要一貫したコンポーザビリティだが実装が異なる

状態管理

パターン状態の編成状態の不変性状態の伝播状態の永続化
PrismUI定義されたレベルを持つ階層的強制トップダウンフロー適切なレベルでサポート
MVVMビューモデルごとオプションバインディングベース実装によって異なる
Redux/Flux中央集権的ストア必須サブスクリプションベース強力なサポート
MVCモデル間で分散強制されないコントローラー経由限定的なサポート
MVPプレゼンター管理オプションプレゼンターからビューへ限定的なサポート
Composable構成可能な状態コンテナ通常は必須定義されたリデューサー強力なサポート

通信フロー

パターン入力処理出力フローエラー処理副作用管理
PrismUIインテントオブジェクト状態更新状態の一部オーケストレーションレベル
MVVMコマンド/バインディングプロパティ変更様々なアプローチ多くの場合ビューモデル内
Redux/Fluxアクション状態サブスクリプション状態プロパティミドルウェア/サンク
MVCコントローラーメソッド直接ビュー更新コントローラー処理混在する場所
MVPインターフェースメソッドインターフェースコールバックプレゼンター処理プレゼンター内
Composableアクション状態更新状態プロパティエフェクトシステム

コンポーネント階層

パターンコンポーネント編成親子通信コンポーネント間通信再利用性
PrismUI3レベルの明示的階層構造化された親子関係共通の祖先経由高い - 明確な境界
MVVMフラットまたはアドホック共有サービス経由共有サービス経由中程度 - ビューモデル依存
Redux/Fluxコンテナコンポーネントを持つフラットプロパティ受け渡しストア経由高い - 純粋なコンポーネント
MVCコントローラー中心の階層コントローラー経由共有モデル経由低い - 密結合
MVPフラットまたは最小階層限定的共有サービス経由中程度 - プレゼンター依存
Composable明示的な構成定義された構成定義された通信非常に高い - 構成重視

テスト容易性

パターンUIロジックテストモック複雑性状態検証ユーザーインタラクションテスト
PrismUI高い - 分離されたプレゼンター低い - 明確なインターフェース簡単 - 明示的な状態直感的 - インテント検証
MVVM高い - 分離されたビューモデル中程度 - 依存関係とバインディング中程度 - 監視可能なプロパティ中程度 - コマンドバインディング
Redux/Flux高い - 純粋なリデューサー関数低い - 定義されたアクション簡単 - 状態スナップショット中程度 - アクションディスパッチ
MVC低い - コントローラービュー結合高い - 依存関係難しい - 分散状態複雑 - ビューコントローラー統合
MVP高い - 分離されたプレゼンター中程度 - インターフェースモック中程度 - インターフェース検証中程度 - インターフェース呼び出し
Composable高い - 純粋なリデューサー関数低い - 定義されたアクション簡単 - 状態スナップショット中程度 - アクションディスパッチ

PrismUIの独自機能

階層的プレゼンター構造

PrismUIは、現代のUIアプリケーションの自然な構造を反映する3階層のプレゼンター構造を採用しています。ビューモデルやプレゼンターがフラットに編成されるパターンとは異なり、この構造化されたアプローチは責任と通信経路の明確な境界を作成します。

3階層プレゼンター階層

1. トップレベルプレゼンター(画面プレゼンター)

トップレベルプレゼンターは画面またはフローレベルで動作し、画面全体またはユーザーフロー全体の主要なコーディネーターとして機能します。オーケストレーション層への排他的なアクセス権を持ち、以下の責任を負います:

  • ユースケースを通じてオーケストレーション層と直接通信する
  • 画面間または主要なアプリケーションセクション間のナビゲーションを管理する
  • 画面内の異なる機能間を調整する
  • ドメインデータを配布用のUI固有の状態に変換する
  • 認証や権限などのシステム全体のUI状態を処理する
  • 子プレゼンターからの重要なイベントに応答する

一般的なアプリケーションでは、HomeScreenPresenter、ProfileScreenPresenter、CheckoutFlowPresenterなどの主要な画面用のトップレベルプレゼンターを持つことがあります。

2. ミッドレベルプレゼンター(機能プレゼンター)

ミッドレベルプレゼンターは、画面内の特定の機能領域またはセクションを処理します。トップレベルの調整とコンポーネント固有のロジックの間の仲介者として機能します:

  • 明確な機能領域または再利用可能な画面セクションを管理する
  • トップレベルプレゼンターとコンポーネントプレゼンターと双方向に通信する
  • 画面レベルの状態を機能固有の状態に変換する
  • 重要なインテントをトップレベルプレゼンターにバブルアップする
  • 機能固有のビジネスロジックを処理する
  • 複数の関連UIコンポーネントを調整する

例としては、UserInfoPresenter、ProductListPresenter、PaymentFormPresenterなどがあり、それぞれが一貫性のある機能領域を担当します。

3. コンポーネントプレゼンター(UIコンポーネントプレゼンター)

コンポーネントプレゼンターは個別のUIコンポーネントとその状態を管理します。これらは最も粒度の細かいプレゼンターであり、以下に焦点を当てています:

  • 特定の、しばしば再利用可能なUIコンポーネントの状態を管理する
  • UI要素との直接的なユーザーインタラクションを処理する
  • コンポーネント固有のロジックと検証を実装する
  • 最適なコンポーネントレンダリングのためにデータを変換する
  • ユーザーインテントを親プレゼンターに転送する

一般的なコンポーネントプレゼンターには、AvatarPresenter、TextFieldPresenter、SelectionListPresenterなどがあります。

階層内の通信フロー

プレゼンター階層は、状態とインテントの両方のフローに明確な経路を確立します:

下向きの状態フロー:

  1. トップレベルプレゼンターがオーケストレーション層からデータを受け取る
  2. データを画面レベルの状態に変換する
  3. 関連する部分をミッドレベルプレゼンターに渡す
  4. ミッドレベルプレゼンターがデータを機能用に変換する
  5. コンポーネント固有の状態をコンポーネントプレゼンターに渡す
  6. コンポーネントプレゼンターがUIコンポーネントを更新する

上向きのインテントフロー:

  1. UIコンポーネントがユーザーアクションを生成する
  2. コンポーネントプレゼンターがアクションをインテントに変換する
  3. インテントを親のミッドレベルプレゼンターに転送する
  4. ミッドレベルプレゼンターがインテントを処理するか上へバブルアップする
  5. トップレベルプレゼンターが重要なインテントを受け取る
  6. 必要に応じてオーケストレーション層と通信する

階層構造の利点

この3階層アプローチはいくつかの重要な利点を提供します:

  • 明確な責任分離: 各プレゼンターレベルに明確に定義された責任がある
  • モジュール開発: チームは異なるレベルで独立して作業できる
  • 再利用可能なコンポーネント: コンポーネントプレゼンターは機能間で再利用できる
  • 保守可能な状態フロー: 状態変換が適切なレベルで行われる
  • テスト可能なアーキテクチャ: 各レベルを分離してテストできる
  • 自然なUI構造の反映: 現代のUIの自然なコンポーネント階層を反映している
  • スケーラブルな複雑性: シンプルな場合も複雑なUIシナリオも対応可能

階層の例

このUIアーキテクチャへの構造化されたアプローチは、PrismUIと他のUIアーキテクチャパターンの主要な違いの一つであり、より広範なPrism Architecture内でより保守性とスケーラビリティの高いプレゼンテーション層を可能にします。

インテントベースの通信

PrismUIはUIからプレゼンターへのユーザーアクションを伝えるためにインテントを使用します:

// インテント定義の例
enum ProfileIntent {
case loadProfile
case updateBio(String)
case toggleFavorite
}

// UIからプレゼンターへのインテント伝達
presenter.handle(intent: .updateBio(newText))

利点には以下が含まれます:

  • 明示的で追跡可能なユーザーインタラクション
  • UIコンポーネントとアクション処理の分離
  • テスト可能なインテント処理ロジック
  • 利用可能なユーザーアクションの明確なドキュメント化

状態フロー管理

PrismUIは不変状態オブジェクトを使用した単方向状態フローを実装します:

// 状態定義の例
struct ProfileState {
let userName: String
let bio: String
let isLoading: Bool
let error: Error?
}

// プレゼンターからUIへの状態更新
view.render(state: newState)

このアプローチは以下を提供します:

  • 予測可能なUI更新
  • 状態のデバッグとテストの容易さ
  • 不整合なUI状態の防止
  • タイムトラベルデバッグのサポート

宣言的UIフレームワークとの統合

PrismUIは現代の宣言的UIフレームワークとシームレスに連携します:

// SwiftUIの例
struct ProfileView: View {
@ObservedObject var presenter: ProfilePresenter

var body: some View {
VStack {
Text(presenter.state.userName)

if presenter.state.isLoading {
ProgressView()
} else {
Button("更新") {
presenter.handle(intent: .loadProfile)
}
}
}
}
}

この互換性は以下を保証します:

  • SwiftUI、React、Flutterとの自然な統合
  • フレームワーク固有の最適化の活用
  • 異なるプラットフォーム間での一貫したアーキテクチャ
  • プラットフォーム間のスムーズな移行

PrismUIと他のパターンとの比較

PrismUI vs. MVVM

類似点:

  • 両方ともUIロジックをUIコンポーネントから分離する
  • 両方ともリアクティブデータフローをサポートする
  • 両方とも分離によるテスト容易性を促進する

主な相違点:

  • 構造: PrismUIは明示的な階層を使用;MVVMは通常フラット
  • 通信: PrismUIはインテントオブジェクトを使用;MVVMはバインディング/コマンドを使用
  • 状態フロー: PrismUIは単方向フローを強制;MVVMは多くの場合双方向
  • 統合: PrismUIはPrism Architecture向けに設計;MVVMはより汎用的

MVVMをPrismUIより選ぶタイミング:

  • 組み込みのMVVMサポートを持つフレームワーク(WPFなど)を使用している場合
  • 双方向バインディングが実装を大幅に簡素化する場合
  • 既存のMVVMコードベースで作業している場合

PrismUI vs. Redux/Flux

類似点:

  • 両方とも単方向データフローを使用
  • 両方とも不変状態を強調
  • 両方とも通信にアクション/インテントオブジェクトを使用

主な相違点:

  • 状態管理: PrismUIは階層状態を使用;Reduxは単一ストアを使用
  • アクション処理: PrismUIはインテントを上にバブルアップ;Reduxはストアにディスパッチ
  • 副作用: PrismUIはオーケストレーションで処理;Reduxはミドルウェアを使用
  • 構造: PrismUIは階層的プレゼンターを持つ;Reduxはコンテナコンポーネントを持つ

Redux/FluxをPrismUIより選ぶタイミング:

  • Reduxが確立されているJavaScript/Reactプロジェクト
  • 中央集権的な状態のデバッグが重要な場合
  • チームの専門知識が主にReduxパターンにある場合

PrismUI vs. MVC

類似点:

  • 両方とも関心事を明確なコンポーネントに分離する
  • 両方ともユーザーインタラクションとUI更新を処理する

主な相違点:

  • 通信: PrismUIはインテントと状態を使用;MVCは直接メソッド呼び出しを使用
  • データフロー: PrismUIは単方向;MVCは多くの場合双方向
  • テスト容易性: PrismUIはテスト容易性が高い;MVCは多くの場合テスト容易性が低い
  • 結合度: PrismUIは結合度が低い;MVCは多くの場合結合度が高い

MVCをPrismUIより選ぶタイミング:

  • MVCのシンプルさがメリットを上回る非常にシンプルなUIの場合
  • MVCを厳密に強制するフレームワークを使用している場合
  • アーキテクチャがそれほど重要でない短期プロトタイピングの場合

PrismUI vs. MVP

類似点:

  • 両方ともUIロジック用にプレゼンターコンセプトを使用
  • 両方ともビューを比較的受動的にする
  • 両方ともテスト容易性に焦点を当てる

主な相違点:

  • 構造: PrismUIは階層的プレゼンターを持つ;MVPは通常フラット
  • ビュー更新: PrismUIは状態オブジェクトを使用;MVPはインターフェースメソッドを使用
  • 統合: PrismUIはオーケストレーションと統合;MVPは様々

MVPをPrismUIより選ぶタイミング:

  • レガシーまたは命令型UIフレームワークと連携している場合
  • ビューインターフェースがアプリケーションニーズにより合っている場合
  • MVCからより良いパターンへ徐々に移行している場合

PrismUI vs. Composable Architecture

類似点:

  • 両方ともコンポーネントの構成性を強調
  • 両方とも単方向データフローを使用
  • 両方ともテスト容易性と状態の予測可能性に焦点を当てる

主な相違点:

  • スコープ: PrismUIはプレゼンテーションに焦点;Composableは多くの場合フルスタック
  • 状態管理: PrismUIは階層的状態を使用;Composableは構成された状態を使用
  • 副作用: PrismUIはオーケストレーションに委任;Composableはエフェクトシステムを使用
  • 統合: PrismUIはPrism向けに設計;Composableは多くの場合スタンドアロン

Composable ArchitectureをPrismUIより選ぶタイミング:

  • フルスタックの構成性がPrism統合より重要な場合
  • TCAなどのライブラリをすでに使用しているSwift/iOSプロジェクト
  • 関数型プログラミングパラダイムが強く好まれる場合

各パターンを選ぶタイミング

PrismUIを選ぶタイミング:

  • 完全なPrism Architectureを使用してアプリケーションを構築する場合
  • 宣言的UIフレームワーク(SwiftUI、React、Flutter)で作業する場合
  • UIロジックとプレゼンテーションの明確な分離が必要な場合
  • 複雑で階層的なUIを構築する場合
  • UIロジックの高いテスト容易性が必要な場合

MVVMを選ぶタイミング:

  • 組み込みのMVVMサポートを持つフレームワークで作業する場合
  • 強力なデータバインディング機能が必要な場合
  • データ集約型アプリケーションを構築する場合
  • チームがMVVMの強い経験を持つ場合

Redux/Fluxを選ぶタイミング:

  • JavaScript/Reactアプリケーションを構築する場合
  • 中央集権的な状態管理が必要な場合
  • タイムトラベルデバッグが必要な場合
  • 複雑なアプリケーション状態を管理する場合

MVCを選ぶタイミング:

  • MVCを強制するフレームワークで作業する場合
  • シンプルなフォームベースのアプリケーションを構築する場合
  • 迅速なプロトタイピングが主な目標の場合
  • チームがMVCの強い経験を持つ場合

MVPを選ぶタイミング:

  • 従来の命令型UIフレームワークで作業する場合
  • 高いUIロジックのテスト容易性が重要な場合
  • 関心事の明確な分離が重要な場合
  • シンプルなプレゼンテーションで複雑なUIロジック

Composable Architectureを選ぶタイミング:

  • 高度にモジュール化されたアプリケーションを構築する場合
  • 強力な型安全性が必要な場合
  • 複雑な副作用を管理する場合
  • チームが関数型プログラミング原則を重視する場合

フレームワーク固有の考慮事項

iOS/SwiftUI

PrismUIはSwiftUIと非常にうまく連携します:

  • 状態とビュー更新の間の自然なマッピング
  • SwiftUIのバインディングシステムとの簡単な統合
  • SwiftUIのネイティブ状態管理との互換性
  • SwiftUIが奨励するが強制しない適切な分離

Android/Jetpack Compose

PrismUIはJetpack Composeとスムーズに統合します:

  • Composeの状態ベースのレンダリングと互換性あり
  • Composeの単方向データフローとうまく連携
  • Composeの柔軟性を補完する構造を提供
  • Composeが奨励する関心事の明確な分離

Web/React

PrismUIの概念はReactに効果的に適用できます:

  • 状態オブジェクトはReactのコンポーネント状態にマッピング
  • インテントはコールバックとアクションクリエーターにマッピング
  • 階層的プレゼンターはコンテナコンポーネントにマッピング
  • 単方向フローはReactのベストプラクティスと整合

テスト戦略

PrismUIはUIロジックの包括的なテストを容易にします:

  1. プレゼンター単体テスト:

    • インテント処理ロジックを分離してテスト
    • 特定の入力に対する状態変更を検証
    • プレゼンター階層通信をテスト
  2. 統合テスト:

    • プレゼンターとオーケストレーションの相互作用をテスト
    • 正しいインテントバブリングを検証
    • 階層を通じた状態伝播をテスト
  3. UIコンポーネントテスト:

    • 状態に基づく正しいレンダリングをテスト
    • ユーザーアクションからのインテント生成を検証
    • アクセシビリティとレイアウトプロパティをテスト

PrismUI実装のベストプラクティス

  1. 階層構造に従う:

    • 明確なトップ、ミッド、コンポーネントレベルのプレゼンターを維持
    • 各レベルで明確な責任を定義
    • プレゼンター階層をUI階層に合わせて維持
  2. 明確なインテントを設計:

    • 明示的で細分化されたインテントオブジェクトを作成
    • インテントにはドメイン中心の命名を使用
    • 適切な階層レベルでインテントを処理
  3. 状態を不変にする:

    • 状態オブジェクトを不変構造として設計
    • 各変更に対して新しい状態インスタンスを作成
    • レンダリングに必要なもののみを含める
  4. 状態フローを最適化:

    • 子プレゼンターには必要な状態のみを渡す
    • 特定のプレゼンターのニーズに合わせて状態を変換
    • 不要な更新を防ぐための適切な差分比較を使用
  5. オーケストレーションとの統合:

    • トップレベルプレゼンターのみがオーケストレーションと通信
    • インテントを適切なレベルまでバブルアップ
    • プレゼンテーションとオーケストレーションの関心事を分離

結論

PrismUIは、Prism Architectureの中核原則と完全に一致する、現代的で階層的なUIアーキテクチャアプローチを提供します。インテントベースの通信、単方向状態フロー、宣言的UIフレームワークとの互換性に焦点を当てることで、現代のアプリケーション開発に最適な選択肢となります。

各UIアーキテクチャパターンにはそれぞれの強みがありますが、PrismUIはテスト容易性、スケーラビリティ、開発者体験を優先するバランスの取れたアプローチを提供し、Prism Architecture実装における推奨選択肢となっています。

UIアーキテクチャを選択する際は、チームの経験、プロジェクト要件、対象プラットフォーム、UIアーキテクチャがアプリケーション全体のアーキテクチャとどのように統合されるかを考慮しましょう。