SlideShare a Scribd company logo
MobileNativeFoundation/Store
meet
Store 5
mattramotar@androidDev.social
friendlyMike@androidDev.Social
Droidcon SF 2023
What is Store?
Store is a Java library for effortless, reactive data loading.
Guarantee things [you don’t want to think about] are done in the same way
What is Store?
Contracts + RELIABILITY
Guarantee things are done in the same way
What is Store?
Store
A brief history
2017 2019 2021 2022 2023
Store A brief history
2017
2019
1.0 Released Jan 17th, 2017 by NY Times
2017
2019
Why did we need Store?
We wanted to do complicated thing once
Store Version 1.0 Api
2017
2019
Store [was] a Java library for effortless, reactive data loading built with RxJava
Store<Article> Store = ParsingStoreBuilder.<BufferedSource, String>builder()
.fetcher(this::ResponseAsSource)
.persister(SourcePersisterFactory.create(context.getFilesDir())
.parser(GsonParserFactory.createSourceParser(gson, Article.class))
.open();
Barcode barcode = new Barcode("Article", "42");
store.get(barcode).subscribe(onNext, onError, onComplete)
2017
2019
Fresh == skip memory/persister go directly to fetcher
store.fresh(param).subscribe(onNext, onError, onComplete)
Fresh Skip Caches
Store Why You Need User Research
2.0 Released 1 month later (oops!)
2017
2019
3.0 Api Rxjava2
RxSingle instead of Observable
Store<Article> Store = ParsingStoreBuilder.<BufferedSource,ArticleParam, String>builder()
.fetcher(this::ResponseAsSource) //responseBody.source()
.persister(SourcePersisterFactory.create(context.getFilesDir())
.parser(GsonParserFactory.createSourceParser(gson, Article.class))
.open();
ArticleParam param = new ArticleParam("42");
store.get(param).subscribe(onNext, onError)
2017
2019
Store
Coroutines have hit stable
2017
2019
2021
Fast forward to 2019
Bye bye RxJava Hello Kotlin
2017
2019
2021
Store4
Fast forward to 2019
Hello Kotlin
2017
2019
2021
Store4
StoreBuilder.from { api.fetchSubreddit(it, "10")}
.sourceOfTruth(
reader = db.postDao()::loadPosts,
writer = db.postDao()::insertPosts,
delete = db.postDao()::clearFeed)
.cachePolicy(MemoryPolicy)
.build()
Api
Streaming as first class citizen
2017
2019
2021
fun stream(request: StoreRequest<Key>): Flow<StoreResponse>Output>>
lifecycleScope.launchWhenStarted {
store.stream(StoreRequest.cached(3, refresh = false))
.collect{ }
store.stream(StoreRequest.get(3)) .collect{ storeResponse -> }
Store4 Api
Loading|Content|Error Return Types
2017
2019
2021
Store 4
store.stream(StoreRequest.cached(key = key, refresh=true)).collect { response ->
when(response) {
is StoreResponse.Loading -> showLoadingSpinner()
is StoreResponse.Data -> {
if (response.origin == ResponseOrigin.Fetcher) hideLoadingSpinner()
updateUI(response.value)
}
is StoreResponse.Error -> {
if (response.origin == ResponseOrigin.Fetcher) hideLoadingSpinner()
showError(response.error)
}}}}
LCE
Using Store 4
Examples are from Firefly for Mastodon
https://github.com/digitalbuddha/Firefly
2017
2019
2021
You create a Store using a builder. The only requirement is to include a Fetcher which is just a typealias to a
function that returns a Flow<FetcherResult<ReturnType>>.
//build it
val store = StoreBuilder.from(
Fetcher.of { key: Unit ->
userApi.noti
fi
cations(
authHeader = " Bearer ${oauthRepository.getCurrent()}",
offset = null)
}).build()
//use it
store.stream(StoreRequest.cached(Unit, refresh = true)).map { it.dataOrNull()
}
.collect{response-> }
Fetcher as a Function
2017
2019
2021
How we get data
2017
2019
2021
Do the hard thing once
How to work with local persistence
Source of Truth
suspend fun fetcher(key:String): Token = api.createAccessToken(key)
fun sourceOfTruth = SourceOfTruth.of<String, Token, String>(
reader = {dataStore.data.map { it.currentUser?.accessToken }},
writer = { _, token -> dataStore.updateData {
it.user.copy(accessToken = token.accessToken)
}})
private val userTokenStore: Store<String, String> =
StoreBuilder.from(
fetcher = Fetcher.of { key: String -> fetcher(key) },
sourceOfTruth = sourceOfTruth
).build()
2017
2019
2021
2017
2019
2021
Store Data Flow
Fast forward to 2022
Where we were 365 days ago
2021
2022
2023
Store 4 is stable
Less than a dozen open bugs
2021
2022
2023
API was perfect
As long as you only asked me
2021
2022
2023
We had LOTS of feature requests
2021
2022
2023
That I was ignoring
2021
2022
2023
Write Support (CRUD)
2021
2022
2023
Conflict Resolution
2021
2022
2023
Fallback Mechanisms
2021
2022
2023
Support for Collections
2021
2022
2023
Store 5
Introducing
Store now with batteries included
Mission-Critical
Server-Driven Architecture
Sync
Collaboration
Upload + Download
Data Protection
Offline Access
Campaigns
Server-driven UI
Don’t worry
Store 5 is a superset of Store4
Which targets JVM/iOS/Web
How we got here…
Try 1…Adding Write Support
Rewrite what you don’t understand
Mike: What is the bene
fi
t of starting over?
Matt: Hmm
Mike: Is it easier to add old to new or new to old?
Some time later… (half hour)
Matt: safeguards will be easier to add to new
Matt: because I don’t understand old
Mike: SGTM as long as all tests are migrated, I also
don’t understand old
Matt: Sure how hard can it be?
Many days later:
Mike: ….
Matt: …
More time passes
Mike: My spider sense is tingling, I found more
gaps in new
Mike: let’s sit together and go through Store4
code
Try 2…Extending the old
Rather than boiling the ocean
Few weeks later…
Matt:Just finished last test cases everything passes
Mike: Everything?
Matt: Yup in iOS, android, JVM and JS, I took all the
work https://github.com/aclassen did and got it to pass
tests
What’sinStore5
Mutations
Con
fl
ict Resolution
Fallback Mechanisms
List Decomposition
Cache Delegation
Validation
Concepts
meet
Trails
An offline-first companion
Trails
User Story - Hiking
without Internet
Trails Architecture TLDR
Data Pulled & Pushed
Source of Truth to
Repository
Data Flow
Can’t do with Store 4
Source of Truth to
Repository
Data Flow
interface Updater<Key, Output, Response> {
suspend fun post(key: Key, value: Output):
UpdaterResult
val onCompletion:
OnUpdaterCompletion<Response>?}
Store 5 New Mutation Api
Creating an Updater (like a fetcher)
UpdatingRemoteData
sample
val updater = Updater.by(
post = { _, hike ->
try {
val latest = api.updateHike(hike)
UpdaterResult.Success.Typed(latest)
} catch (error: Throwable) {
UpdaterResult.Error.Exception(error)
}})
Store 5 Updater Factory
val mutableStore = store.asMutableStore(
updater = updater,
bookkeeper = bookkeeper)
Store 5 Mutable Store Builder
class RealHikeManager @Inject constructor(
private val mutableStore: MutableStore<Int, Hike>,
private val location:locationRepository,
private val map:mapRepository
): HikeManager {
private suspend fun track() {
combine(location.current(),
map.current()) { location, map ->
val request =
createStoreWriteRequest(location, map)
val response = mutableStore.write(request)
handleResponse(response)
}}}
Store 5 Usage of MutableStore
class RealHikeManager @Inject constructor(
private val mutableStore: MutableStore<Int, Hike>,
private val location:locationRepository,
private val map:mapRepository
): HikeManager {
private suspend fun track() {
combine(location.current(),
map.current()) { location, map ->
val request =
createStoreWriteRequest(location, map)
val response = mutableStore.write(request)
handleResponse(response)
}}}
Store 5 Usage of MutableStore
What happens if write fails
or a competing write?
Con
fl
ict Resolution
Store 5 Concepts
https://developer.android.com/topic/architecture/data-layer/o
ffl
ine-
fi
rst#last-write
Non Happy Path == Hard
How Does Store 5 Resolves Con
fl
icts?
Implementing Principles
How Store 5 Resolves Conflicts
We Don’t You Do!
With Delegation
What we need from you
A Bookkeeper (delegate)
Bookkeeper?
Tracks when local changes fail to sync with
network
Store 5 Bookkeeper Api
interface Bookkeeper<Key : Any> {
suspend fun getLastFailedSync(key: Key): Long?
suspend fun setLastFailedSync(key: Key, timestamp: Long): Boolean
suspend fun clear(key: Key): Boolean
suspend fun clearAll(): Boolean}
MutableStore
+ Bookkeeper
Before completing a read request,
MutableStore asks Bookkeeper
whether any conflicts might exist
Store 5 - Any Conflicts? RealMutableStore
private suspend fun con
fl
ictsMightExist(key: Key): Boolean {
val lastFailedSync = bookkeeper?.getLastFailedSync(key)
return lastFailedSync != null || writeRequestsQueueIsEmpty(key).not()
}
MutableStore
+ Bookkeeper
And if conflicts might exist,
MutableStore tries to eagerly resolve them
What we think you should do
Resolve conflicts on remote
On each write request
1. Init thread safety (key-scoped)
2. Add request to stack (key-scoped)
3. Write to memory cache + SOT!!!
4. Try to update network (posting latest)
Mutations In the Weeds
On each write request
1. Init thread safety (key-scoped)
2. Add request to stack (key-scoped)
3. Write to memory cache + SOT!!!
4. Try to update network (posting latest)
In the Weeds
Mutations
On each write request
1. Init thread safety (key-scoped)
2. Add request to stack (key-scoped)
3. Write to memory cache + SOT!!!
4. Try to update network (posting latest)
In the Weeds
Mutations
On each write request
1. Init thread safety (key-scoped)
2. Add request to stack (key-scoped)
3. Write to memory cache + SOT!!!
4. Try to update network (posting latest)
In the Weeds
Mutations
When network response
1. Success
1. Reset stack
2. Reset bookkeeper
2. Failure
1. Log with bookkeeper
Try to update network
When network response
1. Success
1. Reset stack
2. Reset bookkeeper
2. Failure
1. Log with bookkeeper
Try to update network
When network response
1. Success
1. Reset stack
2. Reset bookkeeper
2. Failure
1. Log with bookkeeper
Try to update network
When network response
1. Success
1. Reset stack
2. Reset bookkeeper
2. Failure
1. Log with bookkeeper
Try to update network
When network response
1. Success
1. Reset stack
2. Reset bookkeeper
2. Failure
1. Log with bookkeeper
Try to update network
Fallback Mechanisms
Always have a backup plan!
Fallback Mechanisms
Store 5 Fetcher Api
fun <Key : Any, Network : Any> of(
name: String? = null,
fetch: suspend (key: Key) -> Network
): Fetcher<Key, Network> = ofFlow(name, fetch.asFlow())
fun <Key : Any, Network : Any> of(
name: String? = null,
fallback: Fetcher<Key, Network>,
fetch: suspend (key: Key) -> Network
): Fetcher<Key, Network> =
ofFlowWithFallback(name, fallback, fetch.asFlow())
Store 5 Fetcher Api with fallback
User Story - A/B Testing
data class FeatureFlag(
val key: String,
val name: String,
val description: String,
val kind: Kind,
val version: Int,
val creationDate: Long,
) : Identi
fi
able<String> {
enum class Kind { Boolean, Multivariate}}
Trails Feature Flag Model
Trails Feature Flag Status Model
sealed class FeatureFlagStatus: Identi
fi
able<String> {
data class Multivariate(
val key: String,
val value: FeatureFlagVariation,
val lastRequested: Long,
val links: Links)}
Trails Feature Flag
Architecture
Fallback Mechanisms
sample
Network Feature Flag Status Fetcher
With Fallback
val networkFetcher = Fetcher.ofWithFallback(
name = “networkFetcher”,
fallback = hardcodedFetcher
) { key ->
when (key) {
is Collection -> fetchFeatureFlagStatuses(key.userId)
is Single -> fetchFeatureFlagStatus(key.userId, key.
fl
agId)}}
Hardcoded Feature Flag Status Fetcher
val hardcodedFetcher = Fetcher.of(
name = “hardcodedFetcher”
) { key ->
when (key) {
is Collection -> loadFeatureFlagStatuses(key.userId)
is Single -> loadFeatureFlagStatus(key.userId, key.
fl
agId)}}
Build Store as normal
val store = StoreBuilder.from(
fetcher = networkFetcher,
sourceOfTruth = sourceOfTruth,
memoryCache = multiCache
).toMutableStoreBuilder<FeatureFlagStatusData,
FeatureFlagStatusData>().build(
updater = updater,
bookkeeper = bookkeeper)
Concepts
List Decomposition
Cache Delegation
WorkingWithCollections
sample
Just works
Store Loves KMP
We target Android/
Desktop/iOS/JS
Store 5 Beta is out now
github.com/mobilenativefoundation/store

More Related Content

Similar to meetstore5.pdf

Scale Your Data Tier With Windows Server App Fabric
Scale Your Data Tier With Windows Server App FabricScale Your Data Tier With Windows Server App Fabric
Scale Your Data Tier With Windows Server App Fabric
Chris Dufour
 
Java Performance Tuning
Java Performance TuningJava Performance Tuning
Java Performance Tuning
Atthakorn Chanthong
 
Max Koretskyi "Why are Angular and React so fast?"
Max Koretskyi "Why are Angular and React so fast?"Max Koretskyi "Why are Angular and React so fast?"
Max Koretskyi "Why are Angular and React so fast?"
Fwdays
 
Memcached Presentation @757rb
Memcached Presentation @757rbMemcached Presentation @757rb
Memcached Presentation @757rbKen Collins
 
Programmers, communicate your intentions
Programmers, communicate your intentionsProgrammers, communicate your intentions
Programmers, communicate your intentions
Yael Zaritsky Perez
 
Reactive programming with RxJava
Reactive programming with RxJavaReactive programming with RxJava
Reactive programming with RxJava
Jobaer Chowdhury
 
Intro to Asynchronous Javascript
Intro to Asynchronous JavascriptIntro to Asynchronous Javascript
Intro to Asynchronous Javascript
Garrett Welson
 
Principles of the Play framework
Principles of the Play frameworkPrinciples of the Play framework
Principles of the Play framework
Bernhard Huemer
 
RxSwift to Combine
RxSwift to CombineRxSwift to Combine
RxSwift to Combine
Bo-Young Park
 
Kickin' Ass with Cache-Fu (without notes)
Kickin' Ass with Cache-Fu (without notes)Kickin' Ass with Cache-Fu (without notes)
Kickin' Ass with Cache-Fu (without notes)
err
 
Node.js - iJS 2019
Node.js - iJS 2019Node.js - iJS 2019
Node.js - iJS 2019
NilsMehlhorn
 
Intro to React - Featuring Modern JavaScript
Intro to React - Featuring Modern JavaScriptIntro to React - Featuring Modern JavaScript
Intro to React - Featuring Modern JavaScriptjasonsich
 
The uniform interface is 42
The uniform interface is 42The uniform interface is 42
The uniform interface is 42
Yevhen Bobrov
 
Lambdas puzzler - Peter Lawrey
Lambdas puzzler - Peter LawreyLambdas puzzler - Peter Lawrey
Lambdas puzzler - Peter Lawrey
JAXLondon_Conference
 
3 Mobile App Dev Problems - Monospace
3 Mobile App Dev Problems - Monospace3 Mobile App Dev Problems - Monospace
3 Mobile App Dev Problems - Monospace
Frank Krueger
 
Matthew Vignau: Memory Management in SharePoint 2007 Development
Matthew Vignau: Memory Management in SharePoint 2007 DevelopmentMatthew Vignau: Memory Management in SharePoint 2007 Development
Matthew Vignau: Memory Management in SharePoint 2007 DevelopmentSharePoint Saturday NY
 
Solving the n + 1 query problem
Solving the n + 1 query problemSolving the n + 1 query problem
Solving the n + 1 query problem
Sebastien Pelletier
 
Java
JavaJava
Devf (Shoe Lovers)
Devf (Shoe Lovers)Devf (Shoe Lovers)
Devf (Shoe Lovers)
Alejandro Arza
 

Similar to meetstore5.pdf (20)

Scale Your Data Tier With Windows Server App Fabric
Scale Your Data Tier With Windows Server App FabricScale Your Data Tier With Windows Server App Fabric
Scale Your Data Tier With Windows Server App Fabric
 
Java Performance Tuning
Java Performance TuningJava Performance Tuning
Java Performance Tuning
 
Max Koretskyi "Why are Angular and React so fast?"
Max Koretskyi "Why are Angular and React so fast?"Max Koretskyi "Why are Angular and React so fast?"
Max Koretskyi "Why are Angular and React so fast?"
 
Memcached Presentation @757rb
Memcached Presentation @757rbMemcached Presentation @757rb
Memcached Presentation @757rb
 
Ejb examples
Ejb examplesEjb examples
Ejb examples
 
Programmers, communicate your intentions
Programmers, communicate your intentionsProgrammers, communicate your intentions
Programmers, communicate your intentions
 
Reactive programming with RxJava
Reactive programming with RxJavaReactive programming with RxJava
Reactive programming with RxJava
 
Intro to Asynchronous Javascript
Intro to Asynchronous JavascriptIntro to Asynchronous Javascript
Intro to Asynchronous Javascript
 
Principles of the Play framework
Principles of the Play frameworkPrinciples of the Play framework
Principles of the Play framework
 
RxSwift to Combine
RxSwift to CombineRxSwift to Combine
RxSwift to Combine
 
Kickin' Ass with Cache-Fu (without notes)
Kickin' Ass with Cache-Fu (without notes)Kickin' Ass with Cache-Fu (without notes)
Kickin' Ass with Cache-Fu (without notes)
 
Node.js - iJS 2019
Node.js - iJS 2019Node.js - iJS 2019
Node.js - iJS 2019
 
Intro to React - Featuring Modern JavaScript
Intro to React - Featuring Modern JavaScriptIntro to React - Featuring Modern JavaScript
Intro to React - Featuring Modern JavaScript
 
The uniform interface is 42
The uniform interface is 42The uniform interface is 42
The uniform interface is 42
 
Lambdas puzzler - Peter Lawrey
Lambdas puzzler - Peter LawreyLambdas puzzler - Peter Lawrey
Lambdas puzzler - Peter Lawrey
 
3 Mobile App Dev Problems - Monospace
3 Mobile App Dev Problems - Monospace3 Mobile App Dev Problems - Monospace
3 Mobile App Dev Problems - Monospace
 
Matthew Vignau: Memory Management in SharePoint 2007 Development
Matthew Vignau: Memory Management in SharePoint 2007 DevelopmentMatthew Vignau: Memory Management in SharePoint 2007 Development
Matthew Vignau: Memory Management in SharePoint 2007 Development
 
Solving the n + 1 query problem
Solving the n + 1 query problemSolving the n + 1 query problem
Solving the n + 1 query problem
 
Java
JavaJava
Java
 
Devf (Shoe Lovers)
Devf (Shoe Lovers)Devf (Shoe Lovers)
Devf (Shoe Lovers)
 

More from Mike Nakhimovich

Dispatching Reactive State
Dispatching Reactive StateDispatching Reactive State
Dispatching Reactive State
Mike Nakhimovich
 
Intro to GraphQL on Android with Apollo DroidconNYC 2017
Intro to GraphQL on Android with Apollo DroidconNYC 2017Intro to GraphQL on Android with Apollo DroidconNYC 2017
Intro to GraphQL on Android with Apollo DroidconNYC 2017
Mike Nakhimovich
 
Data Loading Made Easy with Mike Nakhimovich DroidCon Italy 2017
Data Loading Made Easy with Mike Nakhimovich DroidCon Italy 2017Data Loading Made Easy with Mike Nakhimovich DroidCon Italy 2017
Data Loading Made Easy with Mike Nakhimovich DroidCon Italy 2017
Mike Nakhimovich
 
Advanced Dagger talk from 360andev
Advanced Dagger talk from 360andevAdvanced Dagger talk from 360andev
Advanced Dagger talk from 360andev
Mike Nakhimovich
 
Sword fighting with Dagger GDG-NYC Jan 2016
 Sword fighting with Dagger GDG-NYC Jan 2016 Sword fighting with Dagger GDG-NYC Jan 2016
Sword fighting with Dagger GDG-NYC Jan 2016
Mike Nakhimovich
 
Intro to Functional Programming with RxJava
Intro to Functional Programming with RxJavaIntro to Functional Programming with RxJava
Intro to Functional Programming with RxJava
Mike Nakhimovich
 

More from Mike Nakhimovich (6)

Dispatching Reactive State
Dispatching Reactive StateDispatching Reactive State
Dispatching Reactive State
 
Intro to GraphQL on Android with Apollo DroidconNYC 2017
Intro to GraphQL on Android with Apollo DroidconNYC 2017Intro to GraphQL on Android with Apollo DroidconNYC 2017
Intro to GraphQL on Android with Apollo DroidconNYC 2017
 
Data Loading Made Easy with Mike Nakhimovich DroidCon Italy 2017
Data Loading Made Easy with Mike Nakhimovich DroidCon Italy 2017Data Loading Made Easy with Mike Nakhimovich DroidCon Italy 2017
Data Loading Made Easy with Mike Nakhimovich DroidCon Italy 2017
 
Advanced Dagger talk from 360andev
Advanced Dagger talk from 360andevAdvanced Dagger talk from 360andev
Advanced Dagger talk from 360andev
 
Sword fighting with Dagger GDG-NYC Jan 2016
 Sword fighting with Dagger GDG-NYC Jan 2016 Sword fighting with Dagger GDG-NYC Jan 2016
Sword fighting with Dagger GDG-NYC Jan 2016
 
Intro to Functional Programming with RxJava
Intro to Functional Programming with RxJavaIntro to Functional Programming with RxJava
Intro to Functional Programming with RxJava
 

Recently uploaded

PPT on GRP pipes manufacturing and testing
PPT on GRP pipes manufacturing and testingPPT on GRP pipes manufacturing and testing
PPT on GRP pipes manufacturing and testing
anoopmanoharan2
 
PROJECT FORMAT FOR EVS AMITY UNIVERSITY GWALIOR.ppt
PROJECT FORMAT FOR EVS AMITY UNIVERSITY GWALIOR.pptPROJECT FORMAT FOR EVS AMITY UNIVERSITY GWALIOR.ppt
PROJECT FORMAT FOR EVS AMITY UNIVERSITY GWALIOR.ppt
bhadouriyakaku
 
原版制作(unimelb毕业证书)墨尔本大学毕业证Offer一模一样
原版制作(unimelb毕业证书)墨尔本大学毕业证Offer一模一样原版制作(unimelb毕业证书)墨尔本大学毕业证Offer一模一样
原版制作(unimelb毕业证书)墨尔本大学毕业证Offer一模一样
obonagu
 
RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...
RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...
RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...
thanhdowork
 
BPV-GUI-01-Guide-for-ASME-Review-Teams-(General)-10-10-2023.pdf
BPV-GUI-01-Guide-for-ASME-Review-Teams-(General)-10-10-2023.pdfBPV-GUI-01-Guide-for-ASME-Review-Teams-(General)-10-10-2023.pdf
BPV-GUI-01-Guide-for-ASME-Review-Teams-(General)-10-10-2023.pdf
MIGUELANGEL966976
 
在线办理(ANU毕业证书)澳洲国立大学毕业证录取通知书一模一样
在线办理(ANU毕业证书)澳洲国立大学毕业证录取通知书一模一样在线办理(ANU毕业证书)澳洲国立大学毕业证录取通知书一模一样
在线办理(ANU毕业证书)澳洲国立大学毕业证录取通知书一模一样
obonagu
 
一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理
一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理
一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理
zwunae
 
ACRP 4-09 Risk Assessment Method to Support Modification of Airfield Separat...
ACRP 4-09 Risk Assessment Method to Support Modification of Airfield Separat...ACRP 4-09 Risk Assessment Method to Support Modification of Airfield Separat...
ACRP 4-09 Risk Assessment Method to Support Modification of Airfield Separat...
Mukeshwaran Balu
 
Recycled Concrete Aggregate in Construction Part III
Recycled Concrete Aggregate in Construction Part IIIRecycled Concrete Aggregate in Construction Part III
Recycled Concrete Aggregate in Construction Part III
Aditya Rajan Patra
 
一比一原版(UofT毕业证)多伦多大学毕业证成绩单如何办理
一比一原版(UofT毕业证)多伦多大学毕业证成绩单如何办理一比一原版(UofT毕业证)多伦多大学毕业证成绩单如何办理
一比一原版(UofT毕业证)多伦多大学毕业证成绩单如何办理
ydteq
 
Technical Drawings introduction to drawing of prisms
Technical Drawings introduction to drawing of prismsTechnical Drawings introduction to drawing of prisms
Technical Drawings introduction to drawing of prisms
heavyhaig
 
6th International Conference on Machine Learning & Applications (CMLA 2024)
6th International Conference on Machine Learning & Applications (CMLA 2024)6th International Conference on Machine Learning & Applications (CMLA 2024)
6th International Conference on Machine Learning & Applications (CMLA 2024)
ClaraZara1
 
digital fundamental by Thomas L.floydl.pdf
digital fundamental by Thomas L.floydl.pdfdigital fundamental by Thomas L.floydl.pdf
digital fundamental by Thomas L.floydl.pdf
drwaing
 
Literature Review Basics and Understanding Reference Management.pptx
Literature Review Basics and Understanding Reference Management.pptxLiterature Review Basics and Understanding Reference Management.pptx
Literature Review Basics and Understanding Reference Management.pptx
Dr Ramhari Poudyal
 
KuberTENes Birthday Bash Guadalajara - K8sGPT first impressions
KuberTENes Birthday Bash Guadalajara - K8sGPT first impressionsKuberTENes Birthday Bash Guadalajara - K8sGPT first impressions
KuberTENes Birthday Bash Guadalajara - K8sGPT first impressions
Victor Morales
 
Modelagem de um CSTR com reação endotermica.pdf
Modelagem de um CSTR com reação endotermica.pdfModelagem de um CSTR com reação endotermica.pdf
Modelagem de um CSTR com reação endotermica.pdf
camseq
 
Fundamentals of Induction Motor Drives.pptx
Fundamentals of Induction Motor Drives.pptxFundamentals of Induction Motor Drives.pptx
Fundamentals of Induction Motor Drives.pptx
manasideore6
 
A review on techniques and modelling methodologies used for checking electrom...
A review on techniques and modelling methodologies used for checking electrom...A review on techniques and modelling methodologies used for checking electrom...
A review on techniques and modelling methodologies used for checking electrom...
nooriasukmaningtyas
 
Planning Of Procurement o different goods and services
Planning Of Procurement o different goods and servicesPlanning Of Procurement o different goods and services
Planning Of Procurement o different goods and services
JoytuBarua2
 
Design and Analysis of Algorithms-DP,Backtracking,Graphs,B&B
Design and Analysis of Algorithms-DP,Backtracking,Graphs,B&BDesign and Analysis of Algorithms-DP,Backtracking,Graphs,B&B
Design and Analysis of Algorithms-DP,Backtracking,Graphs,B&B
Sreedhar Chowdam
 

Recently uploaded (20)

PPT on GRP pipes manufacturing and testing
PPT on GRP pipes manufacturing and testingPPT on GRP pipes manufacturing and testing
PPT on GRP pipes manufacturing and testing
 
PROJECT FORMAT FOR EVS AMITY UNIVERSITY GWALIOR.ppt
PROJECT FORMAT FOR EVS AMITY UNIVERSITY GWALIOR.pptPROJECT FORMAT FOR EVS AMITY UNIVERSITY GWALIOR.ppt
PROJECT FORMAT FOR EVS AMITY UNIVERSITY GWALIOR.ppt
 
原版制作(unimelb毕业证书)墨尔本大学毕业证Offer一模一样
原版制作(unimelb毕业证书)墨尔本大学毕业证Offer一模一样原版制作(unimelb毕业证书)墨尔本大学毕业证Offer一模一样
原版制作(unimelb毕业证书)墨尔本大学毕业证Offer一模一样
 
RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...
RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...
RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...
 
BPV-GUI-01-Guide-for-ASME-Review-Teams-(General)-10-10-2023.pdf
BPV-GUI-01-Guide-for-ASME-Review-Teams-(General)-10-10-2023.pdfBPV-GUI-01-Guide-for-ASME-Review-Teams-(General)-10-10-2023.pdf
BPV-GUI-01-Guide-for-ASME-Review-Teams-(General)-10-10-2023.pdf
 
在线办理(ANU毕业证书)澳洲国立大学毕业证录取通知书一模一样
在线办理(ANU毕业证书)澳洲国立大学毕业证录取通知书一模一样在线办理(ANU毕业证书)澳洲国立大学毕业证录取通知书一模一样
在线办理(ANU毕业证书)澳洲国立大学毕业证录取通知书一模一样
 
一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理
一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理
一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理
 
ACRP 4-09 Risk Assessment Method to Support Modification of Airfield Separat...
ACRP 4-09 Risk Assessment Method to Support Modification of Airfield Separat...ACRP 4-09 Risk Assessment Method to Support Modification of Airfield Separat...
ACRP 4-09 Risk Assessment Method to Support Modification of Airfield Separat...
 
Recycled Concrete Aggregate in Construction Part III
Recycled Concrete Aggregate in Construction Part IIIRecycled Concrete Aggregate in Construction Part III
Recycled Concrete Aggregate in Construction Part III
 
一比一原版(UofT毕业证)多伦多大学毕业证成绩单如何办理
一比一原版(UofT毕业证)多伦多大学毕业证成绩单如何办理一比一原版(UofT毕业证)多伦多大学毕业证成绩单如何办理
一比一原版(UofT毕业证)多伦多大学毕业证成绩单如何办理
 
Technical Drawings introduction to drawing of prisms
Technical Drawings introduction to drawing of prismsTechnical Drawings introduction to drawing of prisms
Technical Drawings introduction to drawing of prisms
 
6th International Conference on Machine Learning & Applications (CMLA 2024)
6th International Conference on Machine Learning & Applications (CMLA 2024)6th International Conference on Machine Learning & Applications (CMLA 2024)
6th International Conference on Machine Learning & Applications (CMLA 2024)
 
digital fundamental by Thomas L.floydl.pdf
digital fundamental by Thomas L.floydl.pdfdigital fundamental by Thomas L.floydl.pdf
digital fundamental by Thomas L.floydl.pdf
 
Literature Review Basics and Understanding Reference Management.pptx
Literature Review Basics and Understanding Reference Management.pptxLiterature Review Basics and Understanding Reference Management.pptx
Literature Review Basics and Understanding Reference Management.pptx
 
KuberTENes Birthday Bash Guadalajara - K8sGPT first impressions
KuberTENes Birthday Bash Guadalajara - K8sGPT first impressionsKuberTENes Birthday Bash Guadalajara - K8sGPT first impressions
KuberTENes Birthday Bash Guadalajara - K8sGPT first impressions
 
Modelagem de um CSTR com reação endotermica.pdf
Modelagem de um CSTR com reação endotermica.pdfModelagem de um CSTR com reação endotermica.pdf
Modelagem de um CSTR com reação endotermica.pdf
 
Fundamentals of Induction Motor Drives.pptx
Fundamentals of Induction Motor Drives.pptxFundamentals of Induction Motor Drives.pptx
Fundamentals of Induction Motor Drives.pptx
 
A review on techniques and modelling methodologies used for checking electrom...
A review on techniques and modelling methodologies used for checking electrom...A review on techniques and modelling methodologies used for checking electrom...
A review on techniques and modelling methodologies used for checking electrom...
 
Planning Of Procurement o different goods and services
Planning Of Procurement o different goods and servicesPlanning Of Procurement o different goods and services
Planning Of Procurement o different goods and services
 
Design and Analysis of Algorithms-DP,Backtracking,Graphs,B&B
Design and Analysis of Algorithms-DP,Backtracking,Graphs,B&BDesign and Analysis of Algorithms-DP,Backtracking,Graphs,B&B
Design and Analysis of Algorithms-DP,Backtracking,Graphs,B&B
 

meetstore5.pdf

  • 3. Store is a Java library for effortless, reactive data loading. Guarantee things [you don’t want to think about] are done in the same way What is Store?
  • 4. Contracts + RELIABILITY Guarantee things are done in the same way What is Store?
  • 5. Store A brief history 2017 2019 2021 2022 2023
  • 6. Store A brief history 2017 2019 1.0 Released Jan 17th, 2017 by NY Times
  • 7. 2017 2019 Why did we need Store? We wanted to do complicated thing once
  • 8. Store Version 1.0 Api 2017 2019 Store [was] a Java library for effortless, reactive data loading built with RxJava Store<Article> Store = ParsingStoreBuilder.<BufferedSource, String>builder() .fetcher(this::ResponseAsSource) .persister(SourcePersisterFactory.create(context.getFilesDir()) .parser(GsonParserFactory.createSourceParser(gson, Article.class)) .open(); Barcode barcode = new Barcode("Article", "42"); store.get(barcode).subscribe(onNext, onError, onComplete)
  • 9. 2017 2019 Fresh == skip memory/persister go directly to fetcher store.fresh(param).subscribe(onNext, onError, onComplete) Fresh Skip Caches
  • 10. Store Why You Need User Research 2.0 Released 1 month later (oops!) 2017 2019
  • 11. 3.0 Api Rxjava2 RxSingle instead of Observable Store<Article> Store = ParsingStoreBuilder.<BufferedSource,ArticleParam, String>builder() .fetcher(this::ResponseAsSource) //responseBody.source() .persister(SourcePersisterFactory.create(context.getFilesDir()) .parser(GsonParserFactory.createSourceParser(gson, Article.class)) .open(); ArticleParam param = new ArticleParam("42"); store.get(param).subscribe(onNext, onError) 2017 2019 Store
  • 12. Coroutines have hit stable 2017 2019 2021 Fast forward to 2019
  • 13. Bye bye RxJava Hello Kotlin 2017 2019 2021 Store4 Fast forward to 2019
  • 14. Hello Kotlin 2017 2019 2021 Store4 StoreBuilder.from { api.fetchSubreddit(it, "10")} .sourceOfTruth( reader = db.postDao()::loadPosts, writer = db.postDao()::insertPosts, delete = db.postDao()::clearFeed) .cachePolicy(MemoryPolicy) .build() Api
  • 15. Streaming as first class citizen 2017 2019 2021 fun stream(request: StoreRequest<Key>): Flow<StoreResponse>Output>> lifecycleScope.launchWhenStarted { store.stream(StoreRequest.cached(3, refresh = false)) .collect{ } store.stream(StoreRequest.get(3)) .collect{ storeResponse -> } Store4 Api
  • 16. Loading|Content|Error Return Types 2017 2019 2021 Store 4 store.stream(StoreRequest.cached(key = key, refresh=true)).collect { response -> when(response) { is StoreResponse.Loading -> showLoadingSpinner() is StoreResponse.Data -> { if (response.origin == ResponseOrigin.Fetcher) hideLoadingSpinner() updateUI(response.value) } is StoreResponse.Error -> { if (response.origin == ResponseOrigin.Fetcher) hideLoadingSpinner() showError(response.error) }}}} LCE
  • 17. Using Store 4 Examples are from Firefly for Mastodon https://github.com/digitalbuddha/Firefly 2017 2019 2021
  • 18. You create a Store using a builder. The only requirement is to include a Fetcher which is just a typealias to a function that returns a Flow<FetcherResult<ReturnType>>. //build it val store = StoreBuilder.from( Fetcher.of { key: Unit -> userApi.noti fi cations( authHeader = " Bearer ${oauthRepository.getCurrent()}", offset = null) }).build() //use it store.stream(StoreRequest.cached(Unit, refresh = true)).map { it.dataOrNull() } .collect{response-> } Fetcher as a Function 2017 2019 2021
  • 19. How we get data 2017 2019 2021
  • 20. Do the hard thing once How to work with local persistence
  • 21. Source of Truth suspend fun fetcher(key:String): Token = api.createAccessToken(key) fun sourceOfTruth = SourceOfTruth.of<String, Token, String>( reader = {dataStore.data.map { it.currentUser?.accessToken }}, writer = { _, token -> dataStore.updateData { it.user.copy(accessToken = token.accessToken) }}) private val userTokenStore: Store<String, String> = StoreBuilder.from( fetcher = Fetcher.of { key: String -> fetcher(key) }, sourceOfTruth = sourceOfTruth ).build() 2017 2019 2021
  • 23. Fast forward to 2022 Where we were 365 days ago 2021 2022 2023
  • 24. Store 4 is stable Less than a dozen open bugs 2021 2022 2023
  • 25. API was perfect As long as you only asked me 2021 2022 2023
  • 26. We had LOTS of feature requests 2021 2022 2023
  • 27. That I was ignoring 2021 2022 2023
  • 32. Store 5 Introducing Store now with batteries included
  • 33.
  • 35. Sync
  • 42. Don’t worry Store 5 is a superset of Store4 Which targets JVM/iOS/Web
  • 43. How we got here…
  • 44. Try 1…Adding Write Support Rewrite what you don’t understand
  • 45. Mike: What is the bene fi t of starting over? Matt: Hmm Mike: Is it easier to add old to new or new to old?
  • 46. Some time later… (half hour) Matt: safeguards will be easier to add to new Matt: because I don’t understand old Mike: SGTM as long as all tests are migrated, I also don’t understand old Matt: Sure how hard can it be?
  • 47. Many days later: Mike: …. Matt: …
  • 48. More time passes Mike: My spider sense is tingling, I found more gaps in new Mike: let’s sit together and go through Store4 code
  • 49. Try 2…Extending the old Rather than boiling the ocean
  • 50. Few weeks later… Matt:Just finished last test cases everything passes Mike: Everything? Matt: Yup in iOS, android, JVM and JS, I took all the work https://github.com/aclassen did and got it to pass tests
  • 51.
  • 53. Mutations Con fl ict Resolution Fallback Mechanisms List Decomposition Cache Delegation Validation Concepts
  • 56.
  • 57.
  • 58.
  • 59. User Story - Hiking without Internet
  • 61. Data Pulled & Pushed
  • 62. Source of Truth to Repository Data Flow
  • 63. Can’t do with Store 4 Source of Truth to Repository Data Flow
  • 64. interface Updater<Key, Output, Response> { suspend fun post(key: Key, value: Output): UpdaterResult val onCompletion: OnUpdaterCompletion<Response>?} Store 5 New Mutation Api Creating an Updater (like a fetcher)
  • 66. val updater = Updater.by( post = { _, hike -> try { val latest = api.updateHike(hike) UpdaterResult.Success.Typed(latest) } catch (error: Throwable) { UpdaterResult.Error.Exception(error) }}) Store 5 Updater Factory
  • 67. val mutableStore = store.asMutableStore( updater = updater, bookkeeper = bookkeeper) Store 5 Mutable Store Builder
  • 68. class RealHikeManager @Inject constructor( private val mutableStore: MutableStore<Int, Hike>, private val location:locationRepository, private val map:mapRepository ): HikeManager { private suspend fun track() { combine(location.current(), map.current()) { location, map -> val request = createStoreWriteRequest(location, map) val response = mutableStore.write(request) handleResponse(response) }}} Store 5 Usage of MutableStore
  • 69. class RealHikeManager @Inject constructor( private val mutableStore: MutableStore<Int, Hike>, private val location:locationRepository, private val map:mapRepository ): HikeManager { private suspend fun track() { combine(location.current(), map.current()) { location, map -> val request = createStoreWriteRequest(location, map) val response = mutableStore.write(request) handleResponse(response) }}} Store 5 Usage of MutableStore
  • 70. What happens if write fails or a competing write?
  • 73.
  • 74. How Does Store 5 Resolves Con fl icts? Implementing Principles
  • 75. How Store 5 Resolves Conflicts We Don’t You Do! With Delegation
  • 76. What we need from you A Bookkeeper (delegate)
  • 77. Bookkeeper? Tracks when local changes fail to sync with network
  • 78. Store 5 Bookkeeper Api interface Bookkeeper<Key : Any> { suspend fun getLastFailedSync(key: Key): Long? suspend fun setLastFailedSync(key: Key, timestamp: Long): Boolean suspend fun clear(key: Key): Boolean suspend fun clearAll(): Boolean}
  • 79. MutableStore + Bookkeeper Before completing a read request, MutableStore asks Bookkeeper whether any conflicts might exist
  • 80. Store 5 - Any Conflicts? RealMutableStore private suspend fun con fl ictsMightExist(key: Key): Boolean { val lastFailedSync = bookkeeper?.getLastFailedSync(key) return lastFailedSync != null || writeRequestsQueueIsEmpty(key).not() }
  • 81. MutableStore + Bookkeeper And if conflicts might exist, MutableStore tries to eagerly resolve them
  • 82. What we think you should do Resolve conflicts on remote
  • 83. On each write request 1. Init thread safety (key-scoped) 2. Add request to stack (key-scoped) 3. Write to memory cache + SOT!!! 4. Try to update network (posting latest) Mutations In the Weeds
  • 84. On each write request 1. Init thread safety (key-scoped) 2. Add request to stack (key-scoped) 3. Write to memory cache + SOT!!! 4. Try to update network (posting latest) In the Weeds Mutations
  • 85. On each write request 1. Init thread safety (key-scoped) 2. Add request to stack (key-scoped) 3. Write to memory cache + SOT!!! 4. Try to update network (posting latest) In the Weeds Mutations
  • 86. On each write request 1. Init thread safety (key-scoped) 2. Add request to stack (key-scoped) 3. Write to memory cache + SOT!!! 4. Try to update network (posting latest) In the Weeds Mutations
  • 87. When network response 1. Success 1. Reset stack 2. Reset bookkeeper 2. Failure 1. Log with bookkeeper Try to update network
  • 88. When network response 1. Success 1. Reset stack 2. Reset bookkeeper 2. Failure 1. Log with bookkeeper Try to update network
  • 89. When network response 1. Success 1. Reset stack 2. Reset bookkeeper 2. Failure 1. Log with bookkeeper Try to update network
  • 90. When network response 1. Success 1. Reset stack 2. Reset bookkeeper 2. Failure 1. Log with bookkeeper Try to update network
  • 91. When network response 1. Success 1. Reset stack 2. Reset bookkeeper 2. Failure 1. Log with bookkeeper Try to update network
  • 93. Always have a backup plan! Fallback Mechanisms
  • 94. Store 5 Fetcher Api fun <Key : Any, Network : Any> of( name: String? = null, fetch: suspend (key: Key) -> Network ): Fetcher<Key, Network> = ofFlow(name, fetch.asFlow())
  • 95. fun <Key : Any, Network : Any> of( name: String? = null, fallback: Fetcher<Key, Network>, fetch: suspend (key: Key) -> Network ): Fetcher<Key, Network> = ofFlowWithFallback(name, fallback, fetch.asFlow()) Store 5 Fetcher Api with fallback
  • 96. User Story - A/B Testing
  • 97. data class FeatureFlag( val key: String, val name: String, val description: String, val kind: Kind, val version: Int, val creationDate: Long, ) : Identi fi able<String> { enum class Kind { Boolean, Multivariate}} Trails Feature Flag Model
  • 98. Trails Feature Flag Status Model sealed class FeatureFlagStatus: Identi fi able<String> { data class Multivariate( val key: String, val value: FeatureFlagVariation, val lastRequested: Long, val links: Links)}
  • 101. Network Feature Flag Status Fetcher With Fallback val networkFetcher = Fetcher.ofWithFallback( name = “networkFetcher”, fallback = hardcodedFetcher ) { key -> when (key) { is Collection -> fetchFeatureFlagStatuses(key.userId) is Single -> fetchFeatureFlagStatus(key.userId, key. fl agId)}}
  • 102. Hardcoded Feature Flag Status Fetcher val hardcodedFetcher = Fetcher.of( name = “hardcodedFetcher” ) { key -> when (key) { is Collection -> loadFeatureFlagStatuses(key.userId) is Single -> loadFeatureFlagStatus(key.userId, key. fl agId)}}
  • 103. Build Store as normal val store = StoreBuilder.from( fetcher = networkFetcher, sourceOfTruth = sourceOfTruth, memoryCache = multiCache ).toMutableStoreBuilder<FeatureFlagStatusData, FeatureFlagStatusData>().build( updater = updater, bookkeeper = bookkeeper)
  • 106. Just works Store Loves KMP We target Android/ Desktop/iOS/JS
  • 107. Store 5 Beta is out now github.com/mobilenativefoundation/store