Mercari Android チームの @tsuyogoro です。US 版 Mercari Android アプリの開発を担当しています。
この度、より一層 US マーケットにフィットしたアプリをユーザへ提供し US での成長を更に加速すべく、US 版 Mercari を刷新しました (https://play.google.com/store/apps/details?id=com.mercariapp.mercari&hl=en) 。
クライアントアプリだけでなく API サーバのアーキテクチャも変わり、文字通り大変更が施された訳ですが、本記事ではスクラッチから書き直した Android アプリにフォーカスを当て、何が変わったのか / これによってチームはどう変わったのか、という事を紹介します。
UI が大きく変わりました
Before
Mercari が US でリリースされたのが 2014 年ですので、デザインも一昔前という印象が否めません。特に US は日本よりも更に流れの速いマーケットですので、流行りのデザインもどんどん新しくなっていきます。US での成長を加速させるためには、我々もこの流れに乗ってデザインの刷新が必要であると考えました。
After
ユーザーの興味に沿ったアイテムを提示できるようにタイムラインの構成やUIを全体的に見直し、よりモダンなデザインになりました。実際の効果測定はこれからですが、Google Play Store においては概ね高評価です。
アーキテクチャが大きく変わりました
Before
Mercari Android は、2013 年に日本でリリースして以来ずっと同じコードベースで開発していました。
長い時間をかけて積み重ねてきたコードには一貫したルールがなく、MVP、MVC、MVVM…などなど約 4 年の歴史の中でその時その時で良いと思ったものを採用してきたがために、メンテナンス性が非常に悪い状態になってしまいました。新しく加わったメンバーだけでなく既存のメンバーでさえ他人のコードを読むのが一苦労で、改善しようにもリファクタするのが困難な状態でした。
After
コードのメンテナンス性が悪いことはチームの開発速度の低下を招きます。それを解決するために、チームの誰が書いても同じ設計になるよう大方針をいくつか作りました。
-
MVVM + レイヤードアーキテクチャ
- Android Framework をビュー層にのみ依存させ、ViewModel 層以降を Pure Java にする
- ロジック層、データ層の責務を明確化
- アプリの状態は Repository 層で管理され、それを ViewModel 側から参照するオブザーバーパターン
-
4 つのレイヤを定義
- Repository
- DB などに置かれているデータへのアクセスを提供する
- Service
- ロジックのみを提供し、データや状態は持たない
- Android の提供する
Service
とは別物
- ViewModel
- View を更新するためのロジックを持っており、画面 (View) にまつわるデータや状態を管理
- 必要に応じて Repository / Service へアクセス
- View
Activity
/Fragment
/View
が該当- ViewModel が発してくる signal に合わせて UI を更新
- このレイヤだけ
Context
に関連を持つ
- Repository
この大方針により、機能開発やコードレビュー/リーディングの際に「こんな感じだろう」と大枠のイメージを立てながら取り掛かれるようになり、確実に開発スピードが上がりました。
また特に大きかったのが ViewModel 層以降を Pure Java にする (Android フレームワークの依存を極小化する)
という点です。これによって ViewModel 層以降を動作確認する際、ダミーの UI を組んで一生懸命動作確認するよりも、Unit Test を書いてテストをしてしまう方が簡単かつ早いという状況を作り上げることができました。どのメンバーも自然に Unit Test を書く習慣が着きましたし、書き方が分からないケースがあっても既存のテストコードを参考にすればすぐに答えが見つかるという素晴らしいサイクルが生まれました。
使用している OSS ライブラリも大きく変わりました
上で述べたオブザーバーパターンを実現するために、利用しているライブラリも大幅に刷新/バージョンアップしました。
Before
- ネットワーク通信
- OKHttp3
- stream
- RxJava 1.x
After
- ネットワーク通信 (Retrofit によって実装コストを軽減 & stream との親和性を考慮)
- Retrofit
- OKHttp3
- stream
- その他
- Epoxy (左右上下方向にスクロールする画面でもパフォーマンスを落とさないために)
- ButterKnife (DataBinding を使った場合ビルドエラーの対処コストがツラいという経験から、ButterKnife を採用することにしました)
- Dagger2
- Lottie
もちろん他にも様々な有用なライブラリを使っています。
API が Protocol Buffers になりました
Before
- RESTful API
- parse のコードをクライアント側で毎回実装
- API 呼び出しの際のパラメータも、spec とにらめっこしながら決定
After
- Protocol Buffers
- API (サーバ) 側の実装成果物を元に、API protocol (Request / Response) の java ファイルが自動生成されるようになった
- Request のパラメータは Request のクラスに従って作るように
- Response の parser は Response のクラスに実装されており、別途実装する必要が無くなった
デザイナーとの連携を改善しました
Before
- 色の定義やスタイルの定義にルールが存在していなかったため、開発者のさじ加減で色やスタイルが増え続けていました
After
- デザイナーとエンジニアの共通言語を増やしました
- 具体的にはスタイル / フォントガイドやカラーパレットを用意し、これに合わせて
style.xml
やcolor.xml
を実装
- 具体的にはスタイル / フォントガイドやカラーパレットを用意し、これに合わせて
- デザイナーの指定するカラーが既にコードの中に存在しているため、UI の実装がかなりスムーズになりました
開発環境も若干変わりました
CI ツール
Before
- Circle CI と Travis CI の 2 段構えで、良い所を組み合わせて使っていました
- (参考) https://www.slideshare.net/tomoakiimai2/tips-for-better-ci-on-android
- 上手くワークしていましたが、とはいえメンテナンスのためにそれぞれの CI に対する知識が必要で、自分たちでハードルを高くしていました
After
- Bitrise にしました
- 自分たちで定義/設定した workflow というものを、直感的な UI で組み合わせていくスタイルでメンテナンス性が向上
- workflow の設定もかなり細かい所まで可能なので、2 段構えは止めてツールを一本化できると判断しました
コードチェックツールを追加
- Sonarqubeを導入しました
- Pull request を更新する度に Lint チェックが行われ Sonarqube が指摘してくれます
そしてチームはどうなったのか
- 大半の部分において機能の作り方が各メンバーで揃ったため、実装やコードレビューの速度がかなり向上しました
- もちろん新規メンバーのキャッチアップの速度も向上し、人材の流動性も良くなりました
- UI 以下のレイヤにおける Unit Test を書く習慣が定着し、凡ミスが減るだけでなく、Unit Test の知見がどんどん蓄積されて「書きやすいし、書いて当たり前」という状況になってきました
- RxJava2 という共通言語で会話をする事が多くなり、特に非同期処理の設計において (背景のコンテキストが予め共有されているため) 非常にコミュニケーション効率がよくなりました
まとめ
先日刷新された US Android Mercari に関し、開発観点での変化を簡単にご紹介しました。
4 Years Startup & Architecture – Speaker Deck にもありますように、我々 Mercari Android チームは日々改善を追い求め変わり続けております。
更に詳しい話を聞きたいという方は、是非下記よりご連絡下さい。お待ちしております。