こんにちは、PayPayフリマでAndroidやBFFを開発している松田です。
Yahoo! JAPAN Tech Conference 2019 in ShibuyaにてPayPayフリマのバックエンドとAndroidの設計や開発について話をしました。
前回のバックエンド編の記事に続き、本記事ではセッション後半のAndroid開発について紹介します。
PayPayフリマとは
バックエンド編でも触れていましたが、改めて紹介します。
https://paypayfleamarket.yahoo.co.jp
PayPayフリマはフリマに特化したサービスとして10月7日にiOS版をリリースしました。PayPayの名前がつく通り、PayPayを利用してフリマの商品をかんたんに購入でき、買い手から価格の相談をできる機能などが特徴です。
また、ヤフオク!とも連携し、ヤフオク!に出品されている固定価格商品の一部もユーザー体験に変わりなく購入できるようになっています。
開発期間や体制
PayPayフリマは購入者・出品者向けの画面など約60画面あるのですが、3カ月というかなり短い期間で開発を行い、リリースすることができました。
Androidエンジニアはアプリの開発が始まるまで約3カ月間はKotlinで実装されているバックエンドの開発をしていました。
なぜ3カ月でリリースできたのか
強くてニューゲームを実現できた
- ヤフオク!で高速&高品質な開発手法を実践していた
- ヤフオク!に近い画面構成で作ったことがある画面が多い
開発手法・基盤
ペアプログラミング
PayPayフリマの開発は、ペアプログラミングで進めました。
実装をしながら質の高いレビューができるので、コードの品質が上がります。
Pull Requestでレビューするといったレビュー工数はほぼゼロになり、ペアで実装したコードは直接本番コードにマージしています。
また、毎日ペアをローテーションするので、チーム全体での知識の共有が早く、新しいメンバーが追加された時などに、効果を発揮します。
ローテーションにより、全体仕様にも詳しくなるので、属人化しなくなります。
ヤフオク!ではXP開発を3年前から実践しており、そこでの実績をふまえてペアプログラミングを導入しました。興味ある方は以下の記事も参考に読んでみてください。
ペアプログラミングが特徴的な開発手法「Lean XP」を取り入れた「820 Labs」オープン!
Android Jetpack
Android JetpackのArchitecture Componentについて、実際に多くのライブラリを利用している検索結果画面を例に紹介します。
左がヤフオク!の検索結果画面、右がPayPayフリマの検索結果画面です。
検索クエリが更新されたら検索APIをたたき、無限スクロールで一覧表示する画面となっています。
ヤフオク!ではPayPayフリマを作る前、検索結果画面をリニューアルし、AndroidXやJetpackを導入していました。 このヤフオク!の検索結果画面の実装を参考にしたため、両者同じような実装となっています。
ヤフオク!の検索結果
ヤフオク!の検索結果画面はLifecycleやLiveData、ViewModel、Paging、Roomといったライブラリを利用しています。
処理フロー
- 画面をスクロール
- 次のページのデータをAPIで取得
- データをDatabaseに格納(NetworkとDatabaseを併用)
- LiveDataのPagedListに追加
- LiveDataの変更を検知し、PagedListAdapter更新
- 画面内にViewが表示される際にデータをバインド
PayPayフリマの検索結果
PayPayフリマでは、ヤフオク!のライブラリに加え、DataBindingとNavigationも活用しています。
データをViewにバインドする部分や画面遷移をライブラリに任せて記述コードを減らすことで、品質を保ちつつ、実装速度の高速化を実現しました。
実際にPayPayフリマの検索結果は1週間もかからずに実装を完了できました。また、同じような一覧表示系の画面は1日あれば正常系を作れるようになりました。
Android Jetpackのメリット
- 品質を保ったまま、開発を加速させることができる
- コード量が少なくなり、保守しやすいコードになる
マルチモジュール
PayPayフリマでは、約60のモジュールに分割されています。
モジュールの分け方はいろいろあると思いますので、参考になればと思います。
- app:ApplicationとActivityを1つ定義
- navigation:Fragmentの画面管理
- feature:各機能
- repository:複数featureから利用されるような情報
- remote:Retrofitでの各Endpointの定義
- database:databaseのentity定義
- core:ログインやログの機能などさまざまなfeatureから利用されるライブラリ
マルチモジュールのメリット
- マージコストが減る
- 並行開発しやすい
- モジュール間の結合度を低くできる
- モジュール間の依存関係が明確になる
- 循環依存を排除できる
DI Framework
依存性の注入とは
依存性の注入(Dependency Injection:DI)は、コンポーネント間の依存関係をコード上から排除して、オブジェクトを外部から注入できるようにするという設計思想です。
DIしない場合
DIしていないと、RepositoryはApiClientの実装クラスに依存してしまいます。
これでは、単体テストが難しく、また、仕様変更の影響が大きくなります。
DIした場合
コンストラクタで注入すると、RepositoryはApiClientImplに依存しなくなるので、 RepositoryはApiClientにMockを注入できるようになり、テストコードを記述しやすくなります。
ただ、それぞれでオブジェクトを生成したり大変です。
UseCaseやさらに上位レイヤーから注入したりと、コードも増えていきます。
Factoryクラスを作って生成を任せることで問題を軽減できるのですが、 それぞれFactoryが必要になるなどコードが増え、オブジェクトの管理なども必要となるなど、問題はまだまだあります。
DI Framework(Dagger)を使った場合
そこでDI FrameworkのDaggerを使うと、Moduleを作って注入したいApiCLientクラスに依存オブジェクトを紐づけておけば、 注入したいところで@Injectするだけで簡単に使えるようになります。
Daggerの特徴
- Googleが開発
- コンパイル時に依存性を検証し、エラーがわかる
- Annotation Processingで管理し、デバッグしやすい
DI Frameworkのメリット
- モジュール間の結合度が下がり、柔軟性向上
- モジュール間で簡単に注入でき、機能の実装に集中
- テスト/本番環境の振る舞いを変えて効率的に動作確認
まとめ
本記事で紹介したような開発手法や技術は、さまざまなカンファレンスや勉強会でも紹介されています。ただ、知っていても実際に導入が難しいことが多いと思います。
PayPayフリマで実際に導入してみたところ、開発速度や品質の向上につながることがわかりました。
普段から最新の技術をキャッチアップしておくことは大事ですし、実際に使ってみないとわからないことも多いので、少しずつでもサービスに導入していってみましょう。
今後も今回のスピードを維持したまま開発を続けていきますので、PayPayフリマの進化に期待していてください!
こちらの記事のご感想を聞かせください。
- 学びがある
- わかりやすい
- 新しい視点
ご感想ありがとうございました