Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up for free
Repository with Store4 [ja]
Daichi Furiya (Wasabeef)
January 17, 2020
Technology
2
1k
Repository with Store4 [ja]
Daichi Furiya (Wasabeef)
January 17, 2020
Tweet
Share
More Decks by Daichi Furiya (Wasabeef)
See All by Daichi Furiya (Wasabeef)
DevFest_2022_What_it_Takes_to_be_a_Flutter_Developer
wasabeef
0
9
FlutterKaigi 2022 Keynote
wasabeef
1
320
Flutter Hooks を使ったアプリ開発 / App Development with the Flutter Hooks
wasabeef
2
780
Flutter 2021 の振り返りと今後のアプリ開発に向けて / Looking back on Flutter 2021 and for future app development.
wasabeef
4
1.8k
Flutter Hooks, sometimes Jetpack Compose
wasabeef
2
1.4k
Skia and Skija, Skiko [ja]
wasabeef
1
1.2k
Flutter はプロダクション開発に耐えうるのか / Flutter ready for production?
wasabeef
34
11k
モバイル開発におけるクロスプラットフォームの期待と課題 / Cross-platform expectations and challenges in mobile development
wasabeef
0
290
来年に備えるために Android の知識を網羅する / Looking back on this Android year in preparation for next year.
wasabeef
17
13k
Other Decks in Technology
See All in Technology
Technologies for developing editors / Webエディタ開発を支える技術
shuta13
1
220
2023年は何する宣言
shigeruoda
0
230
データベースの発表には RDBMS 以外もありますよ
maroon1st
0
220
UIFlowの2.0がやってきた! / ビジュアルプログラミングIoTLT vol.13
you
0
210
PCI DSS に準拠したシステム開発
yutadayo
0
230
ML PM, DS PMってどんな仕事をしているの?
line_developers
PRO
1
200
データエンジニアを助けてくれるFivetranとSnowflakeの仕様&機能のご紹介
sagara
0
420
ついに来る!TypeScript5.0の新機能
uhyo
16
8.7k
プログラミング支援AI GitHub Copilot すごいの話
moyashi
0
270
エアドロップ for オープンソースプロジェクト
epicsdao
0
180
ラズパイとGASで加湿器の消し忘れをLINEでリマインド&操作
minako__ph
0
110
DID/VCを用いた自己主権型アイデンティティの実現
sbtechnight
0
370
Featured
See All Featured
Why You Should Never Use an ORM
jnunemaker
PRO
49
7.9k
What's new in Ruby 2.0
geeforr
336
30k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
318
19k
Intergalactic Javascript Robots from Outer Space
tanoku
261
26k
Build your cross-platform service in a week with App Engine
jlugia
221
17k
WebSockets: Embracing the real-time Web
robhawkes
58
6k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
217
21k
Reflections from 52 weeks, 52 projects
jeffersonlam
338
18k
Design by the Numbers
sachag
271
18k
Raft: Consensus for Rubyists
vanstee
130
5.7k
A better future with KSS
kneath
230
16k
Designing Experiences People Love
moore
130
22k
Transcript
Repository pattern with Store4 Wasabeef #shibuya_apk
About me Daichi Furiya (降矢 大地) Google Developers Expert CATS,
CyberAgent @wasabeef_jp wasabeef
Repository pattern with Store4
STORE4 - MIGRATING A LIBRARY FROM RXJAVA TO COROUTINES https://kotlinconf.com/talks/video/2019/126904/
そして、MVVM で設 計する上で、使いや すいライブラリが Jetpack には多く存 在します。 Architecture(MVVM) Activity/Fragment Repository
ViewModel LiveData Local Source Room Remote Data Source Retrofit/okHttp https://developer.android.com/jetpack/docs/guide LiveData https://developer.android.com/jetpack/docs/guide https://developer.android.com/jetpack/docs/guide Jetpack
そして、MVVM で設 計する上で、使いや すいライブラリが Jetpack には多く存 在します。 Architecture(MVVM) Activity/Fragment Repository
ViewModel LiveData Local Source Room Remote Data Source Retrofit/okHttp https://developer.android.com/jetpack/docs/guide LiveData https://developer.android.com/jetpack/docs/guide https://developer.android.com/jetpack/docs/guide Jetpack
そして、MVVM で設 計する上で、使いや すいライブラリが Jetpack には多く存 在します。 Architecture(MVVM) Activity/Fragment Repository
ViewModel LiveData Local Source Room Remote Data Source Retrofit/okHttp https://developer.android.com/jetpack/docs/guide LiveData https://developer.android.com/jetpack/docs/guide https://developer.android.com/jetpack/docs/guide Jetpack
そして、MVVM で設 計する上で、使いや すいライブラリが Jetpack には多く存 在します。 Architecture(MVVM) Activity/Fragment Repository
ViewModel LiveData Local Source Room Remote Data Source Retrofit/okHttp https://developer.android.com/jetpack/docs/guide LiveData https://developer.android.com/jetpack/docs/guide https://developer.android.com/jetpack/docs/guide Jetpack Jetpack Jetpack
ただ、Repository の実装については参 考にできるもの (iosched, plaid) はあれど Jetpack で はライブラリ化され ていません。
Architecture(MVVM) Activity/Fragment Repository ViewModel LiveData Local Source Room Remote Data Source Retrofit/okHttp https://developer.android.com/jetpack/docs/guide LiveData https://developer.android.com/jetpack/docs/guide https://developer.android.com/jetpack/docs/guide Jetpack Jetpack Jetpack ?????
Repository pattern? Activity/Fragment Repository ViewModel LiveData Local Source Room Remote
Data Source Retrofit/okHttp https://developer.android.com/jetpack/docs/guide LiveData https://developer.android.com/jetpack/docs/guide https://developer.android.com/jetpack/docs/guide Store4 そこで現在は Dropbox が主体と なって開発されてい る Store4 を使うこ とで、簡単になりそ うなので今回注目し ています。
Repository pattern?
Microsoft によると ...
引用「データソースにアクセス するために必要なロジックをカ プセル化するクラスまたはコン ポーネント。共通のデータアク セス機能を一元化し、保守性を 向上させ、ドメインモデルレイ ヤーからデータベースにアクセ スするために使用されるインフ ラストラクチャまたはテクノロ ジーを分離します。」
Repository pattern? https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/infrastructure-persistence-layer-design
Android の MVVM に合 わせて要約すると、 Repository を使うこと で、ローカルから取得す るかネットワークから取 得するかを
ViewModel が意識する必要がないよ うにします。 Repository pattern? Activity/Fragment Repository ViewModel LiveData Remote Data Source Retrofit/okHttp Local Source Room https://developer.android.com/jetpack/docs/guide LiveData https://developer.android.com/jetpack/docs/guide https://developer.android.com/jetpack/docs/guide Store4
当たり前のことですが Repository を意識しな くていいのは ViewModel から使う側 の話で、実装において は意識して書かなけれ ばなりません。 Repository
pattern? Activity/Fragment Repository ViewModel LiveData Local Source Room Remote Data Source Retrofit/okHttp https://developer.android.com/jetpack/docs/guide LiveData Store4
Repository pattern? Activity/Fragment Repository ViewModel LiveData Remote Data Source Retrofit/okHttp
https://developer.android.com/jetpack/docs/guide LiveData On Memory Store4 さらにいうと、Local Source が SQLite だけ ではなくその前に On Memory に保存・取得す る仕組みを考えだすと、 実装さらに大変になって いきます。 Local Source Room
よくある課題 ...
例えば、同じ画面に複 数の Fragment がい て、それぞれ User データを取得するため に UserRepository か
ら getUser をコールし たとします。 よくある課題 ... UserRepository#getUser() Activity A Fragment B Fragment C
よくある課題 ... UserRepository#getUser() Activity A Fragment B Fragment C そうすると、
UserRepository がシ ングルトンだとして も、それぞれがネット ワーク通信をして、 データを取得しにいき ます。
もし仮に、User データ がほとんどの場合にお いて短期間で不変な仕 組みであるなら、この ネットワーク通信を し、サーバに負荷をか けるのはもったいない かもしれません。 よくある課題
... UserRepository#getUser() Activity A Fragment B Fragment C
もしこのデータを一定 のルールものキャッ シュする仕組みがあっ たらネットワークの負 荷を減らせるかもしれ ません。 よくある課題 ... UserRepository#getUser() Activity
A Fragment B Fragment C
もしこのデータを一定 のルールものキャッ シュする仕組みがあっ たらネットワークの負 荷を減らせるかもしれ ません。 よくある課題 ... UserRepository#getUser() Activity
A Fragment B Fragment C
Store4 ...?
Store4 ...? dropbox/Store nytimes/Store
build.gradle !// Set the source & target compatibilities to 1.8
android { compileOptions { sourceCompatibility 1.8 targetCompatibility 1.8 } !!... } dependencies { !// 2020.1.17 implementation 'com.dropbox.mobile.store:store4:4.0.0-alpha01' }
StoreBuilder typealias UserName = String typealias UserId = String typealias
TimeMs = Long data class User( val id: UserId, val name: UserName, val birthday: TimeMs) val userId: UserId = "wasabeef" UserId を Key として Store で取得するイメージで簡単な説明をしていきます。
StoreBuilder val store = StoreBuilder !!... Repository に相当する Store を
StoreBuilder で実装していきます。 これは、DI で管理することになるかと思います。
StoreBuilder val store = StoreBuilder .fromNonFlow<UserId, User> { key !->
} fromNonFlow<Key, Output> に 最新のデータを取得するためメソッドコールを定義します。
StoreBuilder val store = StoreBuilder .fromNonFlow<UserId, User> { key !->
api.fetchUser(key).user } ここでは、Retrofit など Data source を使って API コールします。
StoreBuilder val store = StoreBuilder .from<UserId, User> { key !->
api.fetchUser(key) } ここでは、Data source が既に Flow 化されているのであれば fromNonFlow {} !-> from {} ͱ͍ͯͩ͘͠͞ɻ
StoreBuilder val store = StoreBuilder .fromNonFlow<UserId, User> { key !->
api.fetchUser(key).user }.persister( reader = !!..., writer = !!..., delete = !!..., ).build() データを永続化するときにどういう振る舞いを行うかを Persister として指定することができます。
StoreBuilder val store = StoreBuilder .fromNonFlow<UserId, User> { key !->
api.fetchUser(key).user }.persister( reader = db.userDao()!::load, writer = db.userDao()!::update, delete = db.userDao()!::clear ).build() もちろん Room で使うことも出来ます。
StoreBuilder val store = StoreBuilder .fromNonFlow<UserId, User> { key !->
api.fetchUser(key).user }.build() 導入初期は Persister を指定しないで、On Memory キャッシュとしてだけ 使うのを試してもいいかもしれません。
suspend fun Store.get(key) !// UserViewModel.kt viewModelScope.launch { userLiveData.value = try
{ val user = store.get("wasabeef") Result.Success(user) } catch(e: Exception) { Result.Error(e) } } StoreBuilder の Store 実装が終わっていれば、get() を使ってデータを取得します。 これは、サスペンド関数なので ViewModel の CoroutineScope 内などで行います。
suspend fun Store.fresh(key) !// UserViewModel.kt viewModelScope.launch { userLiveData.value = try
{ val user = store.fresh("wasabeef") Result.Success(user) } catch(e: Exception) { Result.Error(e) } } fresh() を使ってデータを取得することもできます。
get or fresh ? get(key) 指定されたキーを元にメモリ内または ディスクキャッシュから取得 fresh(key) キャッシュを無視して最新を取得 get
と fresh をどちらを使うかを意識しないといけないのは Repository pattern 概念としては難しいところがあるかもしれませんが … Pull-to-Refresh などの仕組みがある以上、必要なことだと思います。
MemoryPolicy デフォルトのメモリポリシーでは上限 100 個、期限 24 時間となっています。 class MemoryPolicy internal constructor(
val expireAfterWrite: Long, val expireAfterAccess: Long, val expireAfterTimeUnit: TimeUnit, private val maxSizeNotDefault: Long ) { !// expireAfterWrite = TimeUnit.HOURS.toSeconds(24), !// expireAfterTimeUnit = TimeUnit.SECONDS, !// maxSizeNotDefault = 100 }
おしまい..
Image Resources Photos: - https://unsplash.com - https://www.pexels.com - https://www.reddit.com/r/dragonquest/comments/9dm013/ new_desktop_background/
Illustrations: - http://www.chojugiga.com - https://www.irasutoya.com
twitter.com/wasabeef_jp wasabeef.jp github.com/wasabeef