🦴

【Flutter】小規模アプリ向けのディレクトリ構成考えてみた : Feature-first vs Screen-first

に公開

はじめに

Flutterでアプリを作るとき、ディレクトリ構成いろいろあって悩みますよね。😮‍💨

本記事では、MVVM+Riverpod を軽く紹介したうえで、代表的なディレクトリ構成パターン(Feature-first/Screen-first)を比較し、小規模アプリ向けのディレクトリ構成をご提案します。

この記事を読むと、プロジェクト規模に合わせた可読性保守性拡張性の視点で最適なフォルダ設計がわかるかなと思います。

技術スタック(MVVM+Riverpod)

※ ここでは技術スタックの紹介にとどめ、詳細実装は割愛します。

  • MVVM パターン
    • Model(データ)/ViewModel(ビジネスロジック)/View(画面)に責務を分ける設計手法。
  • Riverpod
    • 同期処理は Notifier + NotifierProvider
    • 非同期処理は AsyncNotifier + AsyncNotifierProvider

Feature-first vs Screen-first

Feature-first

lib/
└── features/
    ├── auth/
    │   ├── controllers/
    │   ├── models/
    │   ├── screens/
    │   └── services/
    └── home/
        ├── controllers/
        ├── models/
        ├── screens/
        └── services/
  • features/◯◯/screens/... と機能ごとに完結させるパターン。
  • メリット
    • 機能ごとに関連ファイルがまとまる ⇒ 変更時の影響範囲がフォルダ内で完結
    • チーム分業しやすく、機能担当ごとに衝突が減る
  • ⚠️ デメリット
    • ディレクトリ階層が深くなる ⇒ パスが長く見づらい場合がある
    • 小規模プロジェクトでは過剰に感じやすい

Screen-first

lib/
├── screens/
│   ├── login/
│   │   └── login_screen.dart
│   └── home/
│       ├── home_main.dart
│       ├── home_detail.dart
│       └── home_edit.dart
├── controllers/
├── models/
└── utils/
  • screens/◯◯/...と画面ごとに一覧にするパターン。
  • メリット
    • フラット&シンプル ⇒ 初見でも全体像が把握しやすい
    • 画面数が少ない小規模アプリに最適
  • ⚠️ デメリット
    • 機能横断的な変更時に複数箇所をまたぐ必要あり
    • テスト設計がやや面倒

Feature-first vs Screen-firstの比較表

観点 Feature-first 推奨 Screen-first 推奨
プロジェクト規模 中〜大規模、機能が複数かつ複雑 小規模、画面数が5〜10未満
チーム人数 複数チーム or 3人以上 1〜2人程度
拡張性/保守性重視
初期導入の学習コスト やや高
テスト設計 機能単位で容易 モジュール横断でやや面倒
UIデザイン主導 機能優先 画面優先

それを踏まえた小規模アプリ向けのおすすめディレクトリ構成

Feature-firstとScreen-firstのハイブリット型

lib/
├── core/
│   ├── constants.dart
│   ├── theme.dart
│   ├── utils.dart
│   └── widgets/
│       └── loading_indicator.dart
│
├── screens/
│   ├── auth/
│   │   ├── login_screen.dart
│   │   ├── login_controller.dart
│   │   └── login_model.dart
│   │
│   └── home/
│       ├── home_screen.dart
│       ├── home_controller.dart
│       ├── home_model.dart
│       └── home_widgets/
│           └── home_card.dart
│
└── utils/
    ├── auth_service.dart
    ├── firestore_service.dart
    └── analytics_service.dart

フォルダの説明

  • トップレベルフォルダはcore/ + screens/ + utils/の3つで構成
  • core/ に定数・テーマ・汎用Widgetをまとめ、重複を防止
  • screens/ 配下には画面+その ViewModel・Model・小物 Widgetのみ
  • utils/ に共通ロジック(Firebase/Analytics などの呼び出しや汎用ヘルパー)を集約

この構成だと、

  • 画面構成は浅いネストで把握しやすく、
  • ロジックやモデルの再利用性も確保でき、
  • Shared Service 方式でFirebaseなどの外部連携も一箇所にまとめられる
    などのメリットがあり、小規模アプリでも学習コストを抑えつつ、拡張の余地を残したバランスの良い設計になるかなと思います。

まとめ

  • Feature-first vs Screen-firstの比較表
観点 Feature-first 推奨 Screen-first 推奨
プロジェクト規模 中〜大規模、機能が複数かつ複雑 小規模、画面数が5〜10未満
チーム人数 複数チーム or 3人以上 1〜2人程度
拡張性/保守性重視
初期導入の学習コスト やや高
テスト設計 機能単位で容易 モジュール横断でやや面倒
UIデザイン主導 機能優先 画面優先
  • 構成パターン選びのポイント
    • 小規模&少人数 → Screen-first
    • 中〜大規模&複数チーム → Feature-first
    • 機能数は少ないが責務分離も欲しい → Feature-firstとScreen-firstのハイブリット型
  • まずはハイブリッド型から始め、必要に応じて拡張
  • ドキュメント化&チーム共有 で「なぜこの構成か」を明示し、全員が迷わない環境を整えましょう!

最後まで見ていただきありがとうございました!
参考になったなと思いましたらいいねしてくれると嬉しいです🙌

Discussion