Help us understand the problem. What is going on with this article?

iOS開発でClean Architectureを採用した際のイイ感じのディレクトリ構成とは

More than 1 year has passed since last update.

Clean Architectureを採用しているとファイル数が膨大になってしまうため、イイ感じにグルーピングして管理したいですが、レイヤ単位で分けるか画面とそれ以外で分けるか悩むと思います。(悩みました🙋)

2,3の構成を試し、その中で一番イイ感じに運用できた構成を紹介します。

その前によく見られているであろうリポジトリ※ のディレクトリ構成をパターン分けしてみました。
※「ios clean architecture」でググった際の結果とGitHub検索で出た上位結果

ディレクトリ構成のパターン

上記でさらっと挙げたように大きく2つのパターンがあると思います。
「レイヤ単位で分けているパターン」と「画面とその他で分けているパターン」です。

ここでは参考に上記の2つのパターンに分けて構成をまとめます。

以下では基本的にフォルダ名のみ記載します。
フォルダ名のみだと把握しにくいと判断したものはファイル名も記載しています。
ファイル名が記載されてないファルダの直下は同役割のファイルが全て共存していると捉えてください。

マイノリティーな命名がされているものには隣に括弧で補足しています。
(とはいえマイノリティかマジョリティかは確証がありませんのでご容赦ください。)

レイヤ単位(Data, Domain, Presentaion)で分けているパターン

├── Application
│   ├── Builder
│   └── Wireframe
├── Data
│   ├── DataStore
│   ├── Entity
│   └── Network
├── Domain
│   ├── Model
│   ├── Repository
│   └── UseCase
│       └── Translater
├── Presentation
│   ├── Presenter
│   └── UI
│       ├── Cell
│       ├── View
│       ├── ViewController
│       └── ViewModel
└── Util
├── Data
│   ├── DataType(Entity)
│   ├── Gateway(DataStore)
│   └── Repository
├── Domain
│   ├── Entity
│   ├── UseCase
│   └── ValueObject(Translator)
└── Presentation
      ├── AAA
      │   └── Adapter(Presenter)
      ├── BBB
      │   └── Adapter
      └── ViewData(Model)
├── DataLayer
│   ├── DataStore
│   │   └── Request
│   ├── Entity
│   └── Repository
├── DomainLayer
│   ├── Model
│   ├── UseCase
│   └── ValueObject(Translator)
├── PresentationLayer
│   ├── Presenter
│   │   ├── AAA
│   │   └── BBB
│   ├── Routing
│   │   ├── AAA
│   │   └── BBB
│   ├── View
│   │   ├── AAA
│   │   └── BBB
│   └── ViewModel
│       ├── AAA
│       └── BBB
└── Utility

画面とその他で分けているパターン

├── Data 
│   ├── QiitaItem
│   │   ├── QiitaItemDataStore.swift
│   │   ├── QiitaItemEntity.swift
│   │   ├── QiitaItemRepository.swift
│   │   └── QiitaItemRequest.swift
│   └── Utility
│       ├── ApiClient.swift
│       └── ArrayTransform.swift
├── Environment 
│   ├── Const.swift
│   └── UIStoryboard+Util.swift
├── Scenes 
│   ├── List // リストページ
│   │   ├── ListConfigurator.swift
│   │   ├── Domain
│   │   │   ├── ListModel.swift
│   │   │   ├── ListTranslater.swift
│   │   │   └── ListUseCase.swift
│   │   └── Presentation
│   │       ├── Cells
│   │       │   └── ListTableViewCell.swift
│   │       ├── ListPresenter.swift
│   │       ├── ListRouter.swift
│   │       └── ListViewController.swift
│   └── Utility
│       └── Dependencies.swift
└── Storybords
    └── List.Storyboard
├── Domain  // I/F
│   ├── Entries
│   └── UseCases
├── Network // Implemented
│   ├── API
│   ├── Entries
│   ├── Network
│   └── UseCases
├── Scenes
│   └── AllPosts
│       ├── PostTableViewCell.swift
│       ├── PostsNavigator.swift(Wireframe)
│       ├── PostsViewController.swift
│       └── PostsViewModel.swift
└── Utility
├── Models
│   ├── Order.swift
│   └── ManagedOrder.swift
├── Scenes
│   ├── CreateOrder
│   │   ├── CreateOrderInteractor.swift
│   │   ├── CreateOrderModels.swift
│   │   ├── CreateOrderPresenter.swift
│   │   ├── CreateOrderRouter.swift
│   │   ├── CreateOrderViewController.swift
│   │   └── CreateOrderWorker.swift
│   └── ListOrders
│       ├── ListOrderInteractor.swift
│       ├── ListOrderModels.swift
│       ├── ListOrderPresenter.swift
│       ├── ListOrderRouter.swift
│       ├── ListOrderViewController.swift
│       └── ListOrderWorker.swift
├── Services
│   ├── OrdersAPI.swift
│   └── OrdersMemStore.swift
└── Workers
    └── OrdersWorker.swift

(個人的に)イイ感じだと思った構成

上記の3つパターンを試してみましたが RxSwift+CleanArchitectureで構成をキレイにしよう - Qiita さんの構成が一番イイ感じに運用できました。

まず、1つ目のパターンだとレイヤ毎に全てのフォルダが表示されるのでプロジェクトナビゲータが嵩張ります。
又、場合にもよりますがフォルダを開閉する際も3箇所を操作しないといけないので手間がかかりました。
表示範囲や操作回数はなるべく小さくしたいのでこのパターンは好ましくありませんでした。

逆に全てを画面単位でまとめると、横断して担うDataレイヤや各種オブジェクトが何処かに偏ってしまうので流石にこれも好ましくありませんでした。

ということで最終的にData層のみ切り分ける2の構成が一番無難に運用できています。

ちなみに自分は以下のように構成しています。(2を元に記載)

├── Application
│   └── AppDelegate.swift
├── Data 
│   └── QiitaItem
│       ├── QiitaItemDataStore.swift
│       ├── QiitaItemEntity.swift
│       ├── QiitaItemRepository.swift
│       └── QiitaItemRequest.swift
├── Scenes
│   └── List
│       ├── ListBuilder.swift
│       ├── ListWireframe.swift
│       ├── Domain
│       │   ├── ListModel.swift
│       │   ├── ListTranslater.swift
│       │   └── ListUseCase.swift
│       └── Presentation
│           ├── ListPresenter.swift
│           └── View
│               ├── Cell
│               │   ├── ListTableViewCell.swift
│               │   └── ListTableViewCell.xib
│               ├── ListViewController.swift
│               └── ListViewController.storyboard
└── Utility

最後に

Clean Architectureと括っても、+αでBuilderパターンやWireframe、Routing、一部にMVVMを採用していたり、プロジェクト(≒人)によって色々な実装方法や細分化があるので結局これといったベストプラクティスはないと思いました。

例えば、 まだiOSアプリのArchitecture選定で消耗してるの? - Qiita一見複雑そうな機能を持つアプリでも、1画面1APIのようなI/F設計をしている場合は、サーバ側がロジック部を担保することになるのでClean ArchitectureのようなModel層の細分化はかなり冗長になると思います の通り、1画面1API程度で採用した場合は画面毎に全てまとめたほうが余計なフォルダを開かなくて済みます。

Clean Architectureの構成に限らず、ディレクトリ構成による手間を減らすテクニックなどがあれば共有していただけると幸いです。

最後の最後に

プロジェクト内検索でファイルを開いたほうが早いことも多いのでXcodeのショートカットを覚えましょう。
ショートカットcommand + shift + o

ちなみに開いた後にcommand + shift + j を押すとプロジェクトナビゲータが移動します。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした