はじめに
初めまして。
「ビズリーチ」の求職者様向けプロダクトでAndroidアプリ開発を担当している小河原です。
私たちのチームでは、2023年7月から2024年6月にかけて、「ビズリーチ」の求職者様向けAndroidアプリの大規模な負債解消プロジェクト、通称「リアーキテクチャ」を推進していました。
このプロジェクトが完了してから約1年が経過した今、グロース開発を続ける中で、私たちはリアーキテクチャによって開発生産性が向上したのを大いに実感しています。本記事では、この大規模プロジェクトの全貌と、1年経って見えてきた新たな課題について、現場のリアルな視点でお話しします。
なぜリアーキテクチャが必要だったのか?
「ビズリーチ」のAndroidアプリが抱えていた5つの技術的課題
リアーキテクチャに着手する以前のAndroidアプリは、長年の機能開発の積み重ねにより、5つの大きな課題を抱えていました。当時のアーキテクチャは、以下の図のような構成でした。
このアプリではFluxアーキテクチャをベースとしていましたが、その実装に大きな問題を抱えていました。
- 意図せぬ副作用を生む状態管理
- 課題の核心は、Storeに実装されていた「最後に取得したデータを一時的に記憶しておく」というキャッシュの仕組みにありました。
この仕組みにより、例えばA画面で一度データを取得すると、そのデータがStoreに記憶されたままになります。その後、ユーザーがB画面に移動すると、B画面は本来自分自身でデータを取得すべきにも関わらず、Storeに記憶されていたA画面のデータをそのまま使って画面を表示できてしまったのです。
この挙動は、B画面の表示がA画面の操作に依存するという、見えない親子関係のようなものを作り出していました。ユーザーが操作する順番によって画面の表示内容が変わってしまうため、不具合の調査を非常に難しくする原因となっていました。
- 課題の核心は、Storeに実装されていた「最後に取得したデータを一時的に記憶しておく」というキャッシュの仕組みにありました。
この仕組みにより、例えばA画面で一度データを取得すると、そのデータがStoreに記憶されたままになります。その後、ユーザーがB画面に移動すると、B画面は本来自分自身でデータを取得すべきにも関わらず、Storeに記憶されていたA画面のデータをそのまま使って画面を表示できてしまったのです。
- サポートが終了したライブラリの利用
- イベントの伝播にはRxJava2とRxKotlinを利用していましたが、RxJava2はサポートが終了しており、セキュリティや安定性の観点から、早急な置き換えが求められる状態でした。
- メンテナンスされていないDIライブラリ
- DI(Dependency Injection)には、現在ではメンテナンスされていないマイナーなライブラリを採用している状態でした。これは、新たにチームに参加するメンバーの学習コストを高める一因となっていました。
- 見通しの悪いデータ加工処理
- FragmentやActivityで、画面表示用のデータに加工する処理が点在していました。これにより、ビジネスロジックとUIロジックが密結合し、コードの可読性や再利用性を著しく下げていました。
- ドキュメント化されていない仕様
- 多くの仕様がドキュメントとして残っておらず、コードそのものが唯一の仕様書となっていました。そのため、仕様に関する問い合わせのたびに、担当エンジニアがコードを解読して回答する必要があり、コミュニケーションコストが非常に高くなっていました。
これらの課題は、日々の機能開発の速度を低下させるだけでなく、品質の担保を困難にし、新しいメンバーのオンボーディングを妨げる要因となっていました。プロダクトを今後も安定して成長させていくためには、これらの技術的負債を抜本的に解消する必要があると判断し、私たちはリアーキテクチャの決断をしました。
私たちのリアーキテクチャ戦略:制約の中で最善を目指す
本プロジェクトでは、グロース開発を一時的に止め、限られた期間とリソースの中で最大の効果を出すことが求められました。そのため、「すべてを完璧に作り直す」のではなく、「プロダクトの継続的な成長を可能にする」状態をゴールと定め、取り組むべき課題に優先順位をつけました。
解決策:アーキテクチャと技術選定
1. Fluxアーキテクチャの再設計:Storeの責務とライフサイクルを見直す
既存アプリの最大の課題は、「複数の画面でStoreが共有されることによる意図せぬ副作用」でした。
この問題を解決するため、私たちはFragmentとStoreの直接的な接続を断ち切る設計に変更しました。
新しい構成では、ViewModelがStoreのデータを購読し、その情報をもとに画面の表示に必要な状態のみをまとめた「UiState」を生成して保持します。Fragmentは、ViewModelが持つそのUiStateだけを監視することで、自身のライフサイクルから外れた不要なデータ更新に影響されなくなりました。
これにより、画面間の状態が分離され、意図しない副作用を防ぐことができます。
2. 今後を見据えたモダンな技術スタックへの刷新
- 非同期処理:RxJava → Coroutines & Flow
- サポートが終了しているRxJava2からの移行は必須でした。RxJava3へのアップデートも選択肢にありましたが、私たちはAndroid開発の主流となりつつあるKotlin CoroutinesとFlowを採用しました。これは、Googleが公式に推奨していること、構造化された並行処理によってコードの可読性が向上すること、そして何よりも、今後チームに加わるメンバーがキャッチアップしやすいモダンな技術を選択することが、長期的な開発効率の向上に繋がると考えたためです。
- DI:マイナーライブラリ → Dagger Hilt
- DIライブラリには、Android開発のデファクトスタンダードであるDagger Hiltを導入しました。これにより、定型的なコードを削減できました。 また、Google公式のドキュメントなど、学習リソースも豊富なため、新メンバーのオンボーディングコストを低減できると考えました。
- 画面構成:Multi Activity → Single Activity + Navigation Component
- 既存のアプリは、ほとんどの画面がそれぞれActivityを持つ構成でした。この構成は、画面を作成するたびにActivityとFragmentの両方を実装する必要があり、開発効率が良いとは言えませんでした。また、Activity間の複雑な依存関係やライフサイクル管理は、しばしば不具合の原因となります。
- そこで、アプリ全体のActivityを一つにし、Navigation Componentを利用してFragmentを切り替えるSingle Activityへ移行しました。これにより、画面遷移の管理が一元化され、見通しが良く堅牢なUI構造を実現しました。
3. コードと画面から現状の振る舞いをドキュメント化
リアーキテクチャと並行し、これまで欠けていた「仕様のドキュメント化」にも着手しました。この作業は、PdM・QA・バックエンドチームの協力のもと、画面の見た目やコードから実際の振る舞いを一つひとつ読み解いて文章化していく地道なものでした。この取り組みを通じて、エンジニアだけでなくプランナーやQA担当者も、仕様を正確に理解できる状態を目指しました。
スコープの明確化:「やらないこと」を決める勇気
プロジェクトを期間内に完遂させるため、私たちは「やらないこと」も明確に定義しました。
- UIの全面的な作り直しは行わない
- すべての画面をJetpack Composeでフルリニューアルすることも検討しましたが、期間内に完了させるのは非現実的でした。そのため、基本的には既存のXMLレイアウトを再利用し、UIロジックとビジネスロジックの分離を最優先としました。
- ただし、画面の情報量が多く、XMLでの実装コストが高い一部の複雑な画面については、Jetpack Composeを部分的に採用し、新技術へのキャッチアップとリスク管理を両立させました。
- すべての画面をJetpack Composeでフルリニューアルすることも検討しましたが、期間内に完了させるのは非現実的でした。そのため、基本的には既存のXMLレイアウトを再利用し、UIロジックとビジネスロジックの分離を最優先としました。
- 再利用可能なコンポーネントは活かす
- 既存のコードの中でも、UIコンポーネントなど、ビジネスロジックに依存しないパーツは可能な限り再利用し、実装コストを抑えました。
リアーキテクチャから1年、グロース開発で見えてきた成果
リアーキテクチャ完了から1年、継続的なグロース開発を行う中で、私たちは多くの定量・定性的な成果を実感しています。チームメンバーからも、具体的な改善効果を実感する声が多数上がっています。
- 影響範囲の極小化と予測可能な状態管理
- Fluxアーキテクチャを本来の思想に沿って再設計したことで、状態管理が画面単位で完結するようになりました。メンバーからも「データの流れと利用されるスコープが明確に定義され、アプリの状態を管理しやすくなった」という声が上がっており、1つの画面への修正が他に影響を及ぼす心配なく、安心して開発を進められています。
- 開発生産性の向上
- ある同程度の機能実装を比較したところ、開発速度が約2倍に向上しました。これは、単にコード量が減ったからではなく、アーキテクチャ全体の見通しが良くなったことが主な要因です。
具体的には、これまで画面ごとに異なっていた実装方針が統一され、「新しい画面を作るならこのパターン」という共通認識が生まれました。Navigation Componentによる画面遷移の一元管理や、画面単位で独立した状態管理のパターンが確立されたことで、開発者は影響範囲の調査に時間を費やすことなく、ビジネスロジックの実装に集中できるようになりました。
- ある同程度の機能実装を比較したところ、開発速度が約2倍に向上しました。これは、単にコード量が減ったからではなく、アーキテクチャ全体の見通しが良くなったことが主な要因です。
- オンボーディングコストの低下
- Coroutines, Flow, Dagger Hiltといったモダンな技術スタックを採用したことで、近年のAndroid開発経験があるメンバーであれば、スムーズに開発へ参加できるようになりました。ドキュメントが整備されたことも相まって、新メンバーのキャッチアップコストは下がったと感じています。
- UI実装の高速化と開発者体験(DX)の向上
- 部分的に採用したJetpack Composeが、予想以上の効果を発揮しています。宣言的なUI構築により、XMLと比べて記述量が減り、プレビュー機能も活用することで、UIの開発・修正スピードが向上しました。
- 加えて、チーム内からは「Jetpack Composeでの開発は楽しい」というポジティブな声も聞かれます。単なる生産性向上だけでなく、開発者が楽しんで開発に取り組めるようになったことは、リアーキテクチャがもたらした重要な成果の一つです。
- 仕様の見える化
- リアーキテクチャの過程で仕様を文章化したことによる最大のメリットは、チーム全体の認識を揃えられた点です。以前は、仕様が個々のメンバーの頭の中にしか存在せず、認識のズレがコミュニケーションロスを生んでいました。ドキュメントという誰もが参照できる「正解」ができたことで曖昧さがなくなり、職種に関わらず全員が同じ理解のもとで議論できるようになりました。
今後の展望と残された課題
もちろん、このリアーキテクチャがすべてを解決したわけではありません。1年間の運用を経て、新たに取り組むべき課題が見えてきています。
- UIコンポーネントの共通化とデザインシステム
- プロジェクトの工数的な制約により、UIの全面的なCompose化は見送りました。その結果、共通UIコンポーネントの設計が十分に行えず、画面によって実装にばらつきが生まれてしまっているのが現状です。今後はデザイナーとの連携を強化し、Composeをベースとしたデザインシステムを構築していくことが大きな課題です。
- 継続的な技術のキャッチアップと挑戦
今回のリアーキテクチャでは、時間的な制約からUIを全面的にJetpack Composeへ移行することは見送りました。そのため、必然的にComposeベースの画面遷移ライブラリである「Navigation Compose」の採用も困難でした。
また、当時はNavigation3の開発が始まっていたタイミングでもあったため、今回は既存のFragmentベースであるNavigation Componentを利用するという現実的な判断を下しました。今後は、より宣言的でComposeとの親和性が高い新しいNavigationライブラリへの移行を検討しようと思います。 - アーキテクチャのさらなる探求
- 今回は「既存のFluxアーキテクチャを改善する」というアプローチを取りましたが、時間的な制約から「Flux以外のアーキテクチャ(MVIなど)をゼロベースで検討する」ことまではできませんでした。中長期的には、私たちのプロダクトにとって最適なアーキテクチャは何か、という探求も続けていきたいと考えています。
とはいえ、こうした課題を議論できるようになったこと自体、私たちが健全な状態になった証拠です。以前は、技術的負債を抱えながら、時には無理をしながらもプロダクトを成長させていた状態でした。今ではその足枷が外れ、ユーザーに良い体験をより早く届けられるという、本来あるべき開発の状態に立つことができました。
まとめ
この1年間のリアーキテクチャプロジェクトは、単に古くなったコードを新しくする作業ではありませんでした。それは、プロダクト成長とチームの未来への投資であり、いつでも新しい挑戦ができる健全な土台を手に入れるための取り組みでした。
私たちの経験を記したこの記事が、技術的負債という課題に直面している読者の皆さんにとって、何かのヒントになれば幸いです。
私たちビズリーチはDroidKaigi 2025にゴールドスポンサーとして協賛します。 この記事で紹介したようなリアーキテクチャの裏話や、モダンな環境でのAndroidアプリ開発に少しでも興味を持っていただけましたら、ぜひ現地ブースで私たち開発メンバーと直接お話ししましょう!
また、10/8には、DroidKaigi 2025 後夜祭というイベントを開催します。
https://connpass.com/event/367111
Androidチームに興味を持った方はぜひお話しましょう。
皆さんとお会いできるのを楽しみにしています。