Flutterでよく使われるアーキテクチャやコアライブラリの選択肢【個人的まとめ】
開発の規模に応じて、使用するアーキテクチャやライブラリは変わります。今まで遭遇した様々なライブラリの中で、複数の選択肢があるものをメモしておきます。実質これ一択というものは省いています。
「ここ間違ってない?」や「こういうのもあるよ!」などの指摘は歓迎します!勉強になります 😆
アーキテクチャ
個人的には VVMR がいいと思います。シンプルでカスタマイズしやすいため、必要に応じて Clean Architecture などの細かい分け方を採用すれば良いと考えています。以下、VVMR を利用している前提で話を進めます。
DDD (Domain-Driven Design)
Eric Evans によって提唱されたアーキテクチャです。ドメインという物事の関心とそれ以外を分けることが特徴です。DDD では主に以下の 4 つに分けられ、必ず上から下に依存しなければなりません。
- User Interface
- Application
- Domain
- Infrastructure
参考:
View-ViewModel-Repository
元になっているのはwasabeefさんの flutter-architecture-blueprint です。
DDD の「上から下に依存する」という特徴を踏まえつつ、Application レイヤーを省略したものです。
個人的にはこのアーキテクチャが一番好きです。
MVVM + Repository とも言われますが、モデルの扱い方に違いがあるため、この記事では VVMR と呼ぶことにします。
ViewModel は Repository のインターフェイスに依存し、環境によって実装を切り替えることが可能です。
Model は単なるオブジェクトであり、データ操作の機能は持ちません。
実装例
wasabeef さんの blueprint を参考にします。例として、ニュース一覧ページを考えます。
newsPage(View)ではレイアウトを定義し、newsViewModelを通じて記事一覧を要求します。
newsViewModel はNewsRepositoryから情報を取得し、viewModel 内でデータを保持します。view は viewModel の変更を監視し、変更があれば画面を再描画します。
MVVM (Model-View-ViewModel)
ここではオリジナルのMVVM パターンを指します。モデルが直接データを操作する点が VVMR と異なります。バックエンドにデータを置くことが多く、外部アクセスを Model から分けたい場合には使用しません。
Model は Ruby on Rails のActive Recordをイメージしてます。
Clean Architecture
よく見るクリーンアーキテクチャの構成図に基づいています。DDD をより細かく分けたものです。実務での使用経験はないため、詳細は分かりません。
参考:
View のステート管理とライフサイクル
一長一短があるため、好みに応じて選択すると良いと思います。
個人的には React 風に書ける flutter_hooks が好みです。
StatefulWidget (Flutter オリジナル)
StatefulWidget は State を持ちます。State 内のインスタンス変数は StatefulWidget が破棄されるまで値を保持します。setState()を呼び出すと、Flutter は build メソッドを再度呼び出し、画面を再描画します。
また、ライフサイクルでは initState や dispose などのフェーズごとに処理を記述します。
参考:
flutter_hooks
flutter_hooks はステート管理とライフサイクルを React の hooks 風に書けるようにするライブラリです。Widget は StatefulWidget ではなくHookWidgetを継承します。
ステート管理にはuseStateを使用し、ライフサイクルは各コントローラーごとに記述されます。
ライフサイクルは、それぞれのコントローラーごとに記述されます。Flutter で標準で入っているコントローラーなどはすでに実装されていてそのまま使うことができます。
例えば、useAnimationControllerの initState や dispose の処理はここに書かれています。
また、毎回忘れずに書かないといけない初期化・破棄処理を隠蔽することができると言うメリットもあります。
ViewModel の実装
ViewModel にはステート管理と変更を View に通知する機能が必要です。よく使われるのは以下の 2 つです。
Riverpod
Riverpod は flutter_hooks と同じ作者のRemi 氏によるライブラリです。
例として、Todo モデルと TodosViewModel クラスを考えます。Riverpod を使用すると、viewModel に期待される機能を簡単に実現できます。
class Todo {
Todo(this.description, this.isCompleted);
final bool isCompleted;
final String description;
}
@riverpod
class TodosViewModel extends _$TodosViewModel {
@override
List<Todo> build() {
return [];
}
...
}
class TodosView extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final todos = ref.watch(todosViewModelProvider);
...
}
}
flutter_bloc
flutter_bloc はイベントを stream で viewModel に流し、更新後の state が ViewModel から View に流れる仕組みです。個人的な使用経験はありません。
参考:
flutter_bloc の基本
画面遷移
GetX
GetX は画面遷移以外にも多くの機能を提供しますが、多機能ゆえのバグに遭遇することもあります。アーキテクチャが崩壊しやすいため、使用は推奨しません。
Navigator (Flutter オリジナル)
基本的な画面遷移機能を提供します。
go_router + go_router_builder
Navigator に比べて優れている点は 2 点です。
- ネストした画面遷移を簡単に作成できます。
- 画面に必要な引数の型を指定できるため、タイプセーフに使用できます。
端末内データ
sqflite
SQL を使用する場合に適しています。
shared_preferences
単純な key-value ストアです。
flutter_secure_storage
セキュアなデータの保存に適しています。iOS ではキーチェーンを使用します。
Discussion