Open4

iOSアプリ開発におけるベストなプロジェクトフォルダ構成の検討

kamimikamimi

全体的なフォルダ構成の検討

テクニカルロールごとにフォルダを分ける

概要

  • 採用しているアーキテクチャに沿って、分ける
    • MVVMなら、Models/Views/ViewModelsで分ける
AppName/
 ├ Models/
 │ └ Function1Model.swift
 │ └ Function2Model.swift
 ├ Views/
 │ └ Function1.swift
 │ └ Function2.swift
 └ ViewModels/
 │ └ Function1ViewModel.swift
 │ └ Function2ViewModel.swift

Pros

  • どんなアーキテクチャを採用しているのかわかりやすい

Cons

  • 特定の機能で見た時に、その機能の他のロールがプロジェクトのどこにあるかわかりづらい
  • 後からアーキテクチャを変えたい場合や、複数のアーキテクチャを採用したい場合に修正コストが高い

個人的な意見

「特定の機能で見た時に、その機能の他のロールがプロジェクトのどこにあるかわかりづらい」のデメリットが大きいので、個人的にはこのフォルダ構成には反対

参考

https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/projectstructre/breakintcomponents.md


テクニカルロールごとにフォルダを分けた上で、機能ごとに分ける

概要

  • 採用しているアーキテクチャに沿って分けて、その上で機能ごとにフォルダを分ける
    • MVVMなら、Models/Views/ViewModelsで分ける
AppName/
 ├ Models/
 │ └ Function1/
 │   └ SomeModel.swift
 │ └ Function2/
 │   └ SomeModel2.swift
 ├ Views/
 │ └ Function1/
 │   └ SomeView.swift
 │ └ Function2/
 │   └ SomeView2.swift
 └ ViewModels/
 │ └ Function1/
 │   └ SomeViewModel.swift
 │ └ Function2/
 │   └ SomeViewModel2.swift

Pros

  • どんなアーキテクチャを採用しているのかわかりやすい

Cons

  • 特定の機能で見た時に、その機能の他のロールがプロジェクトのどこにあるかわかりづらい
  • 後からアーキテクチャを変えたい場合や、複数のアーキテクチャを採用したい場合に修正コストが高い
  • 小規模アプリの場合、フォルダ構成が深いので逆に可読性が悪くなる

個人的な意見

「特定の機能で見た時に、その機能の他のロールがプロジェクトのどこにあるかわかりづらい」のデメリットが大きいので、個人的にはこのフォルダ構成には反対


機能ごとにフォルダを分ける

概要

  • アプリが提供する機能ごとにフォルダを分ける
AppName/
 ├ Function1/
 │ └ SomeView.swift
 │ └ SomeViewModel.swift
 │ └ SomeModel.swift
 ├ Function2/
 │ └ SomeView.swift
 │ └ SomeViewModel.swift
 │ └ SomeModel.swift
 ├ Function3/
 │ └ SomeView.swift
 │ └ SomeViewModel.swift
 │ └ SomeModel.swift

Pros

  • アプリにどのような機能があるか、すぐにわかる
  • 機能ごとに必要なファイルが一箇所に纏まっているので、修正がしやすい
  • 機能ごとに異なるアーキテクチャを採用することも容易にできる(そもそも複数のアーキテクチャを採用すること自体は非推奨ではあるが、アーキテクチャの移行など過渡期にはあるあるだと思う)

Cons

  • どんなアーキテクチャを使用しているか、ファイル名を見るまでわからない
  • 中小規模なアプリの場合、機能ごとのフォルダ配下にswiftファイルが直置きされると、ファイル数がかなり多くなってしまい、可読性が低い

個人的な意見

  • 「機能ごとに必要なファイルが一箇所に纏まっているので、修正がしやすい」というメリットがあるので、この方法は良いと思うが、かなりの小規模アプリ向けだと思う

機能ごとにフォルダを分けた上で、テクニカルロールごとに分ける

概要

  • アプリが提供する機能ごとにフォルダを分け、その上で採用しているアーキテクチャごとに分ける
AppName/
 ├ Function1/
 │ └ Views/
 │   └ SomeView.swift
 │ └ ViewModels/
 │   └ SomeViewModel.swift
 │ └ Models/
 │   └ SomeModel.swift
 ├ Function2/
 │ └ Views/
 │ └ ViewModels/
 │ └ Models/
 ├ Function3/
 │ └ Views/
 │ └ ViewModels/
 │ └ Models/

Pros

  • 「機能ごとにフォルダを分ける」と同じメリット
  • フォルダ構成を見れば、どのようなアーキテクチャを採用しているかすぐにわかる

Cons

  • 小規模なアプリの場合は、階層が深くなり、可読性が良くない
    • 例えばViewsやViewModelsのフォルダに1ファイルしかないくらい小規模なアプリの場合、このフォルダの分け方はtoo muchだと思う

個人的な意見

  • 上述した小規模アプリではここまでする必要はないかと思うが、中小規模アプリならこの構成でいいのではないか
kamimikamimi

共通で使用する実装の配置場所

Viewsの場合

  • 例えばColorやButtonのスタイルなどの見た目に関わる場合
    • Common>Appearancesのようなフォルダ階層を用意する?
  • 例えばキーボードを閉じるなど挙動に関わる場合
    • なんだろ、Behaviorsとか?見たことないけど。。

Assetsの場合

  • 例えば画像やlottieのアニメーションなど
    • Resourcesのようなフォルダを用意する?

設定ファイルの場合

  • 例えばInfo.plistやSetting.Bundleなど
    • 以前はSupportingFilesというフォルダがデフォルトで作成されており、その中にInfo.plistが配置されていたが、今はそれは無くなっている。無くなったのは何か理由があるはずなので、そうではないフォルダ構成がいいのではないだろうか

データ処理の場合

  • 例えば複数箇所で共通で使用するネットワーク処理など
    • Networking

すべきではないこと(個人的意見)

  • Extensions

    • 何かの拡張であることしか示していないので、そのフォルダ名は良くないと思っている
    • ユーザーは拡張であることを知りたいのではなく、それを使って何ができるのかを知りたいはずなので、それがわかるフォルダ名にすべきではないだろうか
  • Utilities

    • 人によって解釈が異なりすぎて何が配置されているかわからないので、より具体的なフォルダ名にして配置するべきではないだろうか
kamimikamimi

Viewsのフォルダ構成

フォルダ分けしない場合

Views/
 ├ ChildView1.swift
 ├ ChildView2.swift
 ├ ParentView.swift

Pros

  • 小規模アプリでファイル数が少ない場合は、階層が浅くてみやすい

Cons

  • ファイル名を工夫しない限り、どれが親Viewでどれが子Viewなのかわかりづらい
    • 特にSwiftUIの場合、どのViewも拡張子が基本.swiftになるので、なお分かりづらい
      • UIKitでViewをInterface Builderで実装する場合は、親がstoryboardで、子がxibなどになっていて拡張子を見れば比較的関係が掴みやすかったかもしれないが。

親Viewと子Viewで分類を分ける場合

Views/
 ├ Components/
 ├  ChildView1.swift
 ├  ChildView2.swift
 ├ ParentView.swift

この機能内だけで再利用するアピアランスなどがある場合は、Viewsの直下にAppearancesBehaviors?的なフォルダを設けてもいいかもしれない。

Componentsよりは、Childrenの方が直接的でわかりやすいかも?

Material Design、Atomic Designを参考にして分けるのはどうなんだろう?いいのかな 🤔

Pros

  • どれが親でどれが子Viewなのか分かりやすい

Cons

  • 親Viewに対して、子Viewが1つしかないような場合はtoo muchかも