goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit...

41
Going Reactive An architectural journey

Transcript of goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit...

Page 1: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

Going Reactive An architectural journey

Page 2: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler
Page 3: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

Going Reactive An architectural journey

Matthias KäpplerOctober 2015

Page 4: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

commit 24c61b35754ff5ca153ce37c5886279153f0d16fAuthor: Matthias Kaeppler <[email protected]>Date: Wed Mar 13 16:09:04 2013 +0100

Throw RxJava into the mix!

diff --git a/app/pom.xml b/app/pom.xmlindex 86ba988..1bf5109 100644--- a/app/pom.xml+++ b/app/pom.xml@@ -178,6 +178,11 @@

+ <dependency>+ <groupId>com.netflix.rxjava</groupId>+ <artifactId>rxjava-core</artifactId>+ <version>0.5.4</version>+ </dependency> </dependencies>

Page 5: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

Journey DownThe Stack

Page 6: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

Layered Architecture

Page 7: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

Featurized Architecture

Page 8: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

Featurized Layers

Page 9: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

The Sound Stream

Page 10: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

Layer Objects

Rx

Screen PresenterLife-cycle dispatch,

view binding

Feature OperationsBusiness logic, data

wiring, scheduling

Storage & APINetwork, database,

flat files, syncer

Rx[Android]

Page 11: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

Views

class SoundStreamFragment extends LightCycleSupportFragment {

@Inject @LightCycle SoundStreamPresenter presenter;

public SoundStreamFragment() { setRetainInstance(true); ... } ...}

Page 12: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

LightCycle

A

C

BonCreate LightCycle

Dispatcher

@LightCycle

@LightCycle

@LightCycle

Page 13: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

Presenters

class SoundStreamPresenter extends RecyclerViewPresenter<StreamItem> { ... @Override protected CollectionBinding<StreamItem> onBuildBinding(Bundle args) { return CollectionBinding.from( streamOperations.initialStreamItems()) .withAdapter(adapter) .withPager(streamOperations.pagingFunction()) .build(); }}

Page 14: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

Paging

Page 15: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

Paging

p1p2p3

*current*next

p1

onNext(p1)

subscribe() / next()

PublishSubject

switchOnNext

PagingFunction

Pager

Page 16: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

Use Cases

class SoundStreamOperations {

Observable<List<StreamItem>> initialStreamItems() { return loadFirstPageOfStream() .zipWith( facebookInvites.loadWithPictures(), prependFacebookInvites()) .subscribeOn(scheduler); }

...}

Page 17: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

Feature Data

class SoundStreamStorage {

Observable<PropertySet> streamItems(int limit) { Query query = Query.from(“SoundStreamTable”).limit(limit); return propellerRx.query(query).map(new StreamItemMapper()); }

...}

Page 18: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

Cross-Feature Communication

Page 19: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

Cross-Screen Messaging

updated!

Page 20: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

Screen-to-Screen Updates

Rx Subject

Page 21: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

Screen-to-Screen Updates

Observable<PropertySet> toggleLike(Urn urn, boolean addLike) { return storeLikeCommand.toObservable(urn, addLike) .map(toChangeSet(targetUrn, addLike)) .doOnNext(publishChangeSet);}

Page 22: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

Screen-to-Screen Updates

@Override public void call(PropertySet changeSet) { eventBus.publish( EventQueue.ENTITY_STATE_CHANGED, EntityStateChangedEvent.fromLike(changeSet) ); }

publishChangeSet: Action1<PropertySet>

RxSubject in disguise!

Page 23: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

Screen-to-Screen Updates

protected void onViewCreated(...) { eventBus.subscribe( EventQueue.ENTITY_STATE_CHANGED, new UpdateListSubscriber(adapter) );}

SoundStreamPresenter

Page 24: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

ImplementationPatterns

Page 25: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

Life-Cycle Subscriptions

private CompositeSubscription viewLifeCycle; protected void onViewCreated(...) { viewLifeCycle = new CompositeSubscription(); viewLifeCycle.add(...); ... } protected void onDestroyView() { viewLifeCycle.unsubscribe(); }

Page 26: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

Fast Path & Lazy Updates

Observable<Model> maybeCached() { return Observable.concat(cachedModel(), remoteModel()).first()}

Page 27: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

Observable Transformers

Observable<Model> scheduledModel() { return Observable.create(...).compose(schedulingStrategy)}

class HighPrioUiTask<T> extends Transformer<T, T> { public Observable<T> call(Observable<T> source) { return source .subscribeOn(Schedulers.HIGH_PRIO) .observeOn(AndroidSchedulers.mainThread()) }}

Page 28: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

Observable<Integer> intSequence() { return Observable.create((subscriber) -> { List<Integer> ints = computeListOfInts(); for (int n : ints) { subscriber.onNext(n); subscriber.onCompleted(); } }

Deferred Execution

Observable<Integer> intSequence() { return Observable.defer(() -> { return Observable.from(computeListOfInts()); }}

expensive!

Page 29: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

Common Pitfalls

Page 30: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

No-args subscribe

Observable.create(...).subscribe(/* no-args */)

OnErrorNotImplementedException

Page 31: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

ObserveOn: onError

Observable.create((subscriber) -> { subscriber.onNext(value); subscriber.onError(new Exception());}.observeOn(mainThread()).subscribe(...)

onError cuts ahead of onNext

gets dropped!

Page 32: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

ObserveOn: Backpressure

public void onStart() { request(RxRingBuffer.SIZE);}

public void onNext(final T t) { ... if (!queue.offer(on.next(t))) { onError(new MissingBackpressureException()); return; } schedule();}

16!

Page 33: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

ObserveOn: Backpressure

★ Take load off of target thread˝

★ Use buffering operators (buffer, toList, …)˝

★ Use onBackpressure* operators˝

★ System.setProperty(“rx.ring-buffer.size”)

Page 34: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

Debugging

Page 35: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

Debugging Observables

Observable.just(1, 2, 3) .map((n) -> {return Integer.toString(n);} .observeOn(AndroidSchedulers.mainThread());

How do we debug this?

Page 36: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

Gandalf

★ Annotation based byte code injection

★ Based on Hugo https://github.com/JakeWharton/hugo

★ AspectJ + Gradle plugin

★ @RxLogObservable, @RxLogSubscriber

Page 37: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

Gandalf

@RxLogObservableObservable<String> createObservable() { return Observable.just(1, 2, 3) .map((n) -> {return Integer.toString(n);} .observeOn(mainThread());}

@RxLogSubscriberclass StringSubscriber extends Subscriber<String> {}

Page 38: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

Gandalf

[@Observable :: @InClass -> MainActivity :: @Method -> createObservable()][@Observable#createObservable -> onSubscribe() :: @SubscribeOn -> main][@Observable#createObservable -> onNext() -> 1][@Observable#createObservable -> onNext() -> 2][@Observable#createObservable -> onNext() -> 3][@Observable#createObservable -> onCompleted()][@Observable#createObservable -> onTerminate() :: @Emitted -> 3 elements :: @Time -> 4 ms][@Observable#createObservable -> onUnsubscribe()]

Page 39: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler

.soundcloud.com

Berlin New York San Francisco London

Stay in touch @mttkay

Page 40: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler
Page 41: goto cph 2015 - GOTO Conferencegotocon.com/dl/goto-cph-2015/slides/MatthiasKppler... · commit 24c61b35754ff5ca153ce37c5886279153f0d16f Author: Matthias Kaeppler