🤖

iOS開発でマルチモジュール実践

2022/01/11に公開

この記事では、iOS開発でマルチモジュールを実践します。

モジュールとは

モジュールとは、ソフトウェアのクラス群を意味のあるまとまりに整理することで、構成要素同士の相互依存性を低くする存在・概念です[1]。モジュールとしてまとめることにより、開発効率・メンテナンス性が上がることが期待されています。
似たような概念としてコンポーネントがあり定義も似ていますが、ここではモジュールを使用します。

モジュールの分割

モジュール分割方法ですが、この記事では例として古くからあるレイヤードアーキテクチャの考えを基点に分割していきます。
https://martinfowler.com/bliki/PresentationDomainDataLayering.html

以下のように、UI, Domain, Infrastructureに分けてみました。
レイヤードアーキテクチャ

さらに、Infrastructureを分割してみます。
詳細を分けてみた

レイヤードアーキテクチャの提唱者のMartin Flowerも指摘していますが、開発初期に大きく分けることは大変有効な反面、大規模になってくるとさらに詳細にモジュールを分けたほうが良い場合がほとんどになります。この記事では、Infrastructure層を分けて将来的に出てくるであろうメンテナンスなどの問題に対処することを考えています。

実装方法

(iOS開発の場合を説明しますが、基本的にmacOSやwatchOSでも使用できます。)
モジュールの分割方法として、Swift Package Manager(SPM)を使用します。
Swift Packages

SPMは多くはライブラリとして使用されますが、ローカルライブラリ、つまりモジュールとしても使用できます。下記の公式記事ではリポジトリを分けていますが、今回の方法ではモジュールも同じリポジトリとしています。
Editing a Package Dependency as a Local Package

  1. プロジェクトを開く
  2. File > New > Packageを選択し、モジュール名を入力します。保存場所は、プロジェクト直下にします。同じgitリポジトリとして管理します。
  3. FinderからXcodeプロジェクトに、モジュール名のフォルダごと追加します。そうすることでモジュールはプロジェクトに依存関係として追加されます。
  4. 必要に応じてPackage.swiftを修正します。例えば、モジュールに他のモジュールをdependencyに追加する場合などです。

SPMを使用することによるメリット

モジュールとしてSPMを使用することによって、幾つものメリットがあります。

  • 見通しの良さ:モジュールを分けることで、どのモジュールが何の機能を持っているのかの推測が簡単になります
  • コンフリクトの解消:それなりの人数で開発を行っていると、必ずと言って良いほどgitのコンフリクトが発生しますが、最小限に抑えられます
  • Package.swiftによる依存管理:どのモジュールがどの外部ライブラリに依存するかが明確になります
  • 開発中のビルド時間の短縮:モジュールごとのビルドとなるため、あるモジュールを変更したとしても他のモジュールの再ビルドは行われないためビルド時間の短縮になります

参考:
https://engineering.mercari.com/blog/entry/20210906-162294936e/
https://medium.com/flawless-app-stories/a-modular-architecture-in-swift-aafd9026aa99

ソースコード

実際に作成したプロジェクトはこちらになります。
https://github.com/usk-sample/MultiModuleSPMSample

ポイントは

  • UI(つまりアプリ本体)はDomainモジュールに依存しています
  • DomainモジュールはApi, Infra(DataStore)モジュールに依存しています
  • Apiモジュールは外部ライブラリとしてAlamofireに依存しています
  • UIからはApi, Infraにアクセスすることはできません
  • Domain/Infrastructure層については、Factoryパターンでそれぞれのモジュールを疎結合にしています。

テストについて

モジュール化することで、テストが少ししづらく感じるかもしれませんが、XcodeのTest Plan機能によって、モジュールも同時にテストできます。
https://bamboo-hero.com/entry/manage-tests-with-xcode-test-plans

  1. Product > Scheme > Edit Schemeを選択してからTestを選択状態にします。
  2. 「Convert to use Test Plan...」を押してTest Planを作成します。
  3. プロジェクトナビゲーションから作成されたTest Planを選択し、「+」ボタンを押します。
  4. 追加したモジュールをTest Planに追加していきます。

モジュールに対してTest Planを使うことにより、モジュールごとにテストが可能になることが最大のメリットと言えます。テストのコードも管理もモジュールごとになるので、メンテナンスもしやすくなると言えます。

トラブルシューティング

モジュールとして追加したローカルSPMパッケージ関連でビルドエラーが出る

多くの場合、Files > Reset Package CachesとXcode再起動で解消できます。解消できない場合はPackage.swiftの設定が間違っている場合がほとんどです。
モジュールを追加した最初の方で起きることがあります。

Package.swiftのdependenciesにモジュールを追加したのに認識されない

依存を追加する場合、2つの場所に依存を書く必要があります。

  • dependencies
  • targetsの中のdependencies

まとめ

Swift Package Managerを使い、マルチモジュールを実現することができました。大規模なアプリにとっては大変有用な方法ですので、どんどん使っていきたいです。また、マルチモジュール化については様々な手法があるので、今後調べてまとめていきたいと思います。

脚注
  1. https://www.itmedia.co.jp/im/articles/0912/19/news008.html ↩︎

Discussion