クリーンアーキテクチャーと単方向データフロー
前回投稿に続いて、クリーンアーキテクチャーと単方向データフローの親和性に関する考察です。
一昨年、私はクリーンアーキテクチャーでAndroid/iOSアプリを開発し、ACCESSテックブック第1章を書きました。無料で読めますので、クリーンアーキテクチャーの概要はここでは短く済ませます。
概要
domainから他へインターフェースを提供し、「この通りに実装して結果をください」(to backend, data, sensor)、「Presenter型のオブジェクトを作ってくれれば結果を代入します」(to UI)とし、domainから他への依存を無くすのがクリーンアーキテクチャーの特徴です。
そのクリーンアーキテクチャーのデータの流れをわかりやすくするのが今回の話です。
補足
「クリーンアーキテクチャーを単方向データフロー化する」と書いてましたが、「元からView→UseCase→Presenterで単方向なのでは?」という意見がありました。確かにその通りです。この話は「データの流れをわかりやすくしたい」という内容なので、不適切な文章は修正しました。
Presenterを採用していると、ActionからViewに戻るまでのルートを自由に決めれるので、私の参画してる案件でもApplicationやAppDelegateなんかがPresenterを継承して、データの行き先がよくわからなくなってるロジックが多少ありました。
PresenterをStateに置き換え
まず、UIからdomainに渡すものをAction、domainからUIにはStateの更新を通知するようにしてみます。
AndroidアプリUnusedAppFinderで置き換えを実践してみました。commit
この図っぽくなりましたよね。
ところが、実はクリーンアーキテクチャーに反しています。Notify Updateのところで、UIがdomainに依存しているからです。
これはUI側からStateをSubscribeすることで回避可能で、矢印を依存関係で書くとデータの流れが分かりづらいので、UIまわりだけデータの流れで書いたというワケです。
さて、データの流れを意識するならViewModelも直さないとですね。
ViewModelからViewへは、依存こそありませんが、データは流れます。つまり、ViewとViewModelはデータの流れで言うと双方向の関係になっています。
これでは、ViewModelまわりのデータの流れが複雑で、テストもしにくいですね。
結局ViewModelは必要なのか
ViewModelを取ってしまうと、Viewに以下の責務が集中します。
- 画面の表示
- Stateの監視
- Stateから画面パーツ向けの型変換
- 画面の更新
- 画面遷移
これなら、2と3をViewModelとして分けてた方がまだ読みやすいでしょうし、テストのしにくさに至っては悪くなっています。
では、Viewからのイベント発火で直接interactorを呼び、ViewModelは上記2と3に専念させればどうでしょうか。
スッキリした気がします。
これもサンプルアプリでやってみました。commit
※LiveData→StateFlowの置き換えも含んだコミットなので若干わかりづらいかも…。
ちなみに最後の図のViewModelは、TCAではViewStore、UnioではViewStreamと呼ばれてたりします。ViewModelじゃない呼び名もアリかもしれないですね。
おわりに
大規模なプロジェクトには採用したことなく検討中なので、もしこうすればもっと良くなるとかコメントがあれば、ぜひ教えてください。
Discussion