LoginSignup
12
10

More than 5 years have passed since last update.

unidirection data flow にしびれる、憧れる理由

Last updated at Posted at 2015-05-19

短いまとめ

「ビューにしか影響を与えないアクションもモデルを通過する」のが、すごい。

中ぐらいのまとめ

  1. Viewにしか影響を与えないアクションもModelを通過する
  2. Controllerの責務から「アクションをModelとViewに振り分ける」がなくなる
  3. アクションが(UIのイベントより)抽象的でないと実現できない
  4. アクションを設計するのは難しい
  5. アクションが設計できれば他のパターンでも上手くいく
  6. アクションの設計を強要したのが、すごい

背景

UIアーキテクチャーパターンを振り返ります。

MVC

The Model-View-Controller (MVC) Its Past and Presentに準拠します。

簡単な説明

  • ドメインロジック
    • M:Model データモデル更新ロジック + データモデル
  • プレゼンテーションロジック
    • V:View プレゼンテーションの更新
    • C:Controller ユーザの入力処理

素晴らしい点

  • 分割方針がわかりやすい。誰にでも扱える。

解決できない問題

  • 役割が明確なモジュール(Model)が小さい
    • 一般にビジネスロジックの量は少ない
    • アプリケーション全体の1/3を期待する?実際は1/10程度
  • ビューの状態をControllerが持つ
    • Modelの役割はドメインロジック。ビューの状態はもちません
    • ビューの状態
      • 要素の選択状態
      • ボタンの有効無効制御
  • 要素追加後に自動選択すると、ビューの更新をモデルの更新完了後まで待つ必要がある。Supervising Controllerを導入できない

ModelとViewの役割は明確ですが、それ以外の役割は全てControllerが持ちます。
Controllerが巨大化します。

MVP

MVP: Model-View-Presenter
The Taligent Programming Model for C++ and Java
に準拠します。

簡単な説明

MVCのControllerを役割を細分化したパターン。

  • ドメインロジック
    • M:Model データモデル
  • プレゼンテーションロジック
    • S:Selection 選択状態
    • C:Command データモデル更新ロジック + 選択状態更新ロジック
    • P:Presenter ビューの状態 + ビューの状態更新ロジック + Commandの呼び出し
    • I:Interactor ユーザの入力処理
    • V:View プレゼンテーションの更新

選択状態やビューの状態をもつ専用のオブジェクトを導入します。

素晴らしい点

  • Selectionを導入し、ビューがModelとSelectionを両方監視することで、Supervising Controllerが導入できる
  • CommandをControllerから分離できる

解決できない問題

  • 複数のビューを更新したい時はPresenterが頑張る
  • 編集モードとreadonlyモードの切り替えはPresenterが頑張る
  • モデル更新イベントとビュー更新イベントがどちらもPreseterを通る。Presenterはモデル更新とビュー更新の振り分けを行う

Presenterが巨大化します。

プレゼンテーションモデル

Presentation Modelに準拠します。

簡単な説明

MVCのControllerを画面の要素で分割したパターン。
例えば、リストとリストの表示要素、それぞれにPresentationModelを作ります。

  • ドメインロジック
    • M:Model データモデル更新ロジック + データモデル
  • プレゼンテーションモデル
    • PM:PresentationModel ビューの状態 + Mを表示しやすいように変換。
    • V:View プレゼンテーションの更新

素晴らしい点

  • 巨大化するControllerを分割できる
  • PresentationModelは画面構成と対応するツリー構造になる。構成がわかりやすい

解決できない問題

  • PM間のやりとりは親PMが管理
  • PMとModelが1対1で対応していない場合、対応付けの解決は親PMが行う
  • モデル更新イベントとビュー更新イベントがどちらもPMを通る。PMはモデル更新とビュー更新の振り分けを行う

上位のPresentationModelが巨大化します。

残っている課題

高度なアプリケーションを作ると
ユーザーの操作をModelとViewまたは他のPresentationModelに振り分ける処理が
プレゼンテーションロジックに集中します。

既存のMVC、MVP、プレゼンテーションモデルは、これを解決しません。

本題

unidirection data flow を見ます。

flux-diagram

MVCな視点で見ると、以下になります。

  • ドメインロジック
    • Store
  • プレゼンテーションロジック
    • Action Creators : ユーザーの入力処理
    • React Views : プレゼンテーションの更新

構成要素は(Dispatcherを除くと)MVCとあまり変わりません。

MVCとの違い

「ビューにしか影響を与えないアクションもモデルを通過する」

ビューにしか影響を与えないアクション例:

  • 選択
    • 複数要素を選択して編集する際の、選択状態
  • 非表示切り替え
    • TODOリストの完了項目を非表示にする
    • リストの明細を表示する
  • Read Onlyモード切り替え

これらのアクションが一度はStoreを通る(けど何もしない)のがすごい。

「ビューにしか影響を与えないアクションもモデルを通過する」のすごさ

MVCが生まれてから四半世紀、いろいろ分割してみたけど

ユーザーの操作をModelとView(他のPresentationModel)に振り分ける処理が
プレゼンテーションロジックに集中する。

を回避する方法は発見されませんでした。

「ビューにしか影響を与えないアクションもモデルを通過する」とするだけで
モデル(Store)もビューも「自分の興味があるアクションにだけ、反応すれば良く」なりました:tada:

問題点

  • アクションがflowの途中で破壊された場合(バグ)、発生箇所を特定するのが面倒
  • なんでもflowを一周するのが面倒
    • 「入力欄に文字が入っているときだけ、ボタンを押せる」インタラクションを作るのが面倒
  • アクションの設計が難しい
    • ユーザー操作を上手く抽象化できれば、プレゼンテーションモデルだって、PM間の通信も上手く整理できる

まとめ

「ユーザー操作を抽象化しない」逃げ道を塞ぎました

  • :thumbsup: 機能が増えても破綻しない設計
  • :thumbsdown: 設計・実装コストが高い

unidirection data flowアーキテクチャーの最大の特徴はここだとと思います。
(少し知見がたまると、違う特徴が見えてくる可能性はあります。)

fluxの補足

Dispatcherが必要な理由

  • アクションの投げ先がシングルトンだと、ActionCreatorをViewのパーツごとに分けたときに投げ先を取得しやすい
  • 一つのActionが複数のデータモデル・Viewを変更する時、Actionを分割する
    • 例えばカスケード削除。
  • 分割したActionの順序を制御する
    • 例えばカスケード削除。データモデルは大抵どの順番で消しても大丈夫。Viewは削除順に制約があることがある

Constantsが必要な理由

  • アクションの名前をAction Creator、Dispatcher、Storeで参照する。定数定義があると補完しやすい。
12
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
10