はじめまして!2022年の9月の中頃にジョインしたiOSエンジニアの@komajiです。まだ歴が浅くキャッチアップしている最中ではありますが、私が担当しているスタディサプリ中学講座のiOSアプリが2022年12月現在どのような環境で開発されているのかを紹介していきます。
開発体制
スタディサプリ中学準備講座は、Web, iOS, Androidの3プラットフォームで提供しており、開発チームは以下の縦割りの3チームに分かれています。
- growthチーム: サービス全体の利用促進
- learning-encourageチーム: 学習促進
- learning-coreチーム: 学習体験の向上
iOSエンジニアは、私が所属しているgrowthチームとlearning-encourageチームに2名ずつ所属しております。learning-coreチームは前述した通り学習体験の向上を担うチームですが、ネイティブアプリにおいては学習機能をWebViewで提供しているためネイティブアプリエンジニアは所属していません。
また、弊社はフルリモートの体制となっています。主に以下のツールを活用しながらコミュニケーションを円滑に取れるように工夫しています。
開発フロー
スクラム
3チームがそれぞれスクラムチームとして独立して機能開発を進めています。スクラムの運用にチーム間での差異はありますが、全体の開発フローは同じで、プロジェクト管理ツールとしてZenHubを導入しています。growthチームでは、2週間単位でスプリントを回しており、スクラムイベントは大まかに以下のように運用しています。
- Backlog Refinement
- 見積もりはプランニングポーカーで実施。
- Sprint Plannning
- ZenHubのBoardを見ながら実施。
- Daily Meeting
- 事前にSlackに昨日やったこと・今日やること・お困りごとを各々書いておく。
- 上記とZenHubのBoardを眺めながらSprintゴール達成の妨げがないかどうかを検査する。
- Sprint中間振り返り
- Sprintの折り返し地点に実施する。
- Daily Meetingを補完する目的で実施しており、Sprint Retrospectiveとは目的が異なる。
- ZenHubのBoardを眺めながらSprintゴール達成の妨げがないかどうかを検査する。
- Sprint Retrospective
- Miroを使ってKPT形式で実施。
iOSアプリ
縦割りのチーム構成の場合には横串のコミュニケーションが必要となりますが、私たちは大まかに以下のようにして開発・リリースを進めています。
- 各チームごとにチーム内で機能のリリーススケジュールを立てて開発を進める。
- 毎週開催しているiOSエンジニアが集まる会などで各チームのリリーススケジュールを持ち寄りバージョンスケジュールを立てる。
- リリースに含める開発内容の共有・認識合わせ
- 申請日・1%公開日・100%公開日の決定
- リリースマネージャのアサイン
- リリースバージョンに必要な開発が終えたらコードフリーズしてデプロイする。
主な技術スタック
- Xcode 14.1
- Swift 5.7
- SwiftUI
- Swift Pckage Manager
- Combine, async/await
- GraphQL + Apollo
- XCTest
- CircleCI, Github Actions
- fastlane
- Danger
スタディサプリ中学講座のiOSアプリは2022年2月に新規アプリとしてリニューアルしたばかりのプロダクトということもあり、最新の技術を積極的に導入しています。
例えば、UIはFull SwiftUIで実装されています。SwiftUIに関する記事も定期的に投稿しているので、そちらも眺めてみていただけると嬉しいです。
ライブリ管理ツールはSwift Package Managerに統一されています。Swift Package Managerによるマルチモジュール化も推進し、開発の効率化を図っています。単一モジュールだとXcode Previewsが不安定になり実装後のUI確認に時間がかかってしまうことがあるので、マルチモジュール化によってこの点が解消されることが楽しみです。
アーキテクチャ
アーキテクチャはMVVM + Use Case + Repositoryを採用しています。プレゼンテーションロジックをViewから剥がすためにGUIアーキテクチャとしてMVVMを導入し、その上で、ドメインロジックを担うUse Caseやデータ層を抽象化するRepositoryを別途導入しています。Repositoryに関して、スタディサプリ中学講座はデータ層のネットワーク系にREST APIとGraphQLの2種類が存在しているため、Repositoryを導入することによるメリットが十分にあると感じています。
GraphQLの観点からは、Fragment Colocationの導入を検討しています。Fragmentとは、GraphQLのqueryを再利用できる形で切り出して定義する仕組みで、Fragment Colocationとは、このFragmentとコンポーネント(View)を同じ場所に宣言する手法です。Viewと一対一の関係になるようにqueryをFragmentとして切り出しViewと同じ場所に宣言することで、Viewとデータの対応関係が分かりやすくなるというメリットがあります。導入に際して、単一のqueryから階層的に必要なデータを取得できるようにスキーマを改善する必要があるなどの課題がありますが、更なる開発効率化に向けて取り組んでいきたいと思います。
CI/CD
全体像は上記の図のような構成となっています。様々なサービスやツールを駆使して作業を自動化しています。これにより、ミスを防止し、より開発に専念できるように努めています。
サービス
CI/CDサービスはGithub Actions + CircleCIを導入しています。元々、全社的にCircleCIを導入していましたが、GitHub Actionsが登場してからはGitHub Actionsに寄せていく方針となっています。しかし、iOSアプリ開発で利用するmacOSランナーにおいては、サポート体制や価格、性能といった観点から完全な移行ができずにいます。そのため、主にビルドやアーカイブといったようにmacOSが必要な処理はCircleCIで行い、それ以外の処理はGitHub Actionsで行うというような使い分けをしています。一部、GitHub ActionsのワークフローからCircle CIのパイプラインをAPIを経由して実行しています。とはいえ、CircleCIをやめる方針であるため、状況を見つつ他のCI/CDサービスへの移行を検討しています。
テスト
テストに関しては、Unit Test, Visual Regression Test, E2E Testを実施しており、これらの実行を自動化しています。
Unit TestはXCTestで記述しており、branchのpushをトリガーとして実行するようにしています。テストカバレッジをPull Requestにコメントするようにしているのですが、機能開発時にはUnit Testを必須としているため、現在のテストカバレッジは約88.5%と高い水準を維持できています。
Visual Regression TestはSnapshotTestingにより実施しています。こちらもUnit Test同様、branchのpushをトリガーとして実行するようにしています。
E2E TestはMagicPod で実施しています。E2E Testは毎日スケジュール実行しており、リリース前には別途実行しています。MagicPod導入の詳細は、リンクの記事をご参照いただければと思います。
デプロイなど
検証用のアプリの社内配布にはTestFlightとDeployGateを用いています。これらのサービスへのデプロイはPull Request単位でも実施できるようにしており、開発中のbranchのアプリも配布できるようにしています。
他には、Renovateによるライブラリアップデートの自動化やDangerによるコードレビューの自動化をおこなったり、不要なコードを検知したりなど、様々な作業を自動化しています。
今後も、ユーザーへの価値提供を最大化するために自動化すべき作業は積極的に自動化を検討していきたいと思います。
おわりに
スタディサプリ中学講座のiOSアプリがどのような環境で開発されているのかを紹介しました。開発環境は時間の経過とともに変わっていくものなので、今後も定期的に発信していければと思います。
スタディサプリでは、一緒に最高のプロダクトを作っていってくれる仲間を募集しています! 少しでもご興味がある方はこちらのページからご連絡ください!
https://brand.studysapuri.jp/career/category/engineer#openPositions