flutter-best-practices について
Flutter 開発者向けのアーキテクチャとコーディング実践ガイドです。レイヤー分離、機能単位の構成、状態管理、テストを扱い、タスク別の資料やチェックリストも用意しています。
主な機能
- 01UI とデータレイヤーの分離
- 02機能単位でのコード整理
- 03不変で明示的な状態の設計
- 04モダンな Dart コーディングの実践
- 05タスクに応じたアーキテクチャ資料の参照
- 06機能追加とコードレビューのチェックリスト
活用シーン
- 01アプリのアーキテクチャとフォルダー構成の計画
- 02機能や画面の追加
- 03Flutter コードとテストのレビュー
- 04複数チームまたは複数パッケージのプロジェクト対応
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ evanca/ flutter-ai-rules --skill flutter-best-practicesインストール後、Claude Code で/flutter-best-practicesを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/architecture-layers.mddart-coding-practices.mdenterprise-scale.mdfeature-structure.mdlocalization-package-boundaries.md詳細
Flutter のベストプラクティス
保守しやすい Flutter アプリを構築するための標準です。公式の Flutter アーキテクチャガイドと、LeanCode が 40 件以上の Flutter プロジェクト(開発者 30 人が参加した銀行アプリを含む)をリリースしてきた経験をもとにまとめています。新しいコードを書くときはこれらを適用してください。既存のコードを変更するときは、周囲のコードベースとの一貫性を優先し、黙って書き換えるのではなく、これらの標準との不一致を指摘してください。
このスキルの使い方
タスクに合ったリファレンスファイルを読んでください。複数の領域にまたがるタスク(たとえば、新機能が構成とコーディングスタイルの両方に関わる場合)は、複数のファイルを読んでください。
| タスク | 読むファイル |
|---|---|
| レイヤーの設計、ロジックの配置場所の決定、MVVM、リポジトリ/サービス | references/architecture-layers.md |
| 機能の作成/整理、フォルダー構成、状態管理の接続 | references/feature-structure.md |
| Dart/Flutter コード、ウィジェット、テスト、リンターの作成またはレビュー | references/dart-coding-practices.md |
| 複数チーム/複数パッケージのアプリ、モノレポ、ナビゲーション、ローカライズ、API コントラクト、E2E テスト | references/enterprise-scale.md |
| アプリのローカライズ設定、再利用可能な UI パッケージの文字列の管理、言語ピッカーの表示 | references/localization-package-boundaries.md |
簡単なタスク(小さなウィジェットの修正、1 行のレビューコメントなど)では、以下の基本ルールだけで十分な場合があります。
基本ルール(常に適用)
アーキテクチャ
- UI とデータを分離します。 大きく 2 つのレイヤーに分けます。UI(ビュー+ビューモデル/キュービット)とデータ(リポジトリ+サービス)です。依存関係の方向は一方通行です。
View → ViewModel → Repository → Service。下位レイヤーから上位レイヤーをインポートしてはいけません。リポジトリ同士を依存させてはいけません。 - ビューにビジネスロジックを持たせません。 ウィジェットには、表示/非表示の条件分岐、アニメーション、レイアウト、単純なルーティングロジックを含めてもかまいませんが、データを変換したり判断したりする処理を含めてはいけません。データロジックはすべて、
BuildContextにアクセスしないビューモデル(またはキュービット/ブロック)に置きます。 - レイヤーではなく機能ごとに整理します。 状態管理、ウィジェット、モデルなど、機能に必要なものはすべて 1 つの機能ディレクトリにまとめます。機能がツリー全体に散らばるようなトップレベルの
blocs/、widgets/、models/ディレクトリを作成してはいけません。 - 状態は不変かつ明示的にします。 UI の状態は、sealed/union 型(initial/inProgress/failure/ready)としてモデル化し、すべてのケースを網羅的に処理してください。スナックバーやナビゲーションなどの単発の効果は、状態ではなくイベントとして扱います。
- メリットがある場合にのみレイヤーを追加します。 まずはビューモデル → API クライアントから始めます。キャッシュ、オフライン対応、またはデータソースの統合が必要になったら、リポジトリを導入します。ユースケースを導入するのは、複数のリポジトリにまたがるロジックがある場合、ロジックが本当に複雑な場合、または複数のビューモデルで再利用する場合に限ります。
コーディング
Containerより、意図が伝わるウィジェットを優先します。Padding、SizedBox、ColoredBox、DecoratedBox、Centerを使います。これらは const にでき、役割が明確です。Containerは、複数のプロパティを同時に組み合わせる場合にのみ使用してください。- モダンな Dart を使います。 パターンマッチング(
if (x case final v?))、網羅性を備えた switch 式、レコードと分割代入、.add()ループの代わりとなるコレクションのif/for/スプレッド、冗長なasync/awaitを使わない中継用の非同期関数での式本体を活用します。 - スライバーを返すウィジェットには
Sliverを接頭辞として付けます。 これにより、誤ったスクロールコンテキストでの使用をひと目で見つけられます。 - テストで処理の流れを伝えます。 表現力のあるマッチャー(
isEmpty、throwsA、isA、completion)を使い、依存関係を最小限に抑えます。テスト用フィクスチャでは、デザインシステムのウィジェットよりも通常のText/SizedBoxを使います。キュービット/ビューモデルはウィジェットツリーから分離してテストします。 - すべての
// ignore:に、同じ行または直前の行で理由を記載します。 エラーのログには専用のerror/stackTraceパラメーターを使い、文字列補間は使用しません。
ワークフローのチェックリスト
新しい機能/画面の追加
- references/feature-structure.md を読み、 機能ディレクトリについて既存プロジェクトの規約に合わせます。
- まず状態をユニオン型として定義し、次にCubit/ビューモデルを定義してから、 ウィジェットを作成します。依存関係はコンストラクターで注入し、機能の ウィジェットサブツリー内にスコープを設定します。
- データはリポジトリまたは型付きAPIクライアントを通じて取得します。ウィジェット内で 取得してはいけません。
- UIの詳細を組み込む前に、Cubit/ビューモデルのロジックに対するユニットテストを追加します。
Flutterコードのレビュー
重要度の高い順に確認します。
- ロジックは適切なレイヤーにありますか(ルール1~2)?ビジネスロジックに
BuildContextが含まれていませんか? - 状態は不変のユニオン型としてモデル化され、すべてのケースが処理されていますか?
- 機能は自己完結していますか。それとも、別の機能の内部に踏み込んでいますか?
- ウィジェットの選択(ルール6)、モダンなDart(ルール7)、スライバーの命名(ルール8)は適切ですか?
- ロジックのテストがあり、読みやすく、依存関係は最小限ですか?
- 説明のない
// ignore:、文字列補間を使ったエラーログ、非推奨の パターンがまだ広がっていませんか?
新しいプロジェクトの開始
- レイヤーの設計図については references/architecture-layers.md を、 フォルダーのひな形については references/feature-structure.md を 読みます。
- 約2チームを超える場合、または明確に分離できるドメインがある場合は、 references/enterprise-scale.md を読み、 最初からドメインごとに1つのパッケージを設けるMelosモノレポを検討します。
- 厳格なリント(
leancode_lintまたは同等のものとカスタムルール)を早い段階で設定します。 後から導入する方がはるかにコストがかかります。
パッケージの選択肢
これらの標準が想定するデフォルトです(コードベースですでに別のものを使っている場合は、 プロジェクト内で使われている同等のものに置き換えてください)。
- 状態: ユニオン型の状態には
bloc(Cubit)+freezedを使用します。 単発のUIイベントにはbloc_presentationを使用します。 - DI: ウィジェットのサブツリー内でスコープを設定した
providerを使用します (コンパイル時の安全性がない点は、より小さな悪として受け入れます)。 - ボイラープレートの削減:
flutter_hooks - モノレポ:
melos - ローカライズ:
.arbファイルを使ったflutter_localizations+intl - リント:
leancode_lint - E2E/UIテスト:
patrol
Flutterの公式ガイドは状態管理の方式を指定していません(ChangeNotifierを使ったMVVMも問題ありません)。 重要なのはレイヤーの分離であり、パッケージではありません。根拠とトレードオフについては リファレンスファイルを参照してください。