mcpField
F
flutter-apply-architecture-best-practices

flutter-apply-architecture-best-practices

github.com/dhruvanbhalara開発3060 回インストール9 週間前に更新
リポジトリ

flutter-apply-architecture-best-practices について

flutter-apply-architecture-best-practicesは、Clean Architectureと機能別構成に基づくFlutter・Dartの実装指針を提供するスキルです。レイヤーの境界、データモデルの規約、エラー処理、新機能追加の手順を定めています。

主な機能

  1. 01Clean Architectureのレイヤー境界
  2. 02機能別のディレクトリ構成
  3. 033層データモデルの規約
  4. 04Dart 3のエラー処理パターン
  5. 05機能追加の段階的チェックリスト

活用シーン

  1. 01新しいFlutter機能の構成
  2. 02API・ドメイン・UIモデルの分離
  3. 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 層データモデルパターン

  1. API 層(ItemApiModel)

    • サーバーから受信した生のデータ構造を表します
    • API が提供するすべてのフィールドを含みます
    • API のコントラクトと正確に一致させる必要があります
  2. ドメイン層(Item)

    • 内部データモデルを表します
    • ビジネスロジックに必要なフィールドのみを含みます
    • 不要な API フィールドを削除します
  3. 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)に登録します。

コメント