0
1
テーマ、知りたいこと
Android開発におけるMVVMとFluxアーキテクチャの違いを知りたいです。
背景、状況
これまでのAndroid開発ではMVVMを使っていましたが、最近Fluxを知り、現在実装途中です。しかし、Fluxを使ってみて、これはMVVMの何を解決するんだろうという疑問が湧いてきました。具体的にMVVMとFluxにどのような違いがあるのか知りたいです。
#質問
・MVVMの双方向フローにやりづらさはありますか?
よくFluxは単方向フローで状態を追いやすい、変化を把握しやすいというメリットがあると言われています。そしてそのメリットは自分でも感じました。しかし、逆にMVVMでわかりづらさがあるのかわかりません。
双方向だとどのようなわかりづらさがあるのでしょうか?実務レベルの大規模開発をしたことがないため、ViewModelでModelを更新し、それを再度Viewで購読するという流れにわかりづらさを感じません。何か具体例などを用いて説明していただけると嬉しいです。
・Fluxを採用すべきアプリはどのようなものでしょうか?
Fluxは登場する構成要素が多いため、冗長になるという問題があります。シンプルにかけるMVVMではなくFluxを採用するのはどのような時なのでしょうか?
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答5件
#1
総合スコア269
投稿2024/09/28 20:33
編集2024/09/29 07:19完全に素人意見ですが以下の解釈であってますか?
Store(データベースなどのデータモデル)→view
データモデル(永続データモデル)からviewへ単方向のデータバインディングを行う。
DBが更新されればviewも当然更新される
action(ボタン押下、サーバーからの応答)→dispatcher(ビジネスロジック)→store
actionがDB更新のためのエントリポイントでdispatcherがDBを更新するためのビジネスロジック(viewModel相当)
アーキテクチャの面でいえばMVVMではmodelとviewModelが双方向データバインディング、viewとviewModelが双方向データバインディングをしていたデータモデルが直接viewとmodelに相当する部分がデータバインディングすることで、フローが明確(依存関係が単純)という事な気がします。
ただ、Androidのviewはライフサイクルが独特で永続データモデルではないデータを画面の回転などによって破棄されるので、結局viewModelを介さないと行けない気が?します。
そうなると、viewのデータを保持する(または永続データを取得する)viewmodelとactionのためのviewmodelのふたつが必要になりますね。
結局は同じmodel(store)のインスタンスを共有することになるのでしょか、(補足、若干予想はしていましたがstoreはシングルトンで行うようですね、まあactionはviewから必ずしも発行される訳では無いみたいなのでほかの回避策もありそうですがね)
関心事の分離としてはアリなのかもしれないが
#2
総合スコア9
投稿2024/09/29 05:43
認識の通りだと思います。私の実装では、例えばアプリの中にTodoリストがあったとして、Todo Storeというクラス内でTodo UiStateという状態を保持します。同じくTodo関連のActionがDB操作などのアクションをDispatcherを介してStoreのUiStateを更新するという流れです。そしてアプリの機能ごと(Todo以外)にActionとStoreは増えます。Dispatcherは1つです。
そしておっしゃる通り、Activityの破棄に対応しなければいけないので、UiStateを保持するStoreがViewModelを継承するか、ViewModelでStoreをインスタンス化するというふうにしています。
>アーキテクチャの面でいえばMVVMではmodelとviewModelが双方向データバインディング、viewとviewModelが双>方向データバインディングをしていたデータモデルが直接viewとmodelに相当する部分がデータバインディングするこ>とで、フローが明確という事な気がします。
これについて詳しく伺いたいです。もしかしたら私の実装が悪いかもしれませんが、先ほど記載した通り、MVVMにしてもFluxにしてもデータホルダー(MVVMならViewModel、FluxならStore)のUiStateを更新し、Viewがそれを購読するという流れは一緒になります。バインディングの違いがあれば詳しく教えていただきたいです。
Fluxは構成要素が分かれていて単方向という部分にデバックのしやすさや状態変化のわかりやすさを感じますが、MVVMでも双方向バインディングが働いている時点で状態変化は予測できないわけではない気がします。これは私の実装経験に依存した認識ですので、こんな時に便利というのがあればそれも知りたいです。
例えば、複数の画面で同じデータを扱わなければいけない場合や、状態変化が複雑なアプリだと理解しやすいのかもしれませんが、その経験がないのでテキストベースでの想像になってしまいます。
例えばGPTに聞いてみるとアクションが頻繁に起こるリアルタイムデータアプリ(株価情報アプリなど)では、Actionが順次実行されるので同時にユーザーアクションが起こっても競合しないが、MVVMだと競合しやすくUIに予期せぬ更新が起こる?といった回答をもらいました。ここも理解度が薄いので(あくまで一例としてあげたのでここを深ぼらなくてもいいですが、こういった、MVVMに比べてFluxの良いところという話をしたいです。)理解したいです。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#3
総合スコア269
投稿2024/09/29 06:53
編集2024/09/29 06:54多分なんですが、
なんとなくのイメージなので揚げ足をあげるのですが、
MVVMだと変数の値がUIの表示に使われるが、
FluxだとDBの値がUIの表示に使われるということだと思います(正確に言えばDB上の実際の値であることを保証しなければならない)、
ただ、「入力」もUIのひとつなので説明に若干混乱します。
以下は蛇足なんで、文脈に関係ないのですが、
StoreはSELECT用のものと、更新用のものを分離した方が再利用性や保守性、色んな面から使いやすい気がする。
ただ、ライフタイムの管理ができないのがネックか。
考えながら文章打ったんですが多分、Fluxの説明がどっかにあってそれをソースにした方がいいのかもですね(全然調べてないので合ってたらラッキー笑)
メリットとしてはひとつ、
UIの表示だけの画面(ただしデータはDBを参照する)みたいな画面の時に、actionに相当する部分を省けるのがいい面としてあるような気がどうしてもします。
(リポジトリパターンを再利用できるとか、selectを分離できるとかもありそうなんだけれども妄想の域を出ない)
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#4
総合スコア269
投稿2024/09/29 10:03
さっきは外だったので帰ってきてPCで文字が打ちやすくなったので、状況を整理してみました。
おそらくfluxではactionを一つのクラスで管理する(画面事は関係ない)ので見通しが良いのがメリットなんだと思います。
mvvmではviewが入力を受け付け、viewModelにビジネスロジックを書くというものでしたが、これだと、viewとviewModelの依存関係を切っても切れません。
actionにインターフェースを集約することで、依存関係がなくなります。
構成として、
storeからの依存
- store -> view
storeがシングルトンとしてある(またはポーリングするか、購読するかwebsocketを使うか)のか、store自体がビジネスロジックでDBはまた別なのかわかりませんが、
データ取得することでviewを更新します。
メリット: もし、入力のない画面であれば、これだけで完結するため、不要にクラス定義をする必要がなくなりました。
viewからの依存
- view -> action
- view <-> viewModel
view -> action
viewはボタン押下などされた際にactionのメソッドを呼び出します。actionは一つのアプリケーションないに一つのクラスです。
actionはdispacherに通知するためのメソッド(viewからみるとインターフェース)の管理をするためのクラスであり、関数のたまり場でしかありません。
メリット: すべてのDB更新はactionというインターフェースを介して行われるため、ほかの部分を考慮する必要がなくなるでしょう。
view <-> viewModel
androidアプリケーションのライフタイムに対応するために、viewModelはviewと双方向のデータバインディングをしますが、Fluxにビジネスロジックを書きたいので、viewModelにビジネスロジックを書いてはいけません。
おそらく、入力制御(正規表現など)ぐらいの記述にとどまるでしょう。
viewとviewModelは1vs1対応します。
actionからの依存
- action -> dispatcher
dispatcherについてはよくわからないので、名前での考察ですが、
おそらくactionの中で、並列処理できる何らかの処理があり、dispatherはkotlinでいうディフェンダーを返す。
actionが awaitAllのようなメソッドに非同期処理したい項目を登録することができる。
メリット:dispatherもactionと同じく、関数の集まり。処理のタイミングはおそらくactionに任せることができる。
更新処理をまとめた関数の集まり
dispatcherからの依存
- dispatcher -> store
storeもいまいち、ビジネスロジックを書くのか、シンプルにDBの写像として働くのかわからないのだが、
dipatcherがディフェンダーを生成するための実際のデータ取得フローに使用するデータの塊がstoreだと思われる。
メリット: actionからの依存に記載
まとめ
おそらくなんですが、クラス定義は減ります。半面actionに登録する関数が増えるため、処理が多すぎると見通しが悪くなるような気がします。適宜分割することはできるでしょうが、なにに従って分割できるのかをうまく考慮するのが難しいかもしれません。
MVVMと違い、画面とクラスの対応関係がほとんどなくなるので、膨大な画面が存在するプロジェクトではどこに何があるのか訳が分からないというのを最低限に減らせるような気がします。
MVVMでは一つのフォルダにviewに関する処理を入れるパターンと、M,VM,Mごとにフォルダを分割するパターンがあると思いますが、どこに何のファイルがあるのかがわけわからなくなるのを一見防止できそうな感じがします。
fluxのデメリットとして、更新処理自体がどのスレッドで行われるかを特に考慮しませんでした。うまく制御する方法があるのかもしれないですが、インスタンスがリークする可能性に配慮しないといけないかもしれないです。
どうせインスタンス化するならシングルトンですべて作ってもいいのかもしれないです。状態を持つのはstoreぐらいで他は関数の集まりでしょうから、特に混乱はないような気もします。
今回初めて知りましたが、自分も使ってみたくなりました。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#5
総合スコア269
投稿2024/09/29 16:42
Fluxと言っても、人によって定義がまちまちかもしれないので、質問者さんの意図するものを明確にする必要があるかもしれません。
例えば以下の例だと
https://techblog.zozo.com/entry/android-flux
アーキテクチャと謳っているものの図と説明を見る限りMVVMと実態が同じになっています。
VMでやっていたバインディングがReducerまで伸びていくせいで構成要素が肥大化していそうです。
このリンク先の説明では、単一方向のデータフローを強調しているように見えますが、MVVMもAndroidDeveloperの推奨アーキテクチャでは、単一方向のデータフローを推奨しています。
https://developer.android.com/develop/ui/compose/architecture?hl=ja#udf
恐らく、このリンク先の説明は、
双方向データフローと双方向データバインディングを誤解または混同しています。
MVVMでは双方向データバインディングをしているため、やりづらさや分かりづらさはありません。
私は初めFluxのやりたい事は、ビジネスロジックの再利用だと思いました。副作用として関心事の分離があると思いました。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。