コネヒト開発者ブログ

コネヒト開発者ブログ

ママリiOSアプリで今年取り組んだ3つの改善について

「コネヒト Advent Calendar 2023」の20日目のブログです!

adventar.org

iOSエンジニアのyoshitakaです。 コネヒトに入社してそろそろ1年が経ちます。

コネヒトに入社してからはママリiOSアプリの開発を担当しています。

今回はママリiOSアプリで行った3つの改善をまとめました。

  1. フォルダ構成の変更
  2. 開発中アプリの配布フローの改善
  3. 画面遷移の改善

それぞれどんな課題があったか、どんな改善をしたかを紹介します。

フォルダ構成の変更

課題に感じていたこと

既存のフォルダ構成は機能追加をする際に対象となるコードが見つけにくい状況でした。

前提

  • ママリiOSアプリのアーキテクチャーはMVVMを採用している
  • View・ViewModelModelでモジュール分割している
    • 今回改善したのはView・ViewModel側のフォルダ構成

    ※ モジュール分割の取り組みについてはこちらの記事を見てください。 tech.connehito.com

どんな改善をしたか

変更前のフォルダ構成のイメージがこちらです。

App
├── ViewController
│   ├── 機能AのViewController
│   ├── 機能AのViewController
│   ├── 機能BのViewController
│   └── ...
├── View
│   ├── 機能AのView
│   ├── 機能AのView
│   ├── 機能BのView
│   ├── 機能AB共通のView
│   └── ...
└── ViewModel
    ├── 機能AのViewModel
    ├── 機能AのViewModel
    ├── 機能BのViewModel
    └── ...

アーキテクチャーがわかりやすい構成になっていると思います。

しかし、機能追加をする際に対象となるコードにたどり着くのに時間がかかっていました。

改善案は大きく二つありました。

  1. 現在のフォルダ構成の配下に機能ごとのフォルダを作る
    • メリット: 変更が少なく済む
    • デメリット: 機能ごとのコードが分散する
  2. App配下に機能ごとのフォルダ作り、機能フォルダ内でさらにViewとViewModelのフォルダを作る
    • メリット: 機能ごとのコードがまとまる
    • デメリット: フォルダ構成の変更が大きい

機能改善する際ViewとViewModelをセットで修正することがよくあるので、2のApp配下で機能ごとにフォルダ分けをすることにしました。

改善したフォルダ構成イメージがこちらです。

App
├── Features
│   ├── 機能A
│   │   ├── View:ViewController・DataSource・View置き場
│   │   └── ViewModel
│   ├── 機能B
│   ├── 機能C
│   └── ...
└── Common:共通化されたView・ViewModel置き場
    ├── View
    └── ViewModel

複数の機能で使われているものはCommonフォルダにまとめるようにしました。

フォルダ構成は好みもあるかと思いますが、整理したことで不要なファイルもお掃除でき、良い改善だったと思います。

開発中アプリの配布フローの改善

課題に感じていたこと

特定の開発中ブランチから開発中アプリのを配布する際に、CIでは実行できず、常にローカルでfastlaneを実行する必要がありました。

前提

  • CI/CDはBitriseとfastlaneを使っている
  • 開発中アプリはFirebase Distributionを使い社内に配布している
  • Firebase Distributionへの配布方法は以下の2つ
    • PullRequestをメインブランチにマージすると自動で配布される
    • ローカルでfastlaneを実行して配布する

どんな改善をしたか

CIでfastlaneのアプリ配布のワークフローを実行できるようにすることで、ローカルでのfastlane実行を不要にしました。

トリガーはGitHub Actionsを使い、ブランチを指定して実行するとBitriseのアプリ配布のワークフローが実行されるようにしました。

改善方法は別の記事にまとめております。

tech.connehito.com

この改善により、ローカル環境に依存しないアプリ配布ができるようになり、開発スピードのUPに繋がっています。

画面遷移の改善

課題に感じていたこと

アプリ全体の各ViewConrollerに画面生成と遷移のロジックが実装されていて、コードの見通しが悪く、ViewControllerの肥大化要因にもなっていました。

前提

  • 画面遷移のアーキテクチャーは採用していない
  • 各ViewControllerの任意の箇所でViewControllerの生成と遷移処理を行っている

どんな改善をしたか

画面生成と遷移処理のロジックをなるべく1箇所にまとめる仕組みを作りました。

具体的には画面生成と遷移処理部分で以下のような変更をしました。

let viewController = QuestionContainerViewController.instantiate(
    id: question.id
)
navigationController?.pushViewController(viewController, animated: true)

pushScreen(screen: .questionContainer(
    questionId: question.id
)

Screenというenumを作り、Screenの値を元にViewControllerを生成するようにしました。

enum Screen {
    case questionContainer(
        questionId: Int
    )
    ...
}

extension UIViewController {
    func makeViewController(from screen: Screen) -> UIViewController {
        switch screen {
        case .questionContainer(let questionId):
            return QuestionContainerViewController.instantiate(
                id: questionId
            )
        ...
        }
    }

    func pushScreen(screen: Screen) {
        let viewController = makeViewController(from: screen)

        self.navigationController?.pushViewController(viewController, animated: true)
    }
}

画面遷移のアーキテクチャーパターンの採用も検討しましたが、実装コストとメリットが見合わず、今回はよりライトにできる方法を採用しました。

画面遷移のアーキテクチャー検討について以前外部イベントで発表した資料がありますので、興味がある方はご覧ください。

www.docswell.com

この改善は現在も段階的に置き換えを進めているところですが、すでに実装完了している部分だけでもコードの見通しが良くなり、またテストコードも書きやすくなりました。

まとめ

どの改善も日々の開発業務のスピードを上げることができていると実感する部分が多くありました。

来年はより難易度の高い改善にも取り組めたらと思っております!