Open sourcing the store
-
Upload
mike-nakhimovich -
Category
Technology
-
view
308 -
download
0
Transcript of Open sourcing the store
![Page 1: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/1.jpg)
Open Sourcing the StoreWhat we open sourced and how you can too!
Mike Nakhimovich - New York Times
![Page 2: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/2.jpg)
Agenda For TodayWalkthrough of New York Times’ first Android
Open Source Library
How you can make open source a library yourself
![Page 3: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/3.jpg)
Problem Set
Modern Android Apps need their data representations to be fluid and always available.
Users expect their UI experience to never be compromised (blocked) by new data loads
International users expect minimal data downloads
![Page 4: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/4.jpg)
Android === Open Source
Libraries fill gaps left by framework
Network Client? OKHTTP/Retrofit
Threading/Functional Programming? RxJava
Dependency Injection? Dagger
View Bindings? Butterknife
![Page 5: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/5.jpg)
Android === Open Source
Libraries fill gaps left by framework
Network Client? OKHTTP/Retrofit
Threading/Functional Programming? RxJava
Dependency Injection? Dagger
View Bindings? Butterknife
Store? Data Flow & Caching
![Page 6: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/6.jpg)
Introducing Store
https://github.com/NYTimes/Store
![Page 7: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/7.jpg)
A Store abstracts fetching, parsing, caching, and retrieval of data in
your application.
![Page 8: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/8.jpg)
Stores are configurable and enforce uni-direcitonal data flow while
exposing data as RxJava Observables
![Page 9: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/9.jpg)
Sounds Great, but how do I use them?
![Page 10: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/10.jpg)
Add to build.gradle
compile 'com.nytimes.android:store:1.0.1'
![Page 11: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/11.jpg)
Open A Store
Store<Article> articleStore = StoreBuilder.<Article>builder()
.open();
![Page 12: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/12.jpg)
Add a fetcher
public interface Fetcher<T> {
Observable<T> fetch(BarCode barCode);
}
Store<Article> articleStore = StoreBuilder.<Article>builder()
.fetcher(barCode -> api.getArticle(barCode.getKey()))
.open();
![Page 13: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/13.jpg)
Or NonObservable Fetcher
Use nonObservbleFetcher when connecting to a synchronous & non observable API
Store<Article> articleStore = StoreBuilder.<Article>builder()
.nonObservableFetcher(barCode -> api.getArticle(barCode.getKey()))
.open();
![Page 14: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/14.jpg)
Call your Store with a Barcode...
BarCode barcode = new BarCode("Article", "42");
articleStore.fetch(barcode)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Article>() {
public void onCompleted() {}
public void onError(Throwable throwable) {//handle error} public void onNext(Article article) {//bind Article to UI}});
![Page 15: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/15.jpg)
Fetch Dataflow (Unidirectional)
Same request <1min will get throttled response
![Page 16: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/16.jpg)
Getting Cached Data
![Page 17: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/17.jpg)
articleStore.get(barcode)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Article>() {
public void onCompleted() {}
public void onError(Throwable throwable) {//handle error} public void onNext(Article article) {//bind Article to UI}});
Note: if nothing cached get() will act exactly like fetch()
Getting Cached Data
![Page 18: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/18.jpg)
Note: if nothing cached get() will act exactly like fetch()
Get Dataflow
![Page 19: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/19.jpg)
What happens if we need to transform response?Adding a Parser
![Page 20: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/20.jpg)
Adding a Parser
Store<Article> articleStore = ParsingStoreBuilder.<BufferedSource, Article>builder() .fetcher(barCode -> api.getSource(barCode.getKey()))
.parser(source -> {
try (InputStreamReader reader = new InputStreamReader(source.inputStream())) {
return gson.fromJson(reader, Article.class);
} catch (IOException e) {
throw new RuntimeException(e);} })
.open();
![Page 21: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/21.jpg)
Dataflow with Parser
![Page 22: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/22.jpg)
Introducing Middleware
![Page 23: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/23.jpg)
Use our Middleware
Before:
.parser(source -> {
try (InputStreamReader reader = new InputStreamReader(source.inputStream())) {
return gson.fromJson(reader, Article.class);
} catch (IOException e) {
throw new RuntimeException(e);} })
![Page 24: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/24.jpg)
Use our Middleware
Before:.parser(source -> {
try (InputStreamReader reader = new InputStreamReader(source.inputStream())) {
return gson.fromJson(reader, Article.class);
} catch (IOException e) {
throw new RuntimeException(e);} })
After:
.parser(new GsonSourceParser<>(gson, Article.class))
![Page 25: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/25.jpg)
Disk Caching
ParsingStoreBuilder.<BufferedSource, Article>builder() .fetcher(barCode -> api.getSource(barCode.getKey())) .parser(new GsonSourceParser<>(gson, Article.class)) .persister(new Persister<BufferedSource>() { public Observable<BufferedSource> read(BarCode barCode) { return Observable.fromCallable(() -> diskCache.get(barCode)); } public Observable<Boolean> write(BarCode barCode, BufferedSource source) { diskCache.save(barCode, source); return Observable.just(true); }}) .open();
![Page 26: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/26.jpg)
Dataflow with Cache
![Page 27: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/27.jpg)
No Need to implement yourself
articleStore = ParsingStoreBuilder.<BufferedSource, Article>builder() .fetcher(barCode -> api.getSource(barCode.getKey())) .parser(new GsonSourceParser<>(gson, Article.class)) .persister(new SourcePersister(FileSystemFactory.create(getFilesDir()))) .open();
![Page 28: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/28.jpg)
Hope you’ll use StoresAnd contribute back to the project
![Page 29: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/29.jpg)
Part 2How to go from 0 to Open Source Project
![Page 30: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/30.jpg)
Android Studio Create a Project
![Page 31: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/31.jpg)
Add a library module
![Page 32: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/32.jpg)
Add some code to library
![Page 33: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/33.jpg)
Use Android Studio to create Github Project
![Page 34: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/34.jpg)
Add a Descriptive Readme.md
● Who is project for?
● What was motivation for creation?
● What does it do?
● How does it do it?
![Page 35: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/35.jpg)
Add a License
![Page 36: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/36.jpg)
Part 2B: How to upload project to Maven Central
![Page 37: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/37.jpg)
Create a Sonatype Jira Account (yes really)
![Page 38: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/38.jpg)
Open A ticket to claim an organization
![Page 39: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/39.jpg)
Wait for Response
![Page 40: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/40.jpg)
Whats a GPG Key?
![Page 41: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/41.jpg)
Use GPG to create a keyhttp://central.sonatype.org/pages/working-with-pgp-signatures.html
![Page 42: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/42.jpg)
Add to top level gradle.properties (don’t check into github!)
![Page 43: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/43.jpg)
Add to library module gradle.properties
![Page 44: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/44.jpg)
Add to top level build.gradle
![Page 45: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/45.jpg)
Add Gradle Maven Plugin & Script
https://github.com/NYTimes/Store/blob/develop/gradle/maven-push.gradle
![Page 46: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/46.jpg)
Run UploadArchives task
![Page 47: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/47.jpg)
Go To Nexus Staging Repo to Verify
https://oss.sonatype.org/index.html#stagingRepositories
![Page 48: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/48.jpg)
Close staging Repo and Deploy to Maven Central
![Page 49: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/49.jpg)
Update jira with successful first upload
![Page 50: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/50.jpg)
Enable Travis
![Page 51: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/51.jpg)
Add Travis.yml
![Page 52: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/52.jpg)
Add Contributing.md
![Page 53: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/53.jpg)
Submit a talk to GDG
![Page 54: Open sourcing the store](https://reader035.fdocuments.in/reader035/viewer/2022062821/5886d1921a28ab776a8b48df/html5/thumbnails/54.jpg)
Thanks for listening