[iOS] Swift Package Managerで個人アプリをマルチモジュール&プロジェクト化してみた

2024/09/27に公開

はじめに

キャッチアップを兼ねて個人開発で作成していたアプリをSwift Package Managerでマルチモジュール化してみました。

公開されたアプリはこちら


ソースコードはこちら

https://github.com/Take111/HashtagCatcher

マルチモジュールにするメリット

今回はSPMでマルチモジュール化しましたが、そのことで以下のようなメリットがあると思います。

  • 依存関係がわかりやすくなる
    • Package.swiftを見れば依存関係がわかります。
  • コンフリクトの減少
    • 多人数で開発している場合は、プロジェクトファイルののコンフリクトが必ずと言っていいほど発生しますが、それが発生しにくくなります。
  • 可読性の向上
    • モジュールごとにコードを分割するため、強制的に各モジュールの責務(役割)が明確になり、可読性が向上します。

(プロジェクトファイルのコンフリクトについてはXcodeGenを導入することで防ぐことはできますが、個人的にはyamlファイルのメンテナンスコストが高いと感じています。)

マルチプロジェクトにするメリット

さらに今回は環境ごとにプロジェクトファイルを用意するマルチプロジェクトを採用しました。


環境ごとにプロジェクトファイルを分割している

使ってみてのメリットとしては

  • 環境ごとに1つのプロジェクトファイルなので環境設定が楽になる
    • StagingはこっちでProductionがこっちがなくなります。(散らからない)
  • アプリごとにプロジェクトファイルを分けることができそう
    • 今回は環境ごとにプロジェクトを分けましたが、一つのプロジェクト内に複数のアプリを作成することもできそう
    • 同じような機能を持ったアプリであればCoreなモジュールを使い回して、素早くリリースすることができるかも?(やったことないので未検証)

アプリの構成

アプリの構成は以下のようになっています。


各Moduleの関係図

Find Group Settings
Outline Name Module Name Description
App ProductionApp 本番環境のエントリーポイント
StagingApp 開発環境のエントリーポイント
Features FindFeature Find機能をまとめたもの
GroupFeature Group機能をまとめたもの
SettingsFeature Settings機能をまとめたもの
Core UIComponents UI周りのExtenstionやColorを定義したもの
UseCases 複数のViewModelなどで使われるものをまとめたもの
Repositories 外部またはDBにアクセスする実装をまとめたもの
Models アプリ内で使われるEntityをまとめたもの
APIService 複数のRepositoryで使われるAPI接続に関わるもの

実装時に困ったこと

  • Xcodeでプロジェクトを開いたときにSchemeをうまく認識してくれずにビルドができない
    • Xcodeの再起動
  • Package.swiftを変更して依存関係を変更しても認識されない
    • Xcodeの再起動 & Clean build

その他

UseCaseやRepositoryのDI用にswift-dependenciesを導入しました。(Test用、Preview用に注入を変更することができるのでとても使い勝手がいいです)

まとめ

ほぼ全く機能がない個人アプリだったのですんなり移行することができました。
Xcode独特の挙動に困ることもありますが、マルチモジュール化はかなり良いのではないでしょうか。

今回はまだやってないですが、Feature間の画面遷移は今の構成だとできないので考えていきたいと思っています。

参考

- この記事はuhooiさんのLokiに触発されて作りました。Speacial Thanksです!
https://github.com/uhooi/Loki

終わり

Discussion