Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
AWAのフルリニューアルを支えたアーキテクチャ
Search
Keita Kagurazaka
March 26, 2019
Programming
1
770
AWAのフルリニューアルを支えたアーキテクチャ
CA.apk #7
Keita Kagurazaka
March 26, 2019
Tweet
Share
More Decks by Keita Kagurazaka
See All by Keita Kagurazaka
SELECT FOR UPDATEの話
kkagurazaka
0
70
Mobileアプリのアーキテクチャ設計法
kkagurazaka
2
1.2k
原理から完全理解するDagger Hilt Migration
kkagurazaka
1
1.6k
今後のJetpackでAndroid開発はこう変わる!
kkagurazaka
16
5.8k
外部SDKのViewにマスク処理をする方法と罠
kkagurazaka
0
770
CQRS Architecture on Android
kkagurazaka
7
2.7k
suspending functionの裏側
kkagurazaka
3
410
coroutinesで非同期ページネーション
kkagurazaka
1
550
async/awaitで快適非同期ライフ
kkagurazaka
4
1.7k
Other Decks in Programming
See All in Programming
「2024年版 Kotlin サーバーサイドプログラミング実践開発」の補講 〜O/Rマッパー編〜
n_takehata
2
260
社内 LT 会を発足し、アウトプット文化を醸成させるために考えたこと・やったこと / Starting internal LT meetings and fostering an output culture
mackey0225
3
120
わかりやすい正解を捨てて、コトに向き合う - スクラムフェス金沢2024 スポンサーセッション
yusukekokubo
0
170
最古の関数型言語「Lisp」ことはじめ / lisp_in_kamiyama
uhooi
1
190
CSC307 Lecture 14
javiergs
PRO
0
220
Composing an API the *right* way (Droidcon Berlin 2024)
zsmb
1
450
ピグパーティにおけるMongoDB CommunityバージョンからAtlasへの移行事例
10969hotaka
0
130
生成AIをkintoneに連携してみた
hideg
0
230
小さな開発会社を作った理由
polidog
0
1.9k
【Go言語】ジェネリクス
tomo1227
0
170
Ruby メモリ管理 プログラミング
megmogmog1965
0
130
CSC307 Lecture 08
javiergs
PRO
0
330
Featured
See All Featured
How to train your dragon (web standard)
notwaldorf
79
5.5k
Java REST API Framework Comparison - PWX 2021
mraible
PRO
20
7.2k
The Pragmatic Product Professional
lauravandoore
29
6.1k
A Tale of Four Properties
chriscoyier
155
22k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
12
3.8k
From Idea to $5000 a Month in 5 Months
shpigford
377
46k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
662
120k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
502
140k
YesSQL, Process and Tooling at Scale
rocio
166
14k
Designing for humans not robots
tammielis
247
25k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
149
45k
Designing for Performance
lara
604
67k
Transcript
AWAの フルリニューアルを支えた アーキテクチャ 2019/03/26 CA.apk #7 Keita Kagurazaka
AWAについて • 定額制音楽ストリーミングサービス • 競合にはSpotify, Apple Music, YouTube Music, LINE
MUSICなどなど • Androidアプリは2019年1月24日にフルリ ニューアルをリリース
なぜリニューアルしたのか • リリースしてから3年以上にわたって機能を付け足し続けた結 果、複雑でユーザの理解が難しいプロダクトに ◦ アプリを初めて使ったユーザが何をすればいいかわからない • 開発速度を優先した結果、メンテナンスが困難なソフトウェア に ◦
Fat Activity、上げられないライブラリのバージョン、作成時代によって 違う設計 etc.
リニューアルの目的 • すべての機能を再整理し、新規ユーザでもわかりやすいUIに 変更、UXを最大化する • これまで溜め込んだ技術的負債を返済し、今後の開発速度を 向上させる
リアーキテクチャ
そもそもアーキテクチャって なんのためにあるの?
アーキテクチャは何のためにあるか • すべてのアーキテクチャは本質的には制約 • 開発者ができることを減らすことで、誤りを防ぐ • 間違えないなら制約は緩くてよい
アーキテクチャは何のためにあるか • すべてのアーキテクチャは本質的には制約 • 開発者ができることを減らすことで、誤りを防ぐ • 間違えないなら制約は緩くてよい どのくらい自由度を犠牲にすべきかは チームとプロダクトに強く依存する
チームとアーキテクチャ (1) • チームの人数が多ければ多いほど、自由度は制限したほうが 良い ◦ コミュニケーションコストは人数に対して指数関数的に増加する ◦ 小チームに分けるという選択肢は有力 ◦
採用も見据えて考える
チームとアーキテクチャ (2) • 技術習得度が高くないメンバーが含まれる場合、自由度は制 限したほうが良い ◦ 設計方針を事前レビューしてから実装してもらうくらいなら最初から枠 組みがあったほうが良い ◦ 技術習得度が高いメンバーとペア
/ モブプログラミングをする場合は 自由度を高くできる
プロダクトとアーキテクチャ • プロダクトが巨大で複雑な場合、自由度は制限したほうが良 い ◦ 人数の話と基本的には同じ ◦ 機能で分割するのは有力 (Androidならばmulti-module) ◦
ドメインの複雑さは向き合うしかない
AWAのAndroidチームとアーキテクチャ • チームは4人と小規模 • 技術習得度は全員高く、必要な議論を躊躇わないタイプ • プロダクトは巨大で複雑 (167画面とかある) • 拠点が渋谷と福岡で分かれている
設計方針 • レイヤードアーキテクチャを採用し、各処理をどの階層に置く かまで合意する • ルール化したほうが良さそうならば都度議論する • 重要度が高く、複雑な音楽再生とダウンロードについてはより 制約をきつくする •
必要なら福岡にいく
設計方針 • レイヤードアーキテクチャを採用し、各処理をどの階層に置く かまで合意する • ルール化したほうが良さそうならば都度議論する • 重要度が高く、複雑な音楽再生とダウンロードについてはより 制約をきつくする •
必要なら福岡にいく ビデオ通話を常時接続する
方針は定まった
実現したいこと • ユーザに対してローディング表示をなるべく見せないようにす るため、キャッシュを最大限に活用する • 音楽が再生できる画面では再生状況をリアクティブに表示した い
実現したいこと • ユーザに対してローディング表示をなるべく見せないようにす るため、キャッシュを最大限に活用する • 音楽が再生できる画面では再生状況をリアクティブに表示した い CQRSアーキテクチャを採用
CQRS (コマンドクエリ責務分離) • システム全体を更新系と参照系に分離する • 更新系の操作は値を返さない • 参照系はシステムを更新しない (副作用なし) •
詳しくはこちら https://speakerdeck.com/kkagurazaka/cqrs-architecture-on-android
更新系 View ViewModel UseCase ApiClient DB Data Command ApiClient Repository
Data Command ワーカースレッドで実行
更新系 View ViewModel UseCase ApiClient DB Data Command ApiClient Repository
Data Command • Viewからのイベントを受けてUseCaseをキック する
更新系 View ViewModel UseCase ApiClient DB Data Command ApiClient Repository
Data Command • DataCommandをオーケストレーションして処 理を行う • 戻り値はCompletable
更新系 View ViewModel UseCase ApiClient DB Data Command ApiClient Repository
Data Command • APIからデータを取得してDBに書き込む • 扱うEntityごとにクラスが分かれる • 戻り値はCompletable
更新系 View ViewModel UseCase ApiClient DB Data Command ApiClient Repository
Data Command • Entityを保存するだけ • トランザクションを管理する • 戻り値はUnit
更新系 View ViewModel UseCase ApiClient DB Data Command ApiClient Repository
Data Command • 消えてもいいキャッシュはRealm • 重要なデータはSQLite (Room) • 設定系はSharedPreferences • プロセスを跨がせないデータはon-memory
参照系 View ViewModel UseCase DB Data Query Repository Data Query
RealmのためにUIスレッドで実行 Repository
参照系 View ViewModel UseCase DB Data Query Repository Data Query
Repository • DBの変更を検知してRxJavaのストリームに変 換する • 戻り値はFlowable<Entity> • Realmの場合はRealmResults<Entity>
参照系 View ViewModel UseCase DB Data Query Repository Data Query
Repository • 必要があればEntityを分解した値にしたり、 distinctUntilChangedしたり • ごく一部のキャッシュしない参照のためにAPIを 叩くこともある
参照系 View ViewModel UseCase DB Data Query Repository Data Query
Repository • DataQueryをオーケストレーションして、Viewに 必要な情報を作る
参照系 View ViewModel UseCase DB Data Query Repository Data Query
Repository • UseCaseをobserveしてObservableFieldに詰 め、DataBindingでViewをリアクティブに更新 する
実現したいこと (再掲) • ユーザに対してローディング表示をなるべく見せないようにす るため、キャッシュを最大限に活用する • 音楽が再生できる画面では再生状況をリアクティブに表示した い
実現したいこと (再掲) • ユーザに対してローディング表示をなるべく見せないようにす るため、キャッシュを最大限に活用する • 音楽が再生できる画面では再生状況をリアクティブに表示した い キャッシュを書いてから画面に表示する作り バックグラウンドでデータが書き換わると画面もリアクティブに
変化する
制限を緩めたところ • 本来CQRSでは更新系と参照系でEntityのクラスを分けるが、 重要度が高い再生キューとダウンロード以外は分けなかった ◦ 参照系で更新操作をしないようにしよう、で事足りた • 細かいコーディング規約は定めず、コミット前にコードフォー マットすることだけにした ◦
たとえばapply派とalso派が混在しているが別に問題はなかった
実際やってみてどうだったか
リアーキテクチャしてみて • どこに何を書いたら良いか迷わなくなった • 責務が分かれたため、テストが書きやすくなった • データフローがわかりやすくなったことによってメンテナンス性 が向上した • パフォーマンスには注意
まとめ • AndroidアプリをCQRSアーキテクチャでフルリニューアルした • 不具合をほとんど出さずにすばやく開発できるようになった • ベストなアーキテクチャはチームとプロダクトによって違う
Thanks!