flutter-apply-architecture-best-practices について
flutter-apply-architecture-best-practicesは、Clean Architectureと機能別構成に基づくFlutter・Dartの実装指針を提供するスキルです。レイヤーの境界、データモデルの規約、エラー処理、新機能追加の手順を定めています。
主な機能
- 01Clean Architectureのレイヤー境界
- 02機能別のディレクトリ構成
- 033層データモデルの規約
- 04Dart 3のエラー処理パターン
- 05機能追加の段階的チェックリスト
活用シーン
- 01新しいFlutter機能の構成
- 02API・ドメイン・UIモデルの分離
- 03データアクセスと依存関係の境界確認
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ dhruvanbhalara/ skills --skill flutter-apply-architecture-best-practicesインストール後、Claude Code で/flutter-apply-architecture-best-practicesを入力して読み込まれたか確認します。
詳細
技術スタック
- クロスプラットフォーム開発のための Flutter
- 主要なプログラミング言語としての Dart
- 状態管理のための bloc
- 依存性注入のための injectable
- イミュータブルなデータモデルのための Dart Mappable
- HTTP ネットワーキングのための Dio
- ローカルデータベースのための isar
- バックエンドサービスのための Firebase
クリーンアーキテクチャ
- ドメインの純粋性:
domain層は純粋な Dart でなければなりません。package:flutterのインポートは禁止です。 - 層の依存関係:
Presentation -> Domain <- Data。Data 層は Domain のインターフェースを実装します。 - Feature-First 2.0:
DataSources(外部/生データ)とRepositories(ドメインの抽象化)を厳密に分離します。
ディレクトリ構造
- 機能ベースのクリーンアーキテクチャパターン(
featureA/bloc、featureA/models、featureA/views)に従ってコードを整理します - 機能をまたぐコンポーネントは
coreディレクトリに配置します - 共有ウィジェットは
core/views/widgetsに種類別にグループ化します
3 層データモデルパターン
-
API 層(ItemApiModel)
- サーバーから受信した生のデータ構造を表します
- API が提供するすべてのフィールドを含みます
- API のコントラクトと正確に一致させる必要があります
-
ドメイン層(Item)
- 内部データモデルを表します
- ビジネスロジックに必要なフィールドのみを含みます
- 不要な API フィールドを削除します
-
UI 層(ItemUiState)
- UI レンダリングに最適化されたデータモデルを表します
- 表示のために解析・整形されたデータを含みます
- UI 固有のすべての変換を処理します
データモデルのルール
- イミュータブルな UI 状態を定義するために Dart Mappable を使用します
- 各層は独自の型定義を持つ必要があります
- UI 層は UI 状態のデータモデルを使用し、ドメインモデルや API モデルを直接使用してはいけません
- UI 状態モデルは API モデルではなくドメインモデルから派生させる必要があります
- ドメインモデルは UI 状態モデルではなく API モデルから派生させる必要があります
リポジトリと DataSource のパターン
- リポジトリはデータソース間を調整します(ドメインモデルを返します)
- データソースは生データにアクセスします(API モデルを返します)
- リポジトリは信頼できる唯一の情報源(source of truth)であるべきであり、ドメインモデルを返します
- DataSource には生の SDK/API 呼び出しのみを含める必要があります。マッピングやビジネスロジックを含めてはいけません。
- DataSource の外部でバックエンドの SDK/API を直接呼び出してはいけません
データフロー
UI Event → BLoC (emit Loading) → Repository → DataSource (API/SDK)
↓
Response → Repository (map to Domain Entity) → BLoC (emit Success/Error) → UI
Dart 3 の言語機能
- Sealed クラス: ドメインの失敗に対して
sealed classを使用し、層をまたぐ網羅的なパターンマッチングを可能にします。 - レコード: 完全なクラスを定義するのは過剰な軽量な複数値の返却にはレコードを使用します(例:
(String name, int age))。 - If-Case パターン: null チェックとバインディングには
if (value != null)よりもif (value case final v?)を優先します。 - クラス修飾子:
final、interface、base、sealedのクラス修飾子を使用して API の意図を表現します。
エラーハンドリング
- 関数型エラーハンドリング:
Either<Failure, T>またはResult<T>の sealed クラスを使用します。層の境界を越えて例外をスローしてはいけません。 - パターンマッチング: UI と BLoC において Dart 3.x の
switch式を使用して、すべての sealed クラスの状態を網羅的に処理します。 - 必要に応じてエラーをスローし、適切な境界でキャッチします
- コンテキストとともにエラーをログに記録します
- UI にはユーザーフレンドリーなエラーメッセージを表示します
- サイレント障害を避け、常にエラーを処理または伝播します
プラットフォームチャネルとネイティブ統合
- ネイティブコードへの単発の呼び出し(デバイス情報の読み取り、ネイティブ API の呼び出しなど)には
MethodChannelを使用します - ネイティブから Flutter への継続的なストリーム(センサーデータ、接続状態の変化など)には
EventChannelを使用します - すべてのチャネルコードは、該当する機能内の専用の
platform/ディレクトリに配置します - チャネル名は定数として定義します:
static const channel = MethodChannel('com.app.feature/method') - すべてのチャネル呼び出しを DataSource でラップします。BLoC や UI から
MethodChannelを直接呼び出してはいけません - チャネルを実装していないプラットフォームでは、
MissingPluginExceptionを適切に処理します - プラットフォーム固有の動作を保護するために
defaultTargetPlatformチェックを使用します
FFI (Foreign Function Interface)
- パフォーマンスが重要なネイティブ C/C++ コードには
dart:ffiを使用してください - バインディングは、明確なドキュメントを備えた別のクラスで定義してください
- 複数のパッケージ間でネイティブコードを共有する場合は、Federated Plugins を優先してください
プラットフォーム固有のコード
- 実行時のチェックには
Platform.isAndroid/Platform.isIOSを使用してください(dart:ioをインポート) - Web の場合は、
package:flutter/foundation.dartのkIsWebを使用してください - 可能な限り、手動のプラットフォームチェックよりもアダプティブウィジェット(
Switch.adaptive、Slider.adaptive)を優先してください
コーディングガイドラインとメンテナンス
- 簡潔さ: ファイルは 300 行未満、関数は 50 行未満に抑えてください。クラスのパブリックメソッドは 10 個未満に抑えてください。
- 強い型付け:
dynamicは厳格に禁止します。Object?または明示的な型を使用してください。 - ガード句: ネストを減らし可読性を向上させるために、早期リターン(例:
if (user == null) return;)を使用してください。 - 破棄可能なライフサイクル:
TextEditingController、ScrollController、FocusNode、StreamSubscription、AnimationControllerなどは、initState()でlate初期化し、dispose()で破棄する MUST があります。 - print 文の禁止:
print()は厳格に禁止します。すべてのログにはAppLoggerを使用してください。 - 再利用: 複数回使用されるウィジェットやコードブロックは、
core/views/widgetsまたはユーティリティに抽出してください。
ドキュメント
- What ではなく Why: コメントは MUST コードの動作ではなく、その根拠(意図)を説明する必要があります。
- パブリック API: パブリックなクラスとメソッドは、トリプルスラッシュ(
///)コメントでドキュメント化してください。 - 履歴: バージョン履歴や「fixed by」コメントを含めないでください。Git が信頼できる唯一の情報源です。
ワークフロー: 新機能の実装
アプリケーションに新機能を追加する際は、この順序に従ったワークフローに沿って進めてください。進捗を追跡するにはチェックリストをコピーしてください。
タスクの進捗
- ステップ 1: ドメインモデルを定義する。 Dart Mappable を使用して、機能の不変データクラスを作成します。
- ステップ 2: DataSource を実装する。 生の SDK/API 呼び出し(Dio、Isar、Firebase)を処理する DataSource クラスを作成または更新します。
- ステップ 3: Repository を実装する。 DataSource を消費し、純粋なドメインモデルを返す Repository を作成します。
- ステップ 4: BLoC/Cubit を実装する。 状態管理を作成します。必要な Repository を注入します。不変の UI 状態を公開します。
- ステップ 5: UI を実装する。 View ウィジェットを作成します。
BlocBuilderまたはBlocConsumerを使用して状態の変化を監視します。 - ステップ 6: 依存関係を注入する。 新しい DataSource、Repository、BLoC を依存性注入コンテナ(
injectable)に登録します。
コメント
Markdown 対応