gts episode 1: reactive programming in the wild
TRANSCRIPT
![Page 1: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/1.jpg)
Reactive Programming in the wild
Omer Iqbal
Yang Bo
![Page 2: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/2.jpg)
Functional Reactive Programming
![Page 3: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/3.jpg)
Why?
![Page 4: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/4.jpg)
![Page 5: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/5.jpg)
Listeners/Delegates/Observers/Callbacks!
![Page 6: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/6.jpg)
DeathStarDelegate
DeathStar
didBlowUp:
[self fireStormTroopers]
![Page 7: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/7.jpg)
Problems1. Unpredictable Order2. Missing Events3. Cleaning up listeners4. Accidental Recursion5. Messy State6. Multithreading is a PAIN
![Page 8: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/8.jpg)
![Page 9: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/9.jpg)
![Page 10: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/10.jpg)
"our intellectual powers are rather geared to master static relations and that our powers to visualize processes evolving in time are relatively
poorly developed"
![Page 11: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/11.jpg)
Model events as composable values!
![Page 12: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/12.jpg)
Signals/Observables
next next next
completed
next next
error
![Page 13: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/13.jpg)
Creating a Signal- (RACSignal *)login {
return [RACSignal createSignal:^(id<RACSubscriber> subscriber){
[LoginManager loginWithSuccess:^(data){
[subscriber sendNext:data];
[subscriber sendCompleted];
} error:^(NSError *error){
[subscriber sendError:error];
}];
}];
}
![Page 14: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/14.jpg)
Using a signal
[[self login] subscribeNext:^(id response){
} error:^(NSError *error){
} completed:^(){
}];
![Page 15: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/15.jpg)
[vader login:^(id response, NSError *error) { if (error) { return; } [vader blowUpSomePlanets:^(id response, NSError *error) { if (error) { return; } [vader haveBrekkie:^(id response, NSError *error) { if (error) { return; } [vader playWithKids:^(id response, NSError *error) { if (error) { return; } }]; }]; }]; }];
![Page 16: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/16.jpg)
Composition! [[[[vader login] flattenMap:^RACStream *(id value) { return [vader blowUpSomePlanets]; }] flattenMap:^RACStream *(id value) { return [vader haveBrekkie]; }] flattenMap:^RACStream *(id value) { return [vader playWithKids]; }];
![Page 17: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/17.jpg)
flattenMap
![Page 18: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/18.jpg)
merge
![Page 19: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/19.jpg)
combineLatest
![Page 20: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/20.jpg)
Network RequestsRACSignal *buddies = [self requestBuddyList];RACSignal *chats = [self requestChatList];
[RACSignal combineLatest:@[buddies, chats] reduce:^id (NSArray<GxxUser *> *users, NSArray <GxxChat *> *chats){ // .. process here }];
![Page 21: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/21.jpg)
Composable UI FlowsGCActionViewController *vc = [GCActionViewController new];
RACSignal *camera = [[vc addButtonTitle:@"Take Photo"] flattenMap:^(){
return [self presentCameraAndTakeImage];}];
RACSignal *picker = [[vc addButtonTitle:"Choose Existing"] flattenMap:^(){
return [self presentImageSelect];}];
RACSignal *cancel = [[vc didTapCancel] flattenMap:^(){return [RACSignal error:[GCErrorUtility userCancelled]];
}];
return [RACSignal merge:@[camera, picker, cancel]];
![Page 22: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/22.jpg)
iOS
![Page 23: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/23.jpg)
ReactiveCocoa vs RxSwift
● If you’re on objective C, you don’t have a choice -> ReactiveCocoa 2.0
● RxSwift follows standard Rx conventions borrowed from RxJS, RxJava.
● ReactiveCocoa (Swift) has an awesome API with sexy operators which breaks
over Swift versions
● ReactiveCocoa (Swift) distinguishes between hot and cold signals
![Page 24: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/24.jpg)
Problems
![Page 25: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/25.jpg)
Hot Signals
● Easy to miss events● Beware of the phantom subscribe blocks● Always unsubscribe when not needed!
![Page 26: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/26.jpg)
[didUpdateUsers takeUntil:[self rac_willDeallocSignal]]
takeUntil is your best friend
![Page 27: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/27.jpg)
Cold Signals● Only perform work when subscribed to e.g Network Request, UI Flow● Beware of multiple subscribers! ● Use RACMulticast or convert to Hot Signal if multiple subscribers are needed
![Page 28: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/28.jpg)
AndroidYang Bo
![Page 29: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/29.jpg)
“modern apps are event-driven”
![Page 30: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/30.jpg)
System Broadcast○ Internet connectivity
○ Doze mode
○ Download progress
Lifecycle App enters:
○ Foreground
○ Background
Custom Events○ Connection established
○ User logged in
○ Data updated
○ ...
![Page 31: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/31.jpg)
EventBus
![Page 32: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/32.jpg)
Hard truths○ Throttling control
○ Grouping events
○ Higher-order events
○ Error handling and retry
○ Cache and replay
○ ...
![Page 33: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/33.jpg)
R X J A V AANDROID
RxJava to the rescue!
![Page 34: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/34.jpg)
Rx-based Framework Design
![Page 35: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/35.jpg)
Push PullMix
Choices of protocol
![Page 36: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/36.jpg)
Store NodeLatest snapshot of data
Push model
![Page 37: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/37.jpg)
Store NodeIncremental update
Push model
![Page 38: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/38.jpg)
Store NodeInvalidity
Pull model
Request data
![Page 39: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/39.jpg)
Characteristics of “pull” model✓ Throttling-friendly
✓ Controlled memory footprint
✘ Performance cost of requery
![Page 40: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/40.jpg)
Building blocks○ Network manager
public Observable<Response> send(Request request) { ...
}
○ Database manager
public <T> Observable<T> exec(Query<T> query) { ...
}
![Page 41: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/41.jpg)
Framework architecture
UI Data Stream Layer Local Store
ACTION UPDATE
NOTIFY
FETCH
PUSH
![Page 42: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/42.jpg)
Traditional approach
ContactUIData
Name: “44”Icon: “xxxx”
...
Database
User #1
User #2
User #3
User #4
Converter
Task (one-shot)
![Page 43: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/43.jpg)
Data Stream Layer
ContactUIData
Name: “44”Icon: “xxxx”
...
Database
User #1
User #2
User #3
User #4
Data Stream Layer
![Page 44: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/44.jpg)
Data Stream Layer
Database
User #1
User #2
User #3
User #4
Data Stream Layer
Trigger
Filter + Throttle
Provider
Subscriber
NOTIFY
FETCH
![Page 45: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/45.jpg)
Data Stream Layer
Database
User #1
User #2
User #3
User #4
Data Stream Layer
Trigger
Filter + Throttle
Provider
Subscriber
PUSH
![Page 46: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/46.jpg)
#1. Setup once, always up-to-date
![Page 47: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/47.jpg)
#2. Decouple UI from update logic
![Page 48: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/48.jpg)
#3. Unidirectional data flow
![Page 49: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/49.jpg)
Challenges○ Backpressure
![Page 50: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/50.jpg)
Cold observableObservable.range(1, 1000000)
.observeOn(Schedulers.io())
.doOnNext(new Action1<Object>() {
@Override
public void call(Object o) {
// slow ops
}
})
.subscribe();
![Page 51: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/51.jpg)
Hot observableBehaviorSubject.create(new Object())
.observeOn(Schedulers.io())
.doOnNext(new Action1<Object>() {
@Override
public void call(Object o) {
// slow ops
}
})
.subscribe();
No backpressure support!
![Page 52: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/52.jpg)
BehaviorSubject.create(new Object())
.onBackpressureDrop()
.observeOn(Schedulers.io())
.doOnNext(new Action1<Object>() {
@Override
public void call(Object o) {
// slow ops
}
})
.subscribe();
![Page 53: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/53.jpg)
Challenges○ Custom operator?
map concat merge flatMap concatMap switchMap combineLatest from
range create just first firstOrDefault last startWith zip join
switchOnNext amb retry repeat debounce sample defaultIfEmpty
skipUntil skipWhen switchCase takeUntil contains exists isEmpty
distinctUntilChanged share publish refCount replay filter skip
timeout max min reduce count collect toList toMap scan buffer
window cast cache timestamp observeOn subscribeOn delay timer
interval doOnNext doOnComplete doOnError onErrorReturn ...
DON’T BOTHER
![Page 54: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/54.jpg)
Challenges○ Memory leaks
Remember to unsubscribe, always
Subscription subscription = Observable.range(1, 1000000)
.subscribe();
subscription.unsubscribe();
![Page 55: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/55.jpg)
Summary○ Intro to Reactive Programming
○ Practical application in mobile development
○ Pitfalls & Challenges
![Page 56: GTS Episode 1: Reactive programming in the wild](https://reader031.vdocument.in/reader031/viewer/2022030305/58729f061a28ab07208b5579/html5/thumbnails/56.jpg)
Thanks