Flutterでよく使われるアーキテクチャやコアライブラリの選択肢
開発の規模に応じて、使用するアーキテクチャやライブラリは変わります。今まで遭遇した様々なライブラリの中で、複数の選択肢があるものをメモしてます。
「ここ間違ってない?」や「こういうのもあるよ!」などあれば教えて下さい! 😆
アーキテクチャ
個人的には MVVM がいいと思います。シンプルでカスタマイズしやすいためです。
より厳格にレイヤー毎に分割したい場合は、パッケージ分割するのも一つの手だと思います。
MVVM (Model-View-ViewModel)
前まではwasabeefさんの flutter-architecture-blueprint を使用していました。
View(見た目)と ViewModel(ビジネスロジック)と Model(外部 API をリポジトリパターンで抽象化したレイヤ)に分けるシンプルな設計です。
Riverpod、Freezed、Retrofit など安定しているパッケージを採用してます。
しかし、2022 年 6 月にアーカイブされました。
パッケージが更新されておらずそのまま使用はできないのですが、アーキテクチャとしては現在でも使用できると思います。
また、Flutter 公式がこちらの MVVM パターンをベストプラクティスとして挙げているため、こちらのアーキテクチャにするのが一番安全かと思います。
しかしこちらのコードは外部ライブラリを使用せずに実装されているため、本番環境で使用するには、Riverpod、Freezed など導入する必要があります。
マルチパッケージアーキテクチャ
Kosuke Saigusa(@kosukesaigusa)さんが Omiai というアプリを開発するときに採用したアーキテクチャみたいです。
MVVM のように UI、ビジネスロジック、データ層をレイヤー毎に分けています。
しかし、それぞれをパッケージ化することで、それぞれ依存パッケージを設定することができ、ビジネスロジックに BuildContext が混ざることを避けられるのがメリットです。
DDD (Domain-Driven Design)
Eric Evans によって提唱されたアーキテクチャです。ドメインという物事の関心とそれ以外を分けることが特徴です。DDD では主に以下の 4 つに分けられ、必ず上から下に依存しなければなりません。
- User Interface
- Application
- Domain
- Infrastructure
Clean Architecture
よく見るクリーンアーキテクチャの構成図に基づいています。DDD をより細かく分けたものです。実務での使用経験はないため、詳細は分かりません。
View のステート管理とライフサイクル
flutter_hooks はまだメジャーリリースされていないので、StatefulWidget を使用するのが良さそうです。
StatefulWidget
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 に通知する機能が必要です。
Riverpod しか使用経験ありませが、BLoC パターンは勉強したい。
ChangeNotifier + Provider
Flutter フレームワークに含まれている ChangeNotifier クラスと Provider パッケージを使用します。
Riverpod
Riverpod は Provider の後継で移行することが推奨されています。
flutter_bloc
flutter_bloc はイベントを stream で ViewModel に流し、更新後の state が ViewModel から View に流れる仕組みです。
参考: flutter_bloc の基本
画面遷移
公式では小さなアプリでは Navigator
, ディープリンクや Web 対応する場合は Router が推奨されています。
GetX
GetX は画面遷移以外にも多くの機能を提供しますが、多機能ゆえのバグに遭遇することもあります。アーキテクチャが崩壊しやすいため、使用は推奨しません。
Navigator
基本的な画面遷移機能を提供します。
go_router + go_router_builder
Navigator に比べて優れている点は 2 点です。
- ネストした画面遷移を簡単に作成できます。
- 画面に必要な引数の型を指定できるため、タイプセーフに使用できます。
端末内データ
sqflite
SQL を使用する場合に適しています。
shared_preferences
単純な key-value ストアです。
flutter_secure_storage
セキュアなデータの保存に適しています。
多言語対応
業務だと何らかのサービスなりファイル形式に依存すると思うのでそれらにあったライブラリを使うと良さそうです。
個人開発の場合は1つの csv ファイルで管理し、一番感覚的に呼び出せる slang が良さそうです
パッケージ毎の機能比較はこちらを参考にさせてもらいました
flutter_localizations & intl
公式ドキュメントがあります
ARBという独自の翻訳ファイルのみ対応
ファイル分割に対応していないのでアプリが大きくなってくるとつらそうです
また、ビルダーが付いておらず context から呼び出すため、呼び出し方はAppLocalizations.of(context)!.title
で冗長になる
easy_localization
対応ファイル形式が広い
呼び出し方は t.news.errorMessage.tr()
のようになる。まだ冗長
slang
機能は easy_localization とほぼ同じ
呼び出し方は t.news.errorMessage
のように一番直感的に書ける
リンター & フォーマッター ルールセット
個人的にはキツめのルールが好み
pedantic_mono と dart_code_metrics の recommended 設定がおすすめ
flutter_lints
flutter create
するときに入ってるデフォルトの公式ルールセット
Dart 用の lints/recommended
に Flutter 推奨ルールを追加したもの
pedantic_mono
みんな大好き mono さんが作ったルールセット
デフォルトよりも強め
dart_code_metrics
有料のリンター、メトリクス計測ツール
無料分のリンタールールだけでもおすすめ
Discussion