Reactive programming, DAMN. It is not about ReactJs Samuele Resca CODEMOTION MILAN - SPECIAL EDITION 10 – 11 NOVEMBER 2017
https://samueleresca.net @samueleresca 2
This talk is NOT about ReactJS. It is a talk, NOT a workshop. https://samueleresca.net @samueleresca 3
This talk is about Reactive programming It is language independent(..but) It is pattern oriented https://samueleresca.net @samueleresca 4
“Reactive programming is an asynchronous programming paradigm concerned with data streams and the propagation of change.” - Wikipedia https://samueleresca.net @samueleresca 5
Reactive systems are: responsive, resilient, elastic, message driven. http://www.reactivemanifesto.org/ https://samueleresca.net @samueleresca 6
Start to think functional https://samueleresca.net @samueleresca 7
Immutability, first-class functions, higher- order functions https://samueleresca.net @samueleresca 8
Immutability https://samueleresca.net @samueleresca 9 const message = "Hello Codemotion!"; const result = message.toUpperCase(); console.log(message); //message -> Hello Codemotion! console.log(result); //result -> HELLO CODEMOTION!
First-class functions Higher-order functions https://samueleresca.net @samueleresca 10 const myArr = [ 5, 10, 4, 50, 3 ]; const multiplesOfFive = myArr.filter( (num) => num % 5 === 0 );
Immutability, first-class functions, higher- order functions https://samueleresca.net @samueleresca 11
ReactiveX http://reactivex.io/ https://samueleresca.net @samueleresca 12
The best idea from Observer pattern, Iterator pattern and functional programming. https://samueleresca.net @samueleresca 13
The Observer pattern lets a number of observers get notified when something changes in a subject that they are observing. https://samueleresca.net @samueleresca 14
https://samueleresca.net @samueleresca 15 For each observer in observers call observer.Update()
Iterator pattern lets us abstract how we iterate over a specific collection by wrapping this iteration inside an object and providing a uniform API. https://samueleresca.net @samueleresca 16
https://samueleresca.net @samueleresca 17 The Iterator <<interface>> provide an abstraction over the ListIterator class.
The best idea from Observer pattern, Iterator pattern and functional programming. https://samueleresca.net @samueleresca 18
NOT ONLY a Javascript library https://samueleresca.net @samueleresca 19
https://samueleresca.net @samueleresca 20
https://samueleresca.net @samueleresca 21 [1,2,3].map(value=>value*10) .forEach(value=> console.log(value) ); //10 //20 //30
https://samueleresca.net @samueleresca 22 Observable.of(1,2,3) .map(value=>value*10) .subscribe(value=> console.log(value) ); //10 //20 //30
https://samueleresca.net @samueleresca 23 /** * A representation of any set of values over any amount of time. This is the most basic building block * of RxJS. * * @class Observable<T> */ export declare class Observable<T> implements Subscribable<T>
https://samueleresca.net @samueleresca 24 subscribe( next?: (value: T) => void, error?: (error: any) => void, complete?: () => void): Subscription;
Array is a collection of items Observable is a collection of items over time https://samueleresca.net @samueleresca 25
Observable represents a stream https://samueleresca.net @samueleresca 26
https://samueleresca.net @samueleresca 27 button.addEventListener('click',event=>{ console.log("DAMN, you clicked"); });
https://samueleresca.net @samueleresca 28 Observable.fromEvent(button, 'click') .subscribe(event=> { console.log(”DAMN, you clicked"); });
https://samueleresca.net @samueleresca 29 Observable.fromEvent(button, 'click') .debouceTime(500) .subscribe(event=> { console.log(”DAMN, you clicked"); });
https://samueleresca.net @samueleresca 30 combineAll, combineLatest concat, concatAll, forkJoin, merge, mergeAll, race, startWith, withLatestFrom, zip Combination defaultIfEmpty, everyConditional Error handling catch, retry, retryWhen Filtering debounce, debounceTime, distinctUntilChanged, filter, first, ignoreElements, last, sample, single, skip, skipUntil, skipWhile, take, takeUntil, takeWhile, throttle, throttleTime Transformation buffer, bufferCount, bufferTime, bufferToggle, bufferWhen, concatMap, concatMapTo, expand, exhaustMap, groupBy, map, mapTo, mergeMap, partition, pluck, scan, switchMap, window, windowCount, windowTime, windowToggle, windowWhen
https://samueleresca.net @samueleresca 31 http://rxmarbles.com/
Everything is a data stream Operators make logic easy and functional https://samueleresca.net @samueleresca 32
https://samueleresca.net @samueleresca 33 Case of study @ Netflix Observable everywhere. App startup, Player, Data access, Animations, View/Model binding, Logging
https://samueleresca.net @samueleresca 34 Netflix JavaScript Talks - Async JavaScript with Reactive Extensions function play(movieId, cancelButton, callback) { var movieTicket, playError, tryFinish = function () { if (playError) { callback(null, playError); }else if (movieTicket && player.initialized) { callback(null, ticket); } }; cancelButton.addEventListener("click", function () { playError = "cancel"; }); if (!player.initialized) { player.init(function () { playError = error; tryFinish(); }); } authorizeMovie(movieId, function (error, ticket) { playError = error; movieTicket = ticket; tryFinish(); }); }
https://samueleresca.net @samueleresca 35 Netflix JavaScript Talks - Async JavaScript with Reactive Extensions var authorizations = player .init() .map(() => playAttemps .map(movieId => player.authorize(movieId) .retry(3) .takeUntil(cancels)) .concatAll()) .concatAll(); authorizations.forEach( license => player.play(license), error => showError() );
https://samueleresca.net @samueleresca 36 Reactive extensions provide better codebases: functional, less is more, async error handling, concurrency made easy
https://samueleresca.net @samueleresca 37 "Legacy code is any code without tests" - Michael Feathers
https://samueleresca.net @samueleresca 38 Functional design is testable
https://samueleresca.net @samueleresca 39 Reactive extensions are covered by unit tests http://reactivex.io/rxjs/test.html
https://samueleresca.net @samueleresca 40 Two testing techniques: standard, scheduler testing
https://samueleresca.net @samueleresca 41 it("Should call AWESOME APIs for the resource "100456733922"", (done) => { //ARRANGE | setting up the test variables const resource = '100456733922'; const url = "https://awesome.apis.com/v1/resource/" + resource; //ACT | Observable.fromPromise is our SUT const testFn = query => Rx.Observable.fromPromise(preparePromise(query)) .subscribe(data => { //ASSERT | check the response of the AJAX request expect(data).toHaveProperty("data") expect(data).toHaveProperty("data.result") expect(data.data.result.length).toBe(10) }, null, done); testFn(url); });
https://samueleresca.net @samueleresca 42 new Rx.TestScheduler();
https://samueleresca.net @samueleresca 43 Observable.of(1,2,3) .map(value=>value*10) .subscribe(value=> console.log(value) );
https://samueleresca.net @samueleresca 44
https://samueleresca.net @samueleresca 45 Rx.TestScheduler.createColdObservable('-1-2--3--|');
https://samueleresca.net @samueleresca 46 //it does not emit values, until someone trigger the //subscription createColdObservable<T>(marbles: string, values?: any, error?: any): ColdObservable<T> //immediate, it does not wait the subscribe method //to emit values createHotObservable<T>(marbles: string, values?: any, error?: any): HotObservable<T>
https://samueleresca.net @samueleresca 47 Rx.TestScheduler.createColdObservable('-1-2--3--|');
https://samueleresca.net @samueleresca 48 it('Should multiply values by 10', () => { //ARRANGE | initialize TestScheduler constructor let scheduler = new Rx.TestScheduler(); let stubObs = scheduler.createColdObservable('-1-2--3--|'); //ACT | perform the map operation let result = stubObs. map((value) => value * 10); //ASSERT | check the result scheduler //ASSERT | it should be an observable .expectObservable(result) //ASSERT | it should have the expected structure, with the correct values .toBe('-a-b--c--|', { 'a': 10, 'b': 20, 'c': 30 }); scheduler.flush(); });
https://samueleresca.net @samueleresca 49 Reactive extension helps us to deal with the async behavior of reactive code Reactive code is test-friendly
https://samueleresca.net @samueleresca 50 Demo: Say What Muddafukaaa!!!! https://www.barbarianmeetscoding.com/ https://github.com/samueleresca/reactive-programming-damn
https://samueleresca.net @samueleresca 51
Start to think using an Reactive approach https://samueleresca.net @samueleresca 52
https://samueleresca.net @samueleresca 53 /* gameLoop$ | simply define an loop, it is triggered each INTERVAL_GAME time */ const gameLoop$: Observable<number> = Observable.interval(GameVars.INTERVAL_GAME) /* background$ | define an observable of type new Background() */ const background$: Observable<Background> = Observable.of(new Background())
https://samueleresca.net @samueleresca 54 const game$ : Observable<any> = // every INTERVAL_GAME time gameLoop$ // gather all my observables with game objects .combineLatest(background$, (_, b) => { return [b]; }) // and update and draw them .subscribe((gameObjects) => { gameObjects .forEach(g => { g.update() g.draw() }) });
https://samueleresca.net @samueleresca 55
Let’s add some letters https://samueleresca.net @samueleresca 56
https://samueleresca.net @samueleresca 57 //initialize the letters$ observable const letters$: Observable<Letter[]> = Observable //trigger itself every INVERVAL_LETTER time .interval(GameVars.INTERVAL_LETTER) //generate new random letter in random position .map(_ => new Letter(Words.getRandomLetter(), Drawings.getRandomPosition(0, 500), 0)) //push generated letter in an array of letter .scan((letters, newLetter) => { console.log('generate new letter'); letters.push(newLetter) return letters }, [])
https://samueleresca.net @samueleresca 58
https://samueleresca.net @samueleresca 59 /* combine the letters$ observable with the gameLoop$ by using the combineLatest operator*/ const game$ = gameLoop$ .combineLatest(background$, letters$, (_,b,l) => { const gameObjects = [b, ...l] return gameObjects })
Catch the player speech using Annyang https://samueleresca.net @samueleresca 60
https://samueleresca.net @samueleresca 61 //map each caught word with an action const commands = { '*word': word => { console.log('user said: ', word); userWords$.next(word); } export function configureVoiceRecognition(commands: Object) { // Add our commands to annyang annyang.addCommands(commands); // Start listening. You can call this here, or attach this call to an event, button, etc. annyang.start(); }
https://samueleresca.net @samueleresca 62 const userWords$ = new Subject() //combine the userWords$ subject with our game$ const userWordsAndGame$ = game$ .combineLatest(userWords$, (gameObjects, userWord) => { return { gameObjects, userWord } }) .distinct(o => o.userWord) //distinct to prevent duplicate .subscribe((gou) => { //check if word matches with some letters Words.matchWords(gou, function () { //if the check is positive.. console.log('matched word') console.log('scored!'); ScoreSubject.next(100) }); Drawings.appendToDom(gou.userWord); });
Tracking player score https://samueleresca.net @samueleresca 63
https://samueleresca.net @samueleresca 64 const ScoreSubject = new Subject() /* use the ScoreSubject to create score pipeline */ const score$: Observable<Score> = ScoreSubject .startWith(0) .map((v: number) => new Score(v)) /* we use scan operator to track the points */ .scan((prev, cur) => prev.add(cur), new Score(0))
isDead() https://samueleresca.net @samueleresca 65
https://samueleresca.net @samueleresca 66 // player$ | manage player data const player$: Observable<Player> = Observable //initialize a new player .of(new Player(340, 20, GameVars.LIVES)); const game$ = gameLoop$ .combineLatest(background$, letters$, score$, player$, (_,b,l,s,p) => { const gameObjects = {letters: l, player: p, all: [b, s, p, ...l]} return gameObjects }) // takeWhile | iterate game loop until player is dead .takeWhile(go => !go.player.isDead())
All together now! https://samueleresca.net @samueleresca 67
https://samueleresca.net @samueleresca 68 Reactive extensions give us the ability to handle events and react to data using some higher level abstractions.
https://samueleresca.net @samueleresca 69 It might not be the type of library you rely on to solve one problem in the application.
https://samueleresca.net @samueleresca 70 BE HUMBLE.
https://samueleresca.net @samueleresca 71 References barbarianmeetscoding.com Netflix JavaScript Talks – Async JavaScript with Reactive Extensions Netflix JavaScript Talks – Real-time Insights powered by Reactive Programming The introduction to Reactive Programming you've been missing
https://samueleresca.net @samueleresca 72 https://samueleresca.net @samueleresca (280 chars are enough)

Samuele Resca - REACTIVE PROGRAMMING, DAMN. IT IS NOT ABOUT REACTJS - Codemotion Milan 2017

Editor's Notes

  • #4 Well, this talk is not about a popular framework. It tries covers some principles which can be applied on client-side and server-side. It is a talk, NOT a workshop. We ‘ll see a lot of theory behind the concept of Reactive programming.
  • #5 Well, this talk is clearly focused on reactive programming. It is language independent, but we will cover a lot of examples using typescript and javascript It is pattern oriented because we will discover patterns around reactive system.
  • #6 Here is the definition of reactive programming. Nowdays, more than ever, The important part of our systems are data and events. Our code manage a huge amount of data, and it collect information from a lot of sources: GPS, Extenal system like social network, media content and so on.
  • #7 Reactive programming is to the base of reactive systems. A reactive system is defined by being responsive, resilient, elastic and message-driven. These four characteristic of reactive system are definened in the reactive manifesto. Responsiveness of a system is established by the time it takes for the system to respond. A shorter time to respond means the system is more responsive; Resilient system is one that stays responsive in the case of failure. In other words, you want to handle failures in a way that does not prevent the user from getting response; Elasticity (scalabilty) it needs to span instances as the load increases and remove instances as the load decreases. This behavior is introduced by cloud systems. Message driven each part of our system communicates by
  • #8 Functional way of thinking influenced the way Rx was designed and used.
  • #9 Functional cames with a lot of characteristics: first-class function, higher-order functions, lexical clousre immutable data, lazy evaluation. Just a quick overview on immutability and First-class function
  • #10 In the functional programming, most of the functions do not have side effects. In other words, the function doesn't change state inside the object Immutability: You cannot modify the object state. Immutable object: is an object whose state cannot be modified after it is created. We define a string We apply the .toUpperCase function And we the message in console The value remains the same, because of immutability
  • #11 Let’s take a look to the first-class functions and higher-order function: First-class function: means that the function is like other language primitives. It can be passed as an argument and be returned from a function; High-order function: means a function that receive functions as their arguments or return function as their return value;
  • #12 All theese priciples are the base of funcitional programming. They can be used to improve readbilty and testability of our code.
  • #13 Now, let’s talk about reactive extensions. ReactiveX was born from Volta project in 2010. The Volta project was an experimental developer toolset for creating multitier applications for the cloud, before the term cloud was formally defined. The project failed but it has bring to life other tools such as Typescript and Reactive Extensions. From Volta project also born another famous IL, Typescript.
  • #14 Reactive extensions groups the best idea from observer pattern, iterator pattern and functional programming
  • #15 The Observer pattern was introduced by gang of four in 1994.
  • #16 The observer pattern is useful but it has point of weakness: If you want to attach to more than one subject or more than one event, you need to implement more update methods; The pattern doesn’t specify the best way to handle errors, and it’s up to the developer to find a way to notify of errors; Finally, you do not know when the subject have done its work , it can be crucial for correct resource management. The Reactive extensions are based on the Observer design pattern but extend it to solve these shortcomings.
  • #17 ReactiveX also extends iterator pattern. Iterator pattern abstracts an collection of events by wrapping them and provides an uniform APIs
  • #18 In addition, this pattern is effective at decoupling the business logic applied at each element from the itera-tion itself. The goal is to provide a single protocol for accessing each element and mov- ing on to the next https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#iterator
  • #20 It is not only a javascript library, you can find it on Scala, Java, C# and others
  • #21 Reactive extension are used by some COOL consumers
  • #22 Let's see some code The following sinppet takes an array of numbers and, it multiplies each value by 10. Finally, it prints each value to the console. Now
  • #23 The same result can be achieved by using Reactive extensions. As you can see, the following snippet defines an Observable which comes from RxJs library and it wraps the collection of values and provides an Subscribe method. Let’s focus on theese two components: Observable Subscribe method
  • #24 Observable is the most basic building of RXjs, and also of all reactive extensions in general.
  • #25 The Subscribe operator is the glue that connects Observable and whatever Observer. next?: notifies an observer of a new element in the observable sequence; error?: notifies the observer that an exception was occurred; completed?: notifies the observer that the observable sequence has completed and no more notifications will be emitted
  • #26 but, why should we wrap our array using observable ? Well, the key point is that
  • #27 In fact, observable represents a stream of data. Any time of stream:
  • #28 Just a quick look to another example: We add an event listener to a button and
  • #29 Also the event binding can be achieved by using RxJs. The fromEvent can wrap events on DOM elements. Now, let’s suppose that the click event triggers an AJAX call and users do not have any type of visual feedback. And our PM asks us to prevent click spam on the button…
  • #30 We may add an operator like debounceTime to reduce click spamming. Operator is a nice way to say operations. They are part of a Domain specific language (DSL), which describes event processing in a declarative-way. create pipelines of querying, trasformation.
  • #31 Operators are methods on the Observable type, such as .map(...), .filter(...), .merge(...), etc. When called, they do not change the existing Observable instance. Instead, they return a new Observable, whose subscription logic is based on the first Observable.
  • #32 A picture is worth a thousand words. A common way to describe the execution pipeline of observable sequences is Marble diagrams. In the marble diagram, time goes from left to right Each event is represented by using a symbol. The distance between the symbols shows the amount of time that has passed between the two events. To show that the observable has completed, you use the | (pipe) symbol. To show that an error occurred (which also ends the observable), you use X.
  • #33 Now, just a quick recap: Everything is a data stream; Operators make logic easy and functional;
  • #34 Netflix is a true lover of Reactive programming and reactive extensions.
  • #35 I take this snippet from a Netflix engineering(engegniring) talk. The Ilink is @ the bottom of slide It is a snippet of code which descries some behavior of a video player. It contains a combination of: Events; Callbacks; Conditional branching
  • #36 The following code implements the same logics by using a reactive approach. No more branching Much more linear; @ the bottom you can find the complete talk from netflix It exactly shows the power of reactive extensions
  • #37 Just a quick summary of Reactive extensions power. Here are some benefits you gain by adopting reactive extensions
  • #38 “Legacy code is any code without tests”. This strong statement came from Michael Feathers (Fathers), a software engineer and an author of a popular book about refactoring. Well, test are useful for a lot of reasons: They help us to prevent errors; describe the requirements inside our code; They can be used as a sort of documentation of the expected behaviors inside our application;
  • #39 If some code is not testable, it is a sign that it is smell code. In general, functional design is testable, because: Pure functions are focused on small in scope, An ideal (aidial) function is isolated, and in conclusion, is testable.
  • #40 Also, RxJs framework is tested itself. The following link take to the tests report of the framework.
  • #41 In general, there are two techniques to deal with tests in a reactive world: The standard testing and scheduler testing.
  • #42 Well, in the following example tests an AJAX call managed by using reactive extensions. RxJs to use the benefits of reactive code on javascript promises. It uses Jest, powered by Facebook, as testing framework. We setup our test variables; We perform the action on our SUT, in that case it will be the Observable.fromPromise method. It is a nice way to use the power of reactive extension on a promises Finally, we make some assertions. In that case we want to check the response of our AJAX request;
  • #43 The other way is by using the TestScheduler. It is provided by Reactive extension Well, it uses the concept of marble diagrams to test code pipelines.
  • #44 Let take the previous example. Well, it can be described by using the following marble diagram
  • #45 This is the marble diagram which describe the previous pipeline. In order to test that code we should proceed by stubbing our input flow.
  • #46 To do that, we should use createColdObservable, which is provided by TestScheduler class; These method is useful to generate a new observable. It accept an unique parameter which is a text representation of a marble diagram: Each dash represent time frame; Each number is a value inside our observable;
  • #47 Just a quick side note about the difference between a cold observable and an hot observable: Cold observables only start running when someone subscribes to them. They don’t do anything at all until someone calls subscribe method; Hot observables, in opposition, are immediate. They emit values even before they have active subscribers.
  • #48 Let’s go back to our code
  • #49 This is an example of scheduler testing. First of all, we initialize a new TestScheduler. Then we use the createColdObservable method to stub a new observable; We perform an action, the next step is to perform the map operation on the stub observable; Then we declare the expected structure of the result observable; Finally, we check the result. It should be an observable, The test will replace each letter inside the expected string with the correct value;
  • #50 Just a quick summary about testing on reactive extensions: Reactive code is test friendly; Reactive extension helps us to deal with the async behavior of reactive code, by providing a way to reproduce async collections of items;
  • #51 Now, I show you a demo of reactive programming applied to a game: Say what muddafukaaaa!! The first project of that game came from Jaime González García, a friend that actually live in Sweden. Check it out his blog. He usually writes about JavaScript angular and so on Well, I implemented that project by combining reactive programming and Typescript.
  • #52 Let me present the game: Random letters in random positions falls down from the top of the screen; The goal of the game is to accumulate points by pronouncing words which starts with the falling letters; The game uses the voice APIs to recognize player words; If a letter exit from the screen the player loses a life; This is a very good example of reactive extensions application, because there are a lot of data streams and event.
  • #53 In order to think in a reactive way, all the components inside our game should be represented as streams.
  • #54 First of all we should generates an gameLoop by using an interval operator The gameLoop should be triggered each INTERVAL_GAME (The Interval operator returns an Observable that emits an infinite sequence of ascending integers, with a constant interval of time of your choosing between emissions.) We also need a background for our game. To do that we create a background observable. The background class will have some methods to generate a background using a canvas object.
  • #55 Here is all these components together. As you can see we use a game loop to combine each element on the array In order to represent a background we can include it in our game by making it be a part of our game loop, by using combineLatest (The combineLatest operator combines multiple observables. It combines then in a way that every time one of these source observables emits a value, the resulting observable emits another value that contains all the latest values pushed by the original streams.) The combineLatest operator is a way to merge all the observables into one streams. Each time one of the observables changes, the subscribe method will be triggered
  • #56 I show you the Marble diagram In order to show you the power of combineLatest operator
  • #57 The next step would be to add some letters falling from the top of the screen.
  • #58 Also in that case we should use an observable combined with an interval. For each INTERVAL_WORD; Generate a new random letter in a random position; Push the generated letter in an array of letter;
  • #59 (The Scan operator applies a function to the first item emitted by the source Observable and then emits the result of that function as its own first emission.) Applies an accumulator function over the source and returns each intermediate result, with an optional seed value.
  • #60 Where we accumulate our letters inside an array every 2 seconds. It just remains to add them to our game by including them inside our game$ observable:
  • #61 The next steps is to catch the player words by using Annyang. annyang is a tiny javascript library which wraps browser voice API and catch user words
  • #62 As you can see, the setup of annyang is very simple. We provide a commands object: For each word we declare an action (It maps words and trigger an observable which is defined in the next slide) We bind the commands; And we start the monitoring
  • #63 Here is the declaration of the userWords$ observable. It will be a Subject. A Subject is a special Rx.js object that works just like as an observer and an observable.  Also in that case: We combine userWords$ with the game$ observable; We use distinct method to prevent duplicates; We use the subscribe method to check if word matches with some letter; It the check is positive we print some stuff to the console an increment user points
  • #64 Let’s continue by adding a way to manage scores. We need to be able to both monitoring scores and have a way to display them within the game. Just like we did with the player words, we want to create a subject to push new score.
  • #65 Well, We declare a subject; And we create a pipeline with the following subject; And we use scan to add score each time;
  • #66 We also need to manage the game over feature
  • #67 We define a player observable by using a Player class. (LAIVS) We combine our player observable with the game loop. And we use takeWhile to iterate the observable until the player is dead
  • #68 As you have seen in the previous slide, we push the score inside an Score Subject. Let’s see how to manage the score.
  • #69 Well, Reactive extensions provides an high level abstraction over data streams.
  • #70 They should not be used solve a specific problem in our application. They may be used over all the application layers, both client-side but also server-side
  • #71 BE HUBLE. Does not try to convert all your application layers to Reactive approach. Start with a single layer and understand the benefits.
  • #72 Here is some nice resources about reactive programming and reactive extensions