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

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 を押すとプロジェクトナビゲータが移動します。


『 Swift 』Article List
Category List

Eye Catch Image
Read More

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

AWSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

CentOSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

dockerに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

GitHubに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Javaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Laravelに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Vue.jsに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。