Slide 1

Slide 1 text

AWAの フルリニューアルを支えた アーキテクチャ 2019/03/26 CA.apk #7 Keita Kagurazaka

Slide 2

Slide 2 text

AWAについて ● 定額制音楽ストリーミングサービス ● 競合にはSpotify, Apple Music, YouTube Music, LINE MUSICなどなど ● Androidアプリは2019年1月24日にフルリ ニューアルをリリース

Slide 3

Slide 3 text

なぜリニューアルしたのか ● リリースしてから3年以上にわたって機能を付け足し続けた結 果、複雑でユーザの理解が難しいプロダクトに ○ アプリを初めて使ったユーザが何をすればいいかわからない ● 開発速度を優先した結果、メンテナンスが困難なソフトウェア に ○ Fat Activity、上げられないライブラリのバージョン、作成時代によって 違う設計 etc.

Slide 4

Slide 4 text

リニューアルの目的 ● すべての機能を再整理し、新規ユーザでもわかりやすいUIに 変更、UXを最大化する ● これまで溜め込んだ技術的負債を返済し、今後の開発速度を 向上させる

Slide 5

Slide 5 text

リアーキテクチャ

Slide 6

Slide 6 text

そもそもアーキテクチャって なんのためにあるの?

Slide 7

Slide 7 text

アーキテクチャは何のためにあるか ● すべてのアーキテクチャは本質的には制約 ● 開発者ができることを減らすことで、誤りを防ぐ ● 間違えないなら制約は緩くてよい

Slide 8

Slide 8 text

アーキテクチャは何のためにあるか ● すべてのアーキテクチャは本質的には制約 ● 開発者ができることを減らすことで、誤りを防ぐ ● 間違えないなら制約は緩くてよい どのくらい自由度を犠牲にすべきかは チームとプロダクトに強く依存する

Slide 9

Slide 9 text

チームとアーキテクチャ (1) ● チームの人数が多ければ多いほど、自由度は制限したほうが 良い ○ コミュニケーションコストは人数に対して指数関数的に増加する ○ 小チームに分けるという選択肢は有力 ○ 採用も見据えて考える

Slide 10

Slide 10 text

チームとアーキテクチャ (2) ● 技術習得度が高くないメンバーが含まれる場合、自由度は制 限したほうが良い ○ 設計方針を事前レビューしてから実装してもらうくらいなら最初から枠 組みがあったほうが良い ○ 技術習得度が高いメンバーとペア / モブプログラミングをする場合は 自由度を高くできる

Slide 11

Slide 11 text

プロダクトとアーキテクチャ ● プロダクトが巨大で複雑な場合、自由度は制限したほうが良 い ○ 人数の話と基本的には同じ ○ 機能で分割するのは有力 (Androidならばmulti-module) ○ ドメインの複雑さは向き合うしかない

Slide 12

Slide 12 text

AWAのAndroidチームとアーキテクチャ ● チームは4人と小規模 ● 技術習得度は全員高く、必要な議論を躊躇わないタイプ ● プロダクトは巨大で複雑 (167画面とかある) ● 拠点が渋谷と福岡で分かれている

Slide 13

Slide 13 text

設計方針 ● レイヤードアーキテクチャを採用し、各処理をどの階層に置く かまで合意する ● ルール化したほうが良さそうならば都度議論する ● 重要度が高く、複雑な音楽再生とダウンロードについてはより 制約をきつくする ● 必要なら福岡にいく

Slide 14

Slide 14 text

設計方針 ● レイヤードアーキテクチャを採用し、各処理をどの階層に置く かまで合意する ● ルール化したほうが良さそうならば都度議論する ● 重要度が高く、複雑な音楽再生とダウンロードについてはより 制約をきつくする ● 必要なら福岡にいく ビデオ通話を常時接続する

Slide 15

Slide 15 text

方針は定まった

Slide 16

Slide 16 text

実現したいこと ● ユーザに対してローディング表示をなるべく見せないようにす るため、キャッシュを最大限に活用する ● 音楽が再生できる画面では再生状況をリアクティブに表示した い

Slide 17

Slide 17 text

実現したいこと ● ユーザに対してローディング表示をなるべく見せないようにす るため、キャッシュを最大限に活用する ● 音楽が再生できる画面では再生状況をリアクティブに表示した い CQRSアーキテクチャを採用

Slide 18

Slide 18 text

CQRS (コマンドクエリ責務分離) ● システム全体を更新系と参照系に分離する ● 更新系の操作は値を返さない ● 参照系はシステムを更新しない (副作用なし) ● 詳しくはこちら https://speakerdeck.com/kkagurazaka/cqrs-architecture-on-android

Slide 19

Slide 19 text

更新系 View ViewModel UseCase ApiClient DB Data Command ApiClient Repository Data Command ワーカースレッドで実行

Slide 20

Slide 20 text

更新系 View ViewModel UseCase ApiClient DB Data Command ApiClient Repository Data Command ● Viewからのイベントを受けてUseCaseをキック する

Slide 21

Slide 21 text

更新系 View ViewModel UseCase ApiClient DB Data Command ApiClient Repository Data Command ● DataCommandをオーケストレーションして処 理を行う ● 戻り値はCompletable

Slide 22

Slide 22 text

更新系 View ViewModel UseCase ApiClient DB Data Command ApiClient Repository Data Command ● APIからデータを取得してDBに書き込む ● 扱うEntityごとにクラスが分かれる ● 戻り値はCompletable

Slide 23

Slide 23 text

更新系 View ViewModel UseCase ApiClient DB Data Command ApiClient Repository Data Command ● Entityを保存するだけ ● トランザクションを管理する ● 戻り値はUnit

Slide 24

Slide 24 text

更新系 View ViewModel UseCase ApiClient DB Data Command ApiClient Repository Data Command ● 消えてもいいキャッシュはRealm ● 重要なデータはSQLite (Room) ● 設定系はSharedPreferences ● プロセスを跨がせないデータはon-memory

Slide 25

Slide 25 text

参照系 View ViewModel UseCase DB Data Query Repository Data Query RealmのためにUIスレッドで実行 Repository

Slide 26

Slide 26 text

参照系 View ViewModel UseCase DB Data Query Repository Data Query Repository ● DBの変更を検知してRxJavaのストリームに変 換する ● 戻り値はFlowable ● Realmの場合はRealmResults

Slide 27

Slide 27 text

参照系 View ViewModel UseCase DB Data Query Repository Data Query Repository ● 必要があればEntityを分解した値にしたり、 distinctUntilChangedしたり ● ごく一部のキャッシュしない参照のためにAPIを 叩くこともある

Slide 28

Slide 28 text

参照系 View ViewModel UseCase DB Data Query Repository Data Query Repository ● DataQueryをオーケストレーションして、Viewに 必要な情報を作る

Slide 29

Slide 29 text

参照系 View ViewModel UseCase DB Data Query Repository Data Query Repository ● UseCaseをobserveしてObservableFieldに詰 め、DataBindingでViewをリアクティブに更新 する

Slide 30

Slide 30 text

実現したいこと (再掲) ● ユーザに対してローディング表示をなるべく見せないようにす るため、キャッシュを最大限に活用する ● 音楽が再生できる画面では再生状況をリアクティブに表示した い

Slide 31

Slide 31 text

実現したいこと (再掲) ● ユーザに対してローディング表示をなるべく見せないようにす るため、キャッシュを最大限に活用する ● 音楽が再生できる画面では再生状況をリアクティブに表示した い キャッシュを書いてから画面に表示する作り バックグラウンドでデータが書き換わると画面もリアクティブに 変化する

Slide 32

Slide 32 text

制限を緩めたところ ● 本来CQRSでは更新系と参照系でEntityのクラスを分けるが、 重要度が高い再生キューとダウンロード以外は分けなかった ○ 参照系で更新操作をしないようにしよう、で事足りた ● 細かいコーディング規約は定めず、コミット前にコードフォー マットすることだけにした ○ たとえばapply派とalso派が混在しているが別に問題はなかった

Slide 33

Slide 33 text

実際やってみてどうだったか

Slide 34

Slide 34 text

リアーキテクチャしてみて ● どこに何を書いたら良いか迷わなくなった ● 責務が分かれたため、テストが書きやすくなった ● データフローがわかりやすくなったことによってメンテナンス性 が向上した ● パフォーマンスには注意

Slide 35

Slide 35 text

まとめ ● AndroidアプリをCQRSアーキテクチャでフルリニューアルした ● 不具合をほとんど出さずにすばやく開発できるようになった ● ベストなアーキテクチャはチームとプロダクトによって違う

Slide 36

Slide 36 text

Thanks!