🙄

なぜiOS/Android開発には状態管理ライブラリがないのかをFlutterのRiverpodの機能から考える

に公開

長いタイトルになりました。
先日会社でWebエンジニアの方と話したら、

「iOS開発って状態管理ライブラリあるんですか」
「そういえばないですね」
「え! そうなんですか」

というやりとりになって、そういえばなんでだろなと思って、
他プラットフォームを調べることにしました。

ざっくりした状況

あんまり内容はないですが、調査状況はスクラップにまとめました。
そして各プラットフォームのざっくりした状況は下記の通りでした。

  • iOS/Android: ライブラリは入れず、公式の機能でやりくりするのが普通
  • Flutter: 公式のProviderがあるが、Riverpod を入れてる人が多い状況
  • Webフロント: Reduxが一番人気だが、ボイラープレートが多すぎるのを嫌い勢にもっとライトなライブラリが求められている
    • hooksでもなんとかなる
    • ライブラリ入れるなら、Jotaiが一番人気みたい
    • トレンドのイメージがあったRecoilのメンテナンスがされていないらしい

Jotaiをもうちょっと深掘りしたかったんですが、
Flutterだけでもけっこー大変だったので、この記事では主にRiverpodの機能を扱います。

Riverpodとは

https://riverpod.dev/

RiverpodはFlutterの「リアクティブなキャッシングとデータバインディングを提供するフレームワーク」とのことです。
フランスのRemi Rousselet(レミ・ルセレ)さんが作者です。
Flutter公式ではProviderというパッケージがあり、彼はそっちの開発にも関わっていました。

なぜRiverpodか

僕はFlutterが本業ではないので、正直ProviderもRiverpodもよくわかっていませんでした。
ただTwitterで見かけるFlutter界隈の人は基本的にRiverpodを採用している印象で、
むしろ公式ドキュメントではProviderが推奨されているのが意外でした。

公式ドキュメントを見ると、Providerも一通り機能がそろっていて、困ることはなさそうに見えたので、
余計になぜRiverpodが必要となるのか、モチベーションがわかりませんでした。
などと思っているところに、Riverpod側のドキュメントがあって、そこでドンピシャに解説がありました。

https://riverpod.dev/docs/from_provider/motivation

Riverpodの利点をClaudeにまとめてもらいました。

  • 複数の同じ型のプロバイダーを使用可能
    Providerでは同じ型の2つのプロバイダーが存在すると信頼性の低い動作になりますが、Riverpodではこの制限がなく、ロジックを小さな部分に分割できます。

  • より柔軟な値の発行が可能
    REST APIからデータを読み取る際など、前回の値を表示しながら新しい値をロードするような複数の値の同時発行をサポートしています。AsyncValue APIを使用して、これを簡単に実装できます。

  • プロバイダーの組み合わせが容易
    ref.watchとref.listenユーティリティを使用して、オーバーヘッドなく値を反応的に組み合わせてキャッシュできます。Providerでは同様の機能を実装するのが困難でエラーが発生しやすい状況でした。

  • より高い実行時の安全性
    Providerでよく発生するProviderNotFoundExceptionのような実行時例外を完全に防ぐことができます。

  • 効率的な状態の破棄機能
    autodisposeとkeepAliveのAPIを使用して、柔軟なキャッシング戦略を実装できます。使用されなくなった状態を自動的に破棄することが可能です。

  • 信頼性の高いパラメータ化機能
    .familyモディファイアを使用して、型安全なパラメータ化されたプロバイダーを宣言できます。Providerではこのような機能の実装は本質的に不可能です。

  • 簡単なテスト実装
    プロバイダーはデフォルトでテスト内で使用できる状態で、モック化のための便利なオーバーライドユーティリティも提供されています。

  • 直感的な副作用の処理
    ref.listenを使用して、Flutterとよく統合された形で副作用(スナックバー、モーダルなど)をトリガーできます。

  • メモリリークの防止
    動的にマウントされるプロバイダー状態に関連するメモリリークを防ぐことができます。

  • より良い状態管理とキャッシング
    全体的により優れた状態管理機能とキャッシング戦略を提供し、アプリケーションのパフォーマンスと保守性を向上させます。

基本的にはProviderの大幅な改良版がRiverpodである、という理解をしました。

なぜRiverpodは公式パッケージに入っていないのか

そんな優れたRiverpodですが、なぜ公式パッケージからハブかれているのでしょうか。
ドキュメントに書かれていますが、Riverpodの欠点として、StatelessWidget/StatefulWidgetに対する破壊的変更が含まれています。
これが受け入れられず、独立したパッケージとしてリリースになりました。

Riverpodでは ConsumerWidget/ConsumerStatefulWidget としてウィジェットの抽象クラスが定義されています。
ドキュメント読んだ印象では、作者のRousseletさんはRiverpodが公式パッケージに採用されるべきだと考えてそうですが、受け入れられていないようです。
(RiverpodもProviderのアナグラムです)

iOS/Android開発にはなぜ状態管理ライブラリがないのか

タイトルに戻って、なぜiOS/Android開発に状態管理ライブラリがないのかを考えます。
答えは「標準SDKの中に状態管理に使える機能が存在するから」だと思いました。

SwiftUIで言えば、@State, @Binding, @StateObject, @ObservedObject, @EnvironmentObject があります。
これらを適切に使えば、ボイラーテンプレートなしで、状態管理ができます。
リアクティブプログラミングがしたければCombine、通知処理が書きたければNotificationCenterが提供されています。
これらでRiverpodが実現してる機能はほぼほぼできている印象です。

Android開発は詳しくないですが、remember API というのがあるそうで、これで状態管理を行うのが推奨のようです。

https://developer.android.com/develop/ui/compose/state?hl=ja

強いて公式がサポートしてないものがあるとしたら、iOS開発においては、Reduxみたいな設計をしたい場合、その手段が提供されていません。
そのため、有志の手によってTCAというOSSのパッケージ(アーキテクチャー)が開発されています。

https://github.com/pointfreeco/swift-composable-architecture

あとReactの登場が2013年で、SwiftUIが2019年、Jetpack Composeが2021年のリリースなので、SwiftUI/Jetpack Composeは後発となります。
故にReactの試行錯誤の結果を、バージョン1.0の時点で反映できていて、洗練された状態管理機能を持っていたと思われます。

(了)

Discussion