ABEMAモバイルアプリのアーキテクチャと格闘する
本文の状態
日本語全文を表示中
詳細モードで約7分の本文を読めます。
同じ出来事の情報源
この情報源を基点に整理
CyberAgent Developers Blog
Source Article
元記事を日本語で読む
本文に関係しない購読案内、埋め込み通知、サイト内プロモーションは除いています。
はじめに
はじめまして!埼玉大学大学院 修士2年の 半澤 恭介 です。
2026年4月の1ヶ月間、CyberAgent 主催のインターンシップ「CA Tech JOB」に参加し、ABEMAのAndroidエンジニアとして勤務させていただきました。
この記事では、インターンシップ期間中に取り組んだことと学んだことについてご紹介します。
課題: Flux アーキテクチャからクリーンアーキテクチャベースの Kotlin Multiplatform 設計への移行
このインターンでは、既存のFluxアーキテクチャで実装されていた画面を、クリーンアーキテクチャベースのKotlin Multiplatform (KMP) 設計へ移行するというタスクに取り組みました。
本記事では、今回の移行で実際に考えた設計と、実践した開発プロセスについて紹介します。
学んだこと
アーキテクチャ全体像
ABEMAのモバイルアプリでは、画面ごとにクリーンアーキテクチャベースのKotlin Multiplatform (KMP) 設計への移行を進めており、今回の改修もこの方針に沿って進めました。KMPは、AndroidとiOSの間でロジックを共通化できる仕組みであり、どこまでを共通モジュールに置き、どこからを各Platform側に置くかを柔軟に決められるという特徴があります。

ABEMAでは、上図のように、純粋なビジネスロジックを共通モジュールに配置し、ViewModelはPlatform側(iOS/Android)に配置するという設計をとっています。UseCaseに純粋なビジネスロジックを集約させ、ViewModelはそれを呼び出す層として実装することで、Platform間でのViewModelの実装差を発生しにくくするという設計をとっています。
今回担当した画面でも、実際にiOSとAndroid間で実装に違いがあり、アプリの挙動が異なる問題が存在していました。KMPによって共通化を行うことで、OS間で仕様を確実に揃えることも可能になります。
また、UseCaseは両OSから参照される共通処理として純粋なロジックを担う層です。Platform側のViewModelを直接参照できないため、UseCaseは結果をPresenterに渡し、ViewModelがそれを受けて画面の状態を更新する形をとっています。
知っているだけだった責務の分離
インターンに参加する前は、アーキテクチャを形式的に捉えていました。「責務を分離するためにファイルを切り出す」「テストで差し替えるためにDIを用いる」といった個別のプラクティスを機械的に適用する認識に留まっており、各レイヤーが存在する理由までは十分に理解できていませんでした。
そのため、実装を進める中で、形式だけ整えても責務が混ざってしまう場面に何度か遭遇しました。
– インターフェースのKDocが、実装クラスの中身を前提とした書き方になっている
– APIリクエストのユニットテストが、ドメインオブジェクトへのマッピングまで検証してしまっていた
具体的には、それぞれ次のような形でした。
KDoc の例
kotlin
// image 抽象が具体に縛られている
interface UserRepository {
/** Room データベースからユーザーを取得する */
fun getUser(id: String): User
}
// image 抽象として閉じている
interface UserRepository {
/** 指定された ID のユーザーを取得する */
fun getUser(id: String): User
}
テストの例
kotlin
// image 責務が混ざったテスト
@Test fun getUser returns Alice() {
val response = mockApi.getUser("123")
val user = mapper.toUser(response) // ← マッピングのテストになっている
assertEquals("Alice", user.name)
}
// image 責務ごとに分けたテスト
@Test fun api returns 200() { /* ... */ }
@Test fun mapper converts response to User() { /* ... */ }
ファイルとしては分かれていても、思考としては責務が混ざっているということです。インターンを通して、形だけでなく思考のレベルでも責務を分ける感覚を、少しずつ掴むことができたと思います。
実践した開発スタイル
設計書を先に書く
開発に取り組む際、いきなり実装に入るのではなく、最初にクラス図とシーケンス図を含む設計書を作成しました。今回のような既存の Flux アーキテクチャ(注:Flux)から、クリーンアーキテクチャベースの KMP(注:Kotlin Multiplatform)設計へ移行する大規模な改修では、「どこまで責務を分解するか」「プラットフォーム境界をどこに引くか」といった方針を最初に固めておかなければ、実装中に方向性が揺らぎ、手戻りが発生しやすくなります。
実装の方針について、チームメンバーと認識を合わせて、合意をとって進めていくことで実装のリスク管理も行えた点も実務の開発プロセスとして、価値があったと思っています。
設計書先行で実際に効いたこと
- トレーナーとの実装方針の認識合わせに寄与した
実装に着手する前にクラス図・シーケンス図を用いて合意形成ができることは、大きな利点でした。実装を進めてレビューを受ける中で、考慮漏れが発生する場面はあります。しかし、共通の認識があることで相談がしやすく、大きな手戻りを発生させずに進めることができました。
- AI による半自動開発の基盤として機能した
設計書が AI のコンテキスト把握におけるドキュメントとして機能したことで、後述する Claude Code のスキル群が、そのまま設計書を起点として動作することができました。設計書がなければ、AI に渡す文脈を毎回作り直す必要が生じ、効率が大幅に低下していたと考えられます。
Claude Code を使って開発を半自動化する
インターン中は Claude Code を使用して開発を行いました。個人では使える規模に限りがあるため、この機会に AI を用いた開発プロセスを検証しました。
結果論ではありますが、設計書が十分に充実しているため、実装自体は AI を用いて機械的に進めることができました。これによって、人間の作業を「方針の判断」と「コードレビュー」に集中することができました。この開発プロセスのために、Claude Code のスキルを自作し利用しました。
具体的には、「作成した設計書を読み込み実装する」「実装したコードをレビューする」「得られた知見や進捗を設計書に更新する」という 3 つのスキルです。人間は出力されたコードを読み議論を重ねることで、ナレッジが蓄積されて AI の精度が向上していくシステムになっています。

実際にこの開発プロセスを試して感じたことは、人間のレビュー精度の影響力が非常に大きいということです。大まかに実装が合っているものは作れても、細かな実装の質を担保するためには、技術的知見が人間側に備わっていることが重要であると痛感しました。
まとめ
このインターンを通して、アーキテクチャの知見と AI 開発の検証を行うことができました。その他、社員の方との 1on1 やトレーナーとお話しする機会も非常に多く設けていただいたため、エンジニアとして仕事への向き合い方やどう学んでいくか、はたまた何気ない技術雑談まで、視野の広がる、とても充実した 1 ヶ月間でした!
最後に
1 ヶ月という短い期間ではありましたが、お世話になったトレーナーの方、人事の方、ABEMA チームの方々、ランチでお話いただいた方々、本当にありがとうございました!
今日のまとめ
AIデイリーブリーフで今日の重要ニュースをまとめ読み