Jetpack Compose で Google Analytics を使うなら、MVVM に乗せる意味はほとんどない

UIイベントをViewModel経由にしても責務は増えるだけ。Composeの副作用で完結させたほうがシンプルになる。

 

🧑🏻‍💻 「AnalyticsはViewModelから送るべき」という思い込み

Jetpack Composeでは、ボタンタップや画面表示などのイベントをGoogle Analyticsへ送る機会が多くあります。

しかし、多くのMVVMサンプルでは次のようなコードになっています。


Button
   │
   ▼
ViewModel.onClick()
   │
   ▼
Analytics.log(...)

一見MVVMらしく見えます。

ですが、本当にViewModelが必要なのでしょうか。

Composeでは、多くの場合答えは No です。

 

🧑🏻‍💻 AnalyticsはUIイベントである

Google Analyticsが知りたいのは

- ボタンが押された。
- 画面が表示された。
- ダイアログが開いた。
- スクロールした。
- タブが切り替わった。

つまり

「UIで何が起きたか」

です。

これはRepositoryのデータでもなく、
Business Logicでもありません。

純粋なUIイベントです。

 

🧑🏻‍💻 ViewModelは何も判断していない

例えば


fun onFavoriteClick() {
    analytics.log("favorite")
}

これだけなら

ViewModelは

- 状態も持たない。
- ロジックもない。
- ただ転送しているだけ。

です。

実質


Button
   │
   ▼
Analytics

との違いがありません。

 

🧑🏻‍💻 Composeならその場で書ける


Button(
    onClick = {
        analytics.logEvent("favorite")
        onFavorite()
    }
) {
    Text("Favorite")
}

これだけです。

余計な

- Event
- Action
- Intent
- ViewModel関数

は不要です。

 

🧑🏻‍💻 画面表示も同じ

よくある実装


LaunchedEffect(Unit) {
    viewModel.onScreenShown()
}

ViewModel


fun onScreenShown() {
    analytics.logScreen("Home")
}

ですが、

Composeなら


LaunchedEffect(Unit) {
    analytics.logScreen("Home")
}

だけで終わります。

ViewModelは何もしていません。

 

🧑🏻‍💻 スクロールイベントも同じ

Composeでは


LaunchedEffect(listState) {
    snapshotFlow {
        listState.firstVisibleItemIndex
    }.collect {
        analytics.logScroll(it)
    }
}

で十分です。

これを


snapshotFlow
      │
      ▼
ViewModel
      │
      ▼
Analytics

にする理由はありません。

 

🧑🏻‍💻 MVVMに乗せることで増えるもの


UI
 │
 ▼
ViewModel
 │
 ▼
Analytics

追加されるもの

- Eventクラス
- ViewModel関数
- DI
- テスト対象
- 呼び出し経路

しかし

増える責務はありません。

 

🧑🏻‍💻 ViewModelはUIの代理人ではない

ViewModelの役割は

- UI Stateを持つ。
- Business Logicを実行する。
- Repositoryと連携する。

ことです。

Analytics送信だけのために


fun onButtonClick()
fun onFabClick()
fun onBackPressed()
fun onTabSelected()
fun onDialogOpened()

を大量に並べると、

ViewModelは単なるイベント中継器になります。

 

🧑🏻‍💻 Composeには副作用APIがある

Composeには

- LaunchedEffect
- DisposableEffect
- SideEffect
- snapshotFlow

があります。

これらは

UIから外部世界へ何かを通知する

ために存在しています。

Analytics送信はまさに副作用です。

Compose自身が用意している仕組みを使う方が自然です。

 

🧑🏻‍💻 UIイベントはUIで完結させる

例えば


Button(
    onClick = {
        analytics.logEvent("purchase")
        onPurchase()
    }
)

これだけです。

ViewModelを経由する理由はありません。

 

🧑🏻‍💻 ではViewModelで送るべきケースは?

もちろんあります。

例えば


purchaseRepository.purchase()

analytics.logPurchase(
    price,
    currency
)

購入成功後に

- 金額
- 商品ID
- 購入結果

など

Business Logicの結果

を送る場合です。

この情報はUIでは分かりません。

このようなAnalyticsはViewModelやUseCaseから送るべきです。

 

🧑🏻‍💻 判断基準

 

🧑🏻‍💻 一つの基準

次の質問をすると判断しやすくなります。

このイベントはUIだけで完結しているか?

YESなら

Composeから直接送る。

NOなら

ViewModelやUseCaseから送る。

これだけです。

 

🧑🏻‍💻 まとめ

Composeでは、副作用を扱うためのAPIが最初から用意されています。

Google Analyticsのような「UIで何が起きたか」を記録する処理は、その場で副作用として送るほうがシンプルです。

一方で、ビジネスロジックの結果やRepositoryの処理結果に基づくAnalyticsは、ViewModelやUseCaseが適切な責務を持ちます。

MVVMは「すべての処理をViewModel経由にする」ための設計ではありません。

Analyticsを送る場所も、「誰がその情報を知っているか」で決めるべきです。


Related Categories :  AndroidJetpackComposeKotlinRecommended