Slide 1

Slide 1 text

RxJS Patterns Towards Formalising Common RxJS Patterns @elmd_ Dominic Elm @KwintenP Kwinten Pisman

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

const show$ = this.sourceJokes$.pipe( skip(1), mapTo(true), ); const hide$ = this.update$.pipe(mapTo(false)); const showNotificationSettings$ = this.settingsService.settings$.pipe( select(({ showNotifications }) => showNotifications), ); this.showNotification$ = showNotificationSettings$.pipe( switchMap(showNotifications => { if (showNotifications) { return merge(show$, hide$).pipe(startWith(false)); } return of(false); }), );

Slide 4

Slide 4 text

@elmd_ Dominic Elm @KwintenP Kwinten Pisman thoughtram https://thoughtram.io StackBlitz https://stackblitz.com strongbrew https://strongbrew.io jsbe https://jsbe.io

Slide 5

Slide 5 text

https://angular-checklist.io @elmd_ @KwintenP

Slide 6

Slide 6 text

Reactive Programming

Slide 7

Slide 7 text

[ ] Arrays @elmd_ @KwintenP

Slide 8

Slide 8 text

Observables @elmd_ @KwintenP

Slide 9

Slide 9 text

Observable - producer: function + subscribe(observer: Observer)
 : Subscription @elmd_ @KwintenP Anatomy of an Observable

Slide 10

Slide 10 text

Patterns

Slide 11

Slide 11 text

“In software engineering, a software design pattern is a general, reusable solution to a commonly occurring problem within a given context in software design.”

Slide 12

Slide 12 text

Different Levels of Patterns OPERATORS PATTERNS RECIPES @elmd_ @KwintenP

Slide 13

Slide 13 text

Patterns by Example

Slide 14

Slide 14 text

World of Jokes @elmd_ @KwintenP

Slide 15

Slide 15 text

@elmd_ @KwintenP What we need is a list of jokes that is cached. This cache should be updated every 10 seconds. If the call fails, we obviously want to retry this call every 5 seconds, but only when we are online. Makes no sense to retry with no internet connection. Now, these jokes should be shown on the screen but only update on demand when the user requests an update… oh and don't forget to notify the user that there is new data available. And obviously everything, the polling interval, the notifications and polling itself must be configurable. In case one of these settings are updated, we must restart everything! Request from your Manager ”

Slide 16

Slide 16 text

@elmd_ @KwintenP

Slide 17

Slide 17 text

Divide & Conquer

Slide 18

Slide 18 text

@elmd_ @KwintenP Problem Sub-Problem A Sub-Problem B Solution to Problem Solution to Sub-Problem B Solution to Sub-Problem A

Slide 19

Slide 19 text

Whenever you have a difficult situation, just split it up, fix the small parts and reassemble everything back together to get the final solution! SCHRUTE’s TIP #1

Slide 20

Slide 20 text

What we need is a list of jokes that is cached. This cache should be updated every 10 seconds. If the call fails, we obviously want to retry this call every 5 seconds, but only when we are online. Makes no sense to retry with no internet connection. Now, these jokes should be shown on the screen but only update on demand when the user requests an update… oh and don't forget to notify the user that there is new data available. And obviously everything, the polling interval, the notifications and polling itself must be configurable. In case one of these settings are updated, we must restart everything! Request from your Manager @elmd_ @KwintenP ”

Slide 21

Slide 21 text

”The list of jokes should be updated every 5 seconds. Requirement #1 @elmd_ @KwintenP

Slide 22

Slide 22 text

Pattern Detection

Slide 23

Slide 23 text

WHEN Trigger HOW WHAT Identifying Patterns @elmd_ @KwintenP Result Pattern

Slide 24

Slide 24 text

Triggers and results should always be streams. If the are not streams, create streams yourself. SCHRUTE’s TIP #2

Slide 25

Slide 25 text

WHEN every 5 seconds WHAT cachedJokes$ that updates every 5 seconds The list of jokes should be updated every 5 seconds. ” Requirement #1 HOW when the trigger fires, send HTTP request to fetch the list of jokes @elmd_ @KwintenP

Slide 26

Slide 26 text

@elmd_ @KwintenP JokesListComponent SettingsDialogComponent JokesService SettingsService Application Architecture

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

Pattern #1 Work that needs to be executed n times (n > 1) const result$ = trigger$.pipe( (_ !=> work$) ); Repeater Kwinten - Dominic

Slide 29

Slide 29 text

Translate the written requirement into the WHAT, WHEN and HOW! SCHRUTE’s TIP #3

Slide 30

Slide 30 text

” Requirement #2 jokes$ that is updated on demand when the trigger fires when the user manually requests the data extracting the most recent version of the data from the cache @elmd_ @KwintenP WHEN HOW WHAT When new data is available, the user has to manually request the latest version of the jokes to be shown on the screen.

Slide 31

Slide 31 text

No content

Slide 32

Slide 32 text

Enricher Pattern #2 Lazily enrich a stream with data when the trigger fires const result$ = trigger$.pipe( withLatestFrom(enricherSource$), map(([trigger, data]) !=> ), );

Slide 33

Slide 33 text

” Requirement #3 showNotifcation$ that hides or shows a notification when an update is available (or none is available) create two triggers (show and hide) and merge them @elmd_ @KwintenP WHEN HOW WHAT If an update is available, the user should see a notification to update the list of jokes.

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

Group Aggregator Pattern #3 Whenever the result is an Observable const FT$ = falseTrigger$.pipe(mapTo(false)); const TT$ = trueTrigger$.pipe(mapTo(true)); const result$ = merge(FT$, TT$);

Slide 36

Slide 36 text

” Requirement #4 settings$ that encapsulates state when the user changes one of the settings keep and update state when the trigger fires @elmd_ @KwintenP WHEN HOW WHAT The user should be able to manage settings, that can be updated in a dialog.

Slide 37

Slide 37 text

State should always be managed within a stream. SCHRUTE’s TIP #4

Slide 38

Slide 38 text

No content

Slide 39

Slide 39 text

State Manager Pattern #4 State that needs to be reactively managed const result$ = trigger$.pipe( scan((prevState, updates) !=> { return { …prevState, …updates } }) );

Slide 40

Slide 40 text

Use the State Manager pattern as a minimalistic alternative to state management libraries like redux. SCHRUTE’s TIP #5

Slide 41

Slide 41 text

It should be possible to toggle the notifications and polling ” Requirement #5 jokes$ and showNotification$ conditionally stopping and starting of the notifications and polling @elmd_ @KwintenP WHEN HOW WHAT showNotification or enablePolling changes

Slide 42

Slide 42 text

No content

Slide 43

Slide 43 text

Work Decider Pattern #5 Work that needs to be stopped and restarted when some trigger fires const result$ = trigger$.pipe( (condition !=> { if (condition) workA$;
 else workB$; }) );

Slide 44

Slide 44 text

Use observables as the boundaries between services and components. SCHRUTE’s TIP #6

Slide 45

Slide 45 text

”If fetching the list fails we want to retry fetching it. If we are offline, we only want to retry if we are back online. Otherwise, retry every 1 seconds with max of 5. Requirement #6 @elmd_ @KwintenP

Slide 46

Slide 46 text

Whenever you have a difficult situation, just split it up, fix the small parts and reassemble it to the solution! SCHRUTE’s TIP #1 REMEMBER

Slide 47

Slide 47 text

If fetching the list fails we want to retry it. ” Requirement #6.1 @elmd_ @KwintenP

Slide 48

Slide 48 text

If we are offline, we only want to retry if we are online.Otherwise, retry every 1 second with a max of 5. ” Requirement #6.2 if we are offline, do A (retry when online), otherwise do B (retry every second, max 5). @elmd_ @KwintenP WHEN HOW WHAT cachedJokes$ when an error occurs (call to the backend fails)

Slide 49

Slide 49 text

No content

Slide 50

Slide 50 text

Error Decider Recipe #6 Work that needs to be stopped and restarted when some trigger fires const result$ = trigger$.pipe( retryWhen(error$ !=> { return error$.pipe(switchMap(_ !=> { if (condition) workA$;
 else workB$; })) )} ); X

Slide 51

Slide 51 text

From Pattern to Operator

Slide 52

Slide 52 text

SCHRUTE’s TIP #6 When you have a pattern in your app that keeps on repeating, transform it into an operator!

Slide 53

Slide 53 text

Key Takeaway’s @elmd_ @KwintenP Divide & Conquer Patterns Pattern Detection Custom Operators

Slide 54

Slide 54 text

@elmd_ @KwintenP Think Reactive ! Everything is a Stream

Slide 55

Slide 55 text

Thank you! @elmd_ @KwintenP