SlideShare a Scribd company logo
StoreDataLoadingMadeEasy-ish
Mike Nakhimovich - NY Times
We ❤Making Apps
We ❤Open Source
Why?Open Source Makes Life Easier
Networking is easier:
HTTPURLCONNECTION
Volley
Retrofit/ Okhttp
Storage is Easier
SharedPreferences
Firebase
Realm
SqlBrite/SqlDelight
Parsing is Easier
JSONObject
Jackson
Gson
Moshi
Fetching, Persisting &
Parsing datahas become
easy
What's NOT Easy?
DATALOADINGEveryone does itdifferently
Whatis DataLoading?
TheActofgetting
datafroman external
systemtoauser'sscreen
Loading is
complicated
Rotation Handling isa special
snowflake
NewYorkTimes builtStoreto
simplifydataloading
github.com/NYTimes/store
OUR GOALS
Datashould survive
configuration changes
agnostic ofwhere itcomes from or
howitis needed
Activitiesand
presenters should
stopretaining MBs
ofdata
Offline as configuration
Cachingas standard,
notan exception
API should be
simple enough for
an internto use,yet
robust enough
for everydataload.
Howdowework
with DataatNY
Times?
80% case:
Need data, don'tcare
iffresh or cached
Need fresh data
background
updates &
pull to refresh
Requests needto be
async & reactive
Datais dependenton
each other,
DataLoading should
betoo
Performance is
importantNewcalls should hook into in flight
responses
Parsing should be
done efficientlyand
minimallyParse onceand cachethe resultfor future calls
Let's Use Repository
PatternBy creating reactiveand persistent
DataStores
Repository Pattern
Separatethe logicthatretrievesthe
dataand maps ittothe [view] model
fromthe [view] logicthatacts onthe
model.
The repositorymediates betweenthe
datalayerandthe [view] layer ofthe
application.
WhyRepository?
Maximizetheamountof
codethatcan betested
withautomation by
isolatingthe datalayer
Why
Repository?
Makes iteasierto have
multiple devsworking on
same feature
Why
Repository?
Datasource from many
locationswillbe centrally
managedwith consistent
access rulesand logic
Our Implementation
https://github.com/NYTimes/Store
WhatisaStore?
Aclassthatmanagesthe
fetching, parsing,and
storage ofaspecific data
model
Tell a Store:
Whatto fetch
Tell a Store:
Whatto fetch
Whereto cache
Tell a Store:
Whatto fetch
Whereto cache
Howto parse
Tell a Store:
Whatto fetch
Whereto cache
Howto parse
The Store handles flow
Storesare Observable
Observable<T> get( V key);
Observable<T> fetch(V key)
Observable<T> stream()
void clear(V key)
Let's see howstores
helped usachieve
our goalsthrougha
PizzaExample
Getis for Handling our 80% Use Case
public final class PizzaActivity {
Store<Pizza, String> pizzaStore;
void onCreate() {
store.get("cheese")
.subscribe(pizza ->.show(pizza));
}
}
Howdoes itflow?
On Configuration Change
You onlyneedto Save/Restoreyour !to get
your cached "
public final class PizzaActivity {
void onRecreate(String topping) {
store.get(topping)
.subscribe(pizza ->.show(pizza));
}
}
Please do notserializeaPizza
Itwould beverymessy
Whatwe gain?:Fragments/Presenters don'tneedto be
retained
NoTransactionTooLargeExceptions
Onlykeys needto be Parcelable
Efficiencyis Important:
for(i=0;i<20;i++){
store.get(topping)
.subscribe(pizza -> getView()
.setData(pizza));
}
ManyconcurrentGetrequestswillstillonly
hitnetwork once
Fetching NewDatapublic class PizzaPresenter {
Store<Pizza, String> store;
void onPTR() {
store.fetch("cheese")
.subscribe(pizza ->
getView().setData(pizza));
}
}
Howdoes Store routethe request?
Fetchalsothrottles multiple requestsand
broadcastresult
Stream listens for events
public class PizzaBar {
Store<Pizza, String> store;
void showPizzaDone() {
store.stream()
.subscribe(pizza ->
getView().showSnackBar(pizza));
}
}
How do We build a
Store?
By implementing interfaces
Interfaces
Fetcher<Raw, Key>{
Observable<Raw> fetch(Key key);
}
Persister<Raw, Key>{}
Observable<Raw> read(Key key);
Observable<Boolean> write(Key key, Raw raw);
}
Parser<Raw, Parsed> extends Func1<Raw, Parsed>{
Parsed call(Raw raw);
}
Fetcher defines how a Store will get new data
Fetcher<Pizza,String> pizzaFetcher =
new Fetcher<Pizza, String>() {
public Observable<Pizza> fetch(String topping) {
return pizzaSource.fetch(topping);
};
Becoming Observable
Fetcher<Pizza,String> pizzaFetcher =
topping ->
Observable.fromCallable(() -> client.fetch(topping));
Parsers helpwith
Fetchersthatdon't
returnViewModels
Some ParsersTransform
Parser<Pizza, PizzaBox> boxParser = new Parser<>() {
public PizzaBox call(Pizza pizza) {
return new PizzaBox(pizza);
}
};
Others read Streams
Parser<BufferedSource, Pizza> parser = source -> {
InputStreamReader reader =
new InputStreamReader(source.inputStream());
return gson.fromJson(reader, Pizza.class);
}
MiddleWare is forthe commonJSON cases
Parser<BufferedSource, Pizza> parser
= GsonParserFactory.createSourceParser(gson,Pizza.class)
Parser<Reader, Pizza> parser
= GsonParserFactory.createReaderParser(gson,Pizza.class)
Parser<String, Pizza> parser
= GsonParserFactory.createStringParser(gson,Pizza.class)
'com.nytimes.android:middleware:CurrentVersion'
'com.nytimes.android:middleware:jackson:CurrentVersion'
'com.nytimes.android:middleware-moshi:CurrentVersion'
Data FlowwithaParser
Adding Offline with Persisters
File System Record Persister
FileSystemRecordPersister.create(
fileSystem,key -> "pizza"+key, 1, TimeUnit.DAYS);
File System is KISS storage
interface FileSystem {
BufferedSource read(String var) throws FileNotFoundException;
void write(String path, BufferedSource source) throws IOException;
void delete(String path) throws IOException;
}
compile 'com.nytimes.android:filesystem:CurrentVersion'
Don'tlike our persisters?
No Problem! You
can implement your
own
Persister interfaces
Persister<Raw, Key> {
Observable<Raw> read(Key key);
Observable<Boolean> write(Key key, Raw raw);
}
Clearable<Key> {
void clear(Key key);
}
RecordProvider<Key> {
RecordState getRecordState( Key key);
DataFlowwithaPersister
We have our components!
Let's buildand openastore
MultiParser
List<Parser> parsers=new ArrayList<>();
parsers.add(boxParser);
parsers.add(GsonParserFactory.createSourceParser(gson, Pizza.class));
Store Builder
List<Parser> parsers=new ArrayList<>();
parsers.add(boxParser);
parsers.add(GsonParserFactory.createSourceParser(gson, Pizza.class));
StoreBuilder<String,BufferedSource,Pizza> parsedWithKey()
Add Our Parser
List<Parser> parsers=new ArrayList<>();
parsers.add(boxParser);
parsers.add(GsonParserFactory.createSourceParser(gson, Pizza.class));
StoreBuilder<String,BufferedSource,Pizza> parsedWithKey()
.fetcher(topping -> pizzaSource.fetch(topping))
NowOur Persister
List<Parser> parsers=new ArrayList<>();
parsers.add(boxParser);
parsers.add(GsonParserFactory.createSourceParser(gson, Pizza.class));
StoreBuilder<String,BufferedSource,Pizza> parsedWithKey()
.fetcher(topping -> pizzaSource.fetch(topping))
.persister( FileSystemRecordPersister.create( fileSystem,
key -> "prefix"+key, 1, TimeUnit.DAYS))
And Our Parsers
List<Parser> parsers=new ArrayList<>();
parsers.add(boxParser);
parsers.add(GsonParserFactory.createSourceParser(gson, Pizza.class));
StoreBuilder<String,BufferedSource,Pizza> parsedWithKey()
.fetcher(topping -> pizzaSource.fetch(topping))
.persister( FileSystemRecordPersister.create( fileSystem,
key -> "prefix"+key, 1, TimeUnit.DAYS))
.parsers(parsers)
Timeto OpenaStore
List<Parser> parsers=new ArrayList<>();
parsers.add(boxParser);
parsers.add(GsonParserFactory.createSourceParser(gson, Pizza.class));
Store<Pizza, String> pizzaStore =
StoreBuilder<String,BufferedSource,Pizza> parsedWithKey()
.fetcher(topping -> pizzaSource.fetch(topping))
.persister( FileSystemRecordPersister.create( fileSystem,
key -> "prefix"+key, 1, TimeUnit.DAYS))
.parsers(parsers)
.open();
Configuring caches
Configuring MemoryPolicy
StoreBuilder
.<String, BufferedSource, Pizza>parsedWithKey()
.fetcher(topping -> pizzaSource.fetch(topping))
.memoryPolicy(MemoryPolicy
.builder()
.setMemorySize(10)
.setExpireAfter(24)
.setExpireAfterTimeUnit(HOURS)
.build())
.open()
Refresh On Stale - BackFillingthe Cache
Store<Pizza, String> pizzaStore = StoreBuilder
.<String, BufferedSource, Pizza>parsedWithKey()
.fetcher(topping -> pizzaSource.fetch(topping))
.parsers(parsers)
.persister(persister)
.refreshOnStale()
.open();
Network Before Stales Policy
Store<Pizza, String> pizzaStore = StoreBuilder
.<String, BufferedSource, Pizza>parsedWithKey()
.fetcher(topping -> pizzaSource.fetch(topping))
.parsers(parsers)
.persister(persister)
.networkBeforeStale()
.open();
Stores inthewild
Intern Project: BestSellers List
public interface Api {
@GET
Observable<BufferedSource>
getBooks(@Path("category") String category);
@Provides
@Singleton
Store<Books, BarCode> provideBooks(FileSystem fileSystem,
Gson gson, Api api) {
return StoreBuilder.<BarCode, BufferedSource, Books>
parsedWithKey()
.fetcher(category -> api.getBooks(category))
.persister(SourcePersisterFactory.create(fileSystem))
.parser(GsonParserFactory.createSourceParser(gson, Books.class))
.open();
}
public class BookActivity{
...
onCreate(...){
bookStore
.get(category)
.subscribe();
}
Howdo books getupdated?
public class BackgroundUpdater{
...
bookStore
.fresh(category)
.subscribe();
}
DataAvailablewhen screen needs it
UI calls get, background services call fresh
DependentCalls
Simple case Using RxJavaOperators
MapStore resulttoanother Store Result
public Observable<SectionFront> getSectionFront(@NonNull final String name) {
return feedStore.get()
.map(latestFeed -> latestFeed.getSectionOrBlog(name))
.flatMap(section -> sfStore.get(SectionFrontId.of(section)));
}
More Complicated Example
Video Store Returns singlevideos,
PlaylistStore returns playlist,
Howdowe combine?
Relationships by overriding
Get/Fetch
Step1: CreateVideo Store
Store<Video, Long> provideVideoStore(VideoFetcher fetcher,
Gson gson) {
return StoreBuilder.<Long, BufferedSource, Video>parsedWithKey()
.fetcher(fetcher)
.parser(GsonParserFactory
.createSourceParser(gson, Video.class))
.open();
}
Step 2: Create PlaylistStore
public class VideoPlaylistStore extends RealStore<Playlist, Long> {
final Store<CherryVideoEntity, Long> videoStore;
public VideoPlaylistStore(@NonNull PlaylistFetcher fetcher,
@NonNull Store<CherryVideoEntity, Long> videoStore,
@NonNull Gson gson) {
super(fetcher, NoopPersister.create(),
GsonParserFactory.createSourceParser(gson, Playlist.class));
this.videoStore = videoStore;
}
Step 3: Override store.get()
public class VideoPlaylistStore extends RealStore<Playlist, Long> {
final Store<CherryVideoEntity, Long> videoStore;
@Override
public Observable<Playlist> get(Long playlistId) {
return super.get(playlistId)
.flatMap(playlist ->
from(playlist.videos())
.concatMap(video -> videoStore.get(video.id()))
.toList()
.map(videos ->
builder().from(playlist)
.videos(videos)
.build()));
}
Listening for changes
Step1: Subscribeto Store, Filterwhatyou need
sectionFrontStore.subscribeUpdates()
.observeOn(scheduler)
.subscribeOn(Schedulers.io())
.filter(this::sectionIsInView)
.subscribe(this::handleSectionChange);
Step2: Kick offafresh requesttothatstore
public Observable<SectionFront> refreshAll(final String sectionName) {
return feedStore.get()
.flatMapIterable(this::updatedSections)
.map(section->sectionFrontStore.fetch(section))
latestFeed -> fetch(latestFeed.changedSections));
}
Bonus: Howwe made Store
RxJavaforAPIand FunctionalNiceties
public Observable<Parsed> get(@Nonnull final Key key) {
return Observable.concat(
cache(key),
fetch(key)
).take(1);
}
public Observable<Parsed> getRefreshing(@Nonnull final Key key) {
return get(key)
.compose(repeatOnClear(refreshSubject, key));
}
GuavaCaches For MemoryCache
memCache = CacheBuilder
.newBuilder()
.maximumSize(maxSize())
.expireAfterWrite(expireAfter(),timeUnit())
.build();
In FlightThrottlerToo
inflighter.get(key, new Callable<Observable<Parsed>>() {
public Observable<Parsed> call() {
return response(key);
}
})
compile 'com.nytimes.android:cache:CurrentVersion'
Why GuavaCaches?
Theywillblockacrossthreads saving precious MBs ofdownloads
when making same requests in parallel
FileSystem:
Builtusing OKIOtoallowstreaming
from Networkto disk & diskto parser
On Fresh InstallNYTimesappsuccessfullydownloadsand caches
dozens ofmbs ofdata
Would love
contributions &
feedback!thanks for listening

More Related Content

What's hot

Contract-driven development with OpenAPI 3 and Vert.x | DevNation Tech Talk
Contract-driven development with OpenAPI 3 and Vert.x | DevNation Tech TalkContract-driven development with OpenAPI 3 and Vert.x | DevNation Tech Talk
Contract-driven development with OpenAPI 3 and Vert.x | DevNation Tech Talk
Red Hat Developers
 
End to end todo list app with NestJs - Angular - Redux & Redux Saga
End to end todo list app with NestJs - Angular - Redux & Redux SagaEnd to end todo list app with NestJs - Angular - Redux & Redux Saga
End to end todo list app with NestJs - Angular - Redux & Redux Saga
Babacar NIANG
 
Appengine Java Night #2b
Appengine Java Night #2bAppengine Java Night #2b
Appengine Java Night #2bShinichi Ogawa
 
Appengine Java Night #2a
Appengine Java Night #2aAppengine Java Night #2a
Appengine Java Night #2aShinichi Ogawa
 
Intro to Retrofit 2 and RxJava2
Intro to Retrofit 2 and RxJava2Intro to Retrofit 2 and RxJava2
Intro to Retrofit 2 and RxJava2
Fabio Collini
 
#ajn3.lt.marblejenka
#ajn3.lt.marblejenka#ajn3.lt.marblejenka
#ajn3.lt.marblejenka
Shingo Furuyama
 
[Srijan Wednesday Webinar] Rails 5: What's in It for Me?
[Srijan Wednesday Webinar] Rails 5: What's in It for Me?[Srijan Wednesday Webinar] Rails 5: What's in It for Me?
[Srijan Wednesday Webinar] Rails 5: What's in It for Me?
Srijan Technologies
 
Retrofit
RetrofitRetrofit
Retrofit
Amin Cheloh
 
Java Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to MissJava Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to Miss
Andres Almiray
 
FullStack Reativo com Spring WebFlux + Angular
FullStack Reativo com Spring WebFlux + AngularFullStack Reativo com Spring WebFlux + Angular
FullStack Reativo com Spring WebFlux + Angular
Loiane Groner
 
Android getting started
Android getting startedAndroid getting started
Android getting started
Uptech
 
Durable functions
Durable functionsDurable functions
Durable functions
명신 김
 
iOS Keychain by 흰, 민디
iOS Keychain by 흰, 민디iOS Keychain by 흰, 민디
iOS Keychain by 흰, 민디
MINJICHO20
 
Enterprise Guice 20090217 Bejug
Enterprise Guice 20090217 BejugEnterprise Guice 20090217 Bejug
Enterprise Guice 20090217 Bejugrobbiev
 
Android httpclient php_mysql
Android httpclient php_mysqlAndroid httpclient php_mysql
Android httpclient php_mysql
Chalermchon Samana
 
第一次用Parse就深入淺出
第一次用Parse就深入淺出第一次用Parse就深入淺出
第一次用Parse就深入淺出
Ymow Wu
 
Parse Advanced
Parse AdvancedParse Advanced
Parse Advanced
Tushar Acharya
 
Dependency rejection and TDD without Mocks
Dependency rejection and TDD without MocksDependency rejection and TDD without Mocks
Dependency rejection and TDD without Mocks
Antya Dev
 
Using Java to interact with Firebase in Android
Using Java to interact with Firebase in AndroidUsing Java to interact with Firebase in Android
Using Java to interact with Firebase in Android
Magda Miu
 
Android Libs - Retrofit
Android Libs - RetrofitAndroid Libs - Retrofit
Android Libs - Retrofit
Daniel Costa Gimenes
 

What's hot (20)

Contract-driven development with OpenAPI 3 and Vert.x | DevNation Tech Talk
Contract-driven development with OpenAPI 3 and Vert.x | DevNation Tech TalkContract-driven development with OpenAPI 3 and Vert.x | DevNation Tech Talk
Contract-driven development with OpenAPI 3 and Vert.x | DevNation Tech Talk
 
End to end todo list app with NestJs - Angular - Redux & Redux Saga
End to end todo list app with NestJs - Angular - Redux & Redux SagaEnd to end todo list app with NestJs - Angular - Redux & Redux Saga
End to end todo list app with NestJs - Angular - Redux & Redux Saga
 
Appengine Java Night #2b
Appengine Java Night #2bAppengine Java Night #2b
Appengine Java Night #2b
 
Appengine Java Night #2a
Appengine Java Night #2aAppengine Java Night #2a
Appengine Java Night #2a
 
Intro to Retrofit 2 and RxJava2
Intro to Retrofit 2 and RxJava2Intro to Retrofit 2 and RxJava2
Intro to Retrofit 2 and RxJava2
 
#ajn3.lt.marblejenka
#ajn3.lt.marblejenka#ajn3.lt.marblejenka
#ajn3.lt.marblejenka
 
[Srijan Wednesday Webinar] Rails 5: What's in It for Me?
[Srijan Wednesday Webinar] Rails 5: What's in It for Me?[Srijan Wednesday Webinar] Rails 5: What's in It for Me?
[Srijan Wednesday Webinar] Rails 5: What's in It for Me?
 
Retrofit
RetrofitRetrofit
Retrofit
 
Java Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to MissJava Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to Miss
 
FullStack Reativo com Spring WebFlux + Angular
FullStack Reativo com Spring WebFlux + AngularFullStack Reativo com Spring WebFlux + Angular
FullStack Reativo com Spring WebFlux + Angular
 
Android getting started
Android getting startedAndroid getting started
Android getting started
 
Durable functions
Durable functionsDurable functions
Durable functions
 
iOS Keychain by 흰, 민디
iOS Keychain by 흰, 민디iOS Keychain by 흰, 민디
iOS Keychain by 흰, 민디
 
Enterprise Guice 20090217 Bejug
Enterprise Guice 20090217 BejugEnterprise Guice 20090217 Bejug
Enterprise Guice 20090217 Bejug
 
Android httpclient php_mysql
Android httpclient php_mysqlAndroid httpclient php_mysql
Android httpclient php_mysql
 
第一次用Parse就深入淺出
第一次用Parse就深入淺出第一次用Parse就深入淺出
第一次用Parse就深入淺出
 
Parse Advanced
Parse AdvancedParse Advanced
Parse Advanced
 
Dependency rejection and TDD without Mocks
Dependency rejection and TDD without MocksDependency rejection and TDD without Mocks
Dependency rejection and TDD without Mocks
 
Using Java to interact with Firebase in Android
Using Java to interact with Firebase in AndroidUsing Java to interact with Firebase in Android
Using Java to interact with Firebase in Android
 
Android Libs - Retrofit
Android Libs - RetrofitAndroid Libs - Retrofit
Android Libs - Retrofit
 

Similar to Data Loading Made Easy with Mike Nakhimovich DroidCon Italy 2017

Apache Calcite Tutorial - BOSS 21
Apache Calcite Tutorial - BOSS 21Apache Calcite Tutorial - BOSS 21
Apache Calcite Tutorial - BOSS 21
Stamatis Zampetakis
 
Adopting F# at SBTech
Adopting F# at SBTechAdopting F# at SBTech
Adopting F# at SBTech
Antya Dev
 
하이퍼커넥트 데이터 팀이 데이터 증가에 대처해온 기록
하이퍼커넥트 데이터 팀이 데이터 증가에 대처해온 기록하이퍼커넥트 데이터 팀이 데이터 증가에 대처해온 기록
하이퍼커넥트 데이터 팀이 데이터 증가에 대처해온 기록
Jaehyeuk Oh
 
twMVC#46 一探 C# 11 與 .NET 7 的神奇
twMVC#46 一探 C# 11 與 .NET 7 的神奇twMVC#46 一探 C# 11 與 .NET 7 的神奇
twMVC#46 一探 C# 11 與 .NET 7 的神奇
twMVC
 
Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC
Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVCConstruindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC
Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC
Emmanuel Neri
 
Change tracking
Change trackingChange tracking
Change tracking
Sonny56
 
Getting Started with Real-Time Analytics
Getting Started with Real-Time AnalyticsGetting Started with Real-Time Analytics
Getting Started with Real-Time Analytics
Amazon Web Services
 
Rethinking Syncing at AltConf 2019
Rethinking Syncing at AltConf 2019Rethinking Syncing at AltConf 2019
Rethinking Syncing at AltConf 2019
Joe Keeley
 
Wcf data services
Wcf data servicesWcf data services
Wcf data services
Eyal Vardi
 
Bringing JAMStack to the Enterprise
Bringing JAMStack to the EnterpriseBringing JAMStack to the Enterprise
Bringing JAMStack to the Enterprise
C4Media
 
Ft10 de smet
Ft10 de smetFt10 de smet
Ft10 de smetnkaluva
 
Working effectively with legacy code
Working effectively with legacy codeWorking effectively with legacy code
Working effectively with legacy codeShriKant Vashishtha
 
meetstore5.pdf
meetstore5.pdfmeetstore5.pdf
meetstore5.pdf
Mike Nakhimovich
 
Bootiful Development with Spring Boot and React - UberConf 2018
Bootiful Development with Spring Boot and React - UberConf 2018Bootiful Development with Spring Boot and React - UberConf 2018
Bootiful Development with Spring Boot and React - UberConf 2018
Matt Raible
 
Bootiful Development with Spring Boot and React - RWX 2017
Bootiful Development with Spring Boot and React - RWX 2017Bootiful Development with Spring Boot and React - RWX 2017
Bootiful Development with Spring Boot and React - RWX 2017
Matt Raible
 
Ingesting streaming data for analysis in apache ignite (stream sets theme)
Ingesting streaming data for analysis in apache ignite (stream sets theme)Ingesting streaming data for analysis in apache ignite (stream sets theme)
Ingesting streaming data for analysis in apache ignite (stream sets theme)
Tom Diederich
 
2015 09-02 - transaction log prototype
2015 09-02 - transaction log prototype2015 09-02 - transaction log prototype
2015 09-02 - transaction log prototype
David Heath
 
Marvel of Annotation Preprocessing in Java by Alexey Buzdin
Marvel of Annotation Preprocessing in Java by Alexey BuzdinMarvel of Annotation Preprocessing in Java by Alexey Buzdin
Marvel of Annotation Preprocessing in Java by Alexey Buzdin
Java User Group Latvia
 
Building a Real-Time Feature Store at iFood
Building a Real-Time Feature Store at iFoodBuilding a Real-Time Feature Store at iFood
Building a Real-Time Feature Store at iFood
Databricks
 
Spicy javascript: Create your first Chrome extension for web analytics QA
Spicy javascript: Create your first Chrome extension for web analytics QASpicy javascript: Create your first Chrome extension for web analytics QA
Spicy javascript: Create your first Chrome extension for web analytics QA
Alban Gérôme
 

Similar to Data Loading Made Easy with Mike Nakhimovich DroidCon Italy 2017 (20)

Apache Calcite Tutorial - BOSS 21
Apache Calcite Tutorial - BOSS 21Apache Calcite Tutorial - BOSS 21
Apache Calcite Tutorial - BOSS 21
 
Adopting F# at SBTech
Adopting F# at SBTechAdopting F# at SBTech
Adopting F# at SBTech
 
하이퍼커넥트 데이터 팀이 데이터 증가에 대처해온 기록
하이퍼커넥트 데이터 팀이 데이터 증가에 대처해온 기록하이퍼커넥트 데이터 팀이 데이터 증가에 대처해온 기록
하이퍼커넥트 데이터 팀이 데이터 증가에 대처해온 기록
 
twMVC#46 一探 C# 11 與 .NET 7 的神奇
twMVC#46 一探 C# 11 與 .NET 7 的神奇twMVC#46 一探 C# 11 與 .NET 7 的神奇
twMVC#46 一探 C# 11 與 .NET 7 的神奇
 
Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC
Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVCConstruindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC
Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC
 
Change tracking
Change trackingChange tracking
Change tracking
 
Getting Started with Real-Time Analytics
Getting Started with Real-Time AnalyticsGetting Started with Real-Time Analytics
Getting Started with Real-Time Analytics
 
Rethinking Syncing at AltConf 2019
Rethinking Syncing at AltConf 2019Rethinking Syncing at AltConf 2019
Rethinking Syncing at AltConf 2019
 
Wcf data services
Wcf data servicesWcf data services
Wcf data services
 
Bringing JAMStack to the Enterprise
Bringing JAMStack to the EnterpriseBringing JAMStack to the Enterprise
Bringing JAMStack to the Enterprise
 
Ft10 de smet
Ft10 de smetFt10 de smet
Ft10 de smet
 
Working effectively with legacy code
Working effectively with legacy codeWorking effectively with legacy code
Working effectively with legacy code
 
meetstore5.pdf
meetstore5.pdfmeetstore5.pdf
meetstore5.pdf
 
Bootiful Development with Spring Boot and React - UberConf 2018
Bootiful Development with Spring Boot and React - UberConf 2018Bootiful Development with Spring Boot and React - UberConf 2018
Bootiful Development with Spring Boot and React - UberConf 2018
 
Bootiful Development with Spring Boot and React - RWX 2017
Bootiful Development with Spring Boot and React - RWX 2017Bootiful Development with Spring Boot and React - RWX 2017
Bootiful Development with Spring Boot and React - RWX 2017
 
Ingesting streaming data for analysis in apache ignite (stream sets theme)
Ingesting streaming data for analysis in apache ignite (stream sets theme)Ingesting streaming data for analysis in apache ignite (stream sets theme)
Ingesting streaming data for analysis in apache ignite (stream sets theme)
 
2015 09-02 - transaction log prototype
2015 09-02 - transaction log prototype2015 09-02 - transaction log prototype
2015 09-02 - transaction log prototype
 
Marvel of Annotation Preprocessing in Java by Alexey Buzdin
Marvel of Annotation Preprocessing in Java by Alexey BuzdinMarvel of Annotation Preprocessing in Java by Alexey Buzdin
Marvel of Annotation Preprocessing in Java by Alexey Buzdin
 
Building a Real-Time Feature Store at iFood
Building a Real-Time Feature Store at iFoodBuilding a Real-Time Feature Store at iFood
Building a Real-Time Feature Store at iFood
 
Spicy javascript: Create your first Chrome extension for web analytics QA
Spicy javascript: Create your first Chrome extension for web analytics QASpicy javascript: Create your first Chrome extension for web analytics QA
Spicy javascript: Create your first Chrome extension for web analytics QA
 

Recently uploaded

Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
Ana-Maria Mihalceanu
 
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Albert Hoitingh
 
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
Alan Dix
 
Video Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the FutureVideo Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the Future
Alpen-Adria-Universität
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
Kari Kakkonen
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance
 
Uni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdfUni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems S.M.S.A.
 
Elizabeth Buie - Older adults: Are we really designing for our future selves?
Elizabeth Buie - Older adults: Are we really designing for our future selves?Elizabeth Buie - Older adults: Are we really designing for our future selves?
Elizabeth Buie - Older adults: Are we really designing for our future selves?
Nexer Digital
 
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
Neo4j
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance
 
20240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 202420240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 2024
Matthew Sinclair
 
Introduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - CybersecurityIntroduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - Cybersecurity
mikeeftimakis1
 
Elevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object CalisthenicsElevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object Calisthenics
Dorra BARTAGUIZ
 
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdfSAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
Peter Spielvogel
 
Climate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing DaysClimate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing Days
Kari Kakkonen
 
Microsoft - Power Platform_G.Aspiotis.pdf
Microsoft - Power Platform_G.Aspiotis.pdfMicrosoft - Power Platform_G.Aspiotis.pdf
Microsoft - Power Platform_G.Aspiotis.pdf
Uni Systems S.M.S.A.
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
Prayukth K V
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
James Anderson
 

Recently uploaded (20)

Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
 
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
 
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
 
Video Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the FutureVideo Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the Future
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
 
Uni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdfUni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdf
 
Elizabeth Buie - Older adults: Are we really designing for our future selves?
Elizabeth Buie - Older adults: Are we really designing for our future selves?Elizabeth Buie - Older adults: Are we really designing for our future selves?
Elizabeth Buie - Older adults: Are we really designing for our future selves?
 
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
 
20240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 202420240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 2024
 
Introduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - CybersecurityIntroduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - Cybersecurity
 
Elevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object CalisthenicsElevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object Calisthenics
 
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdfSAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
 
Climate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing DaysClimate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing Days
 
Microsoft - Power Platform_G.Aspiotis.pdf
Microsoft - Power Platform_G.Aspiotis.pdfMicrosoft - Power Platform_G.Aspiotis.pdf
Microsoft - Power Platform_G.Aspiotis.pdf
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
 

Data Loading Made Easy with Mike Nakhimovich DroidCon Italy 2017