🐈

[Flutter]フォルダ構成について

2021/08/14に公開4

前提

この記事は、自分がFlutter+Freezed+Riverpodでアプリを開発する際に用いているフォルダ構成について、なぜそのような構成にしているのかを紹介した記事です。私は、アーキテクチャの深い理解が無いため、間違ったことを書いている場合はご指摘ください。
初心者でフォルダ構成をどうしていけば良いかわからない人などは、参考程度に読んでください。

フォルダ構成について

MVVMのような構成

厳密に言うとMVVMとは違うのですが、その要素を取り入れているため、主な枠組みとしてMVVMライクだと思っています。

各フォルダの紹介


自分は上記の画像のようなフォルダ構成を使用しています。

components

様々なファイルで使うwidgetなどが入っていて、部品が入っているイメージです。

firebase

Firebase関係のファイルが入っています。
こちらはFirebaseを使用していない場合は必要ないため省略。

model

MVCなど、一般的にはmodelはデータ周りすべて指す事が多いですが、私は各データの定義などのが入るようにしています。Freezedを使用したファイルなどです。

repository

APIやFirestoreなどの外部への通信系の処理や、パッケージの処理をこちらに入れています。

screen

各画面ごとのファイルを入れています。

state

Riverpodを使用しているので、StreamProviderやStateNotifierProviderなど、どの画面でも参照できるstateを入れています。

utility

便利なメソッド群です。

view_model

View(Screen)とModel(repository)との間をつなぐようなファイルを入れています。

このフォルダ構成においての各役割とつながり

MVVMライクにしていますが、上記のmodel説明のように、modelはただのデータ定義を行っているフォルダに過ぎません。ですので、主な処理はrepositoryに固まってきます。基本的にViewModelやRepositoryはメソッドの集まりで、実際にView(Screen)で表示されるものはStateです。
イメージとしては以下になります。

なぜこのフォルダ構成なのか

よくRiverpodを使用する際に、1画面に1Stateのようにするのを見かけます。例えば、home画面の実装をする際に、homeStateを作成するなど。
この方法をとった場合は、もう少しフォルダの数が少なくフォルダ構成自体は簡単に見えるかもしれません。しかし、私はこの方法が良いとあまり思いません。あくまでもStateはひとまとまりのデータを指すべきだと思います。例えば、User, Todoなど。
自分のフォルダ構成では、ScreenとViewModelでは、各画面毎にファイルを作成します。また、Repository, Model, Stateではデータの塊ごとにファイルを作成します。
例えば、home画面を作成する際にUserとTodoという情報が必要だと仮定します。

  • home_screen
  • home_view_model
  • user_model
  • user_repository
  • user_state
  • todo_model
  • todo_repository
  • todo_state
    このようにファイルを作成していきます。
    home_view_modelでuser_repositoryとtodo_repositoryの処理をhome_screenで使いやすいように加工し、home_screenでhome_view_model, user_state, todo_stateを使用します。こうすることで各役割がはっきりし、各画面でメソッドをview_modelにまとめることもできます。

最後に

自分のフォルダ構成についてまとめてみましたが、文章でまとめるのは難しく伝えたいことがうまく伝えられていない気がします😓
この記事は、もっとわかりやすく修正していきたいので、ご指摘や質問などありましたら、Twitterかコメントにお願いします。

Discussion

miyaken12miyaken12

よくRiverpodを使用する際に、1画面に1Stateのようにするのを見かけます。例えば、home画面の実装をする際に、homeStateを作成するなど。
この方法をとった場合は、もう少しフォルダの数が少なくフォルダ構成自体は簡単に見えるかもしれません。しかし、私はこの方法が良いとあまり思いません。あくまでもStateはひとまとまりのデータを指すべきだと思います。

状態管理という設計構造だと同じくViewModelという構造は違和感がありました (特にRiverpodの場合)
Riverpodの場合は基本、責務の範囲を考慮し状態値の粒度を小さく分けそれぞれで状態管理を自分も最近やってます👍

nickynicky

コメントありがとうございます😄
Riverpodの利点を最大限に活かすなら、おっしゃられている通りの方法が良いと僕も思います!
ただ、その方法だと自分の場合Viewが大きくなりすぎたり、どこに処理を書いたらいいのかわからなくなるとが多いので今回はViewModelを採用しました!
次回は、miyaken12さんがおっしゃるような、Riverpodらしい設計ができればなと思います!

masato_is_a_ snakemasato_is_a_ snake

例えばバリデーションやその他複雑な条件分岐等のrepository以外のビジネスロジックの場合は、このアーキテクチャの場合だとmodelに記載すべきなのでしょうか?

nickynicky

その場合はmodelに記載して良いと考えています。どうしても、画面などに属さないビジネスロジックはでてくるものですので!!