Upgrade to Pro — share decks privately, control downloads, hide ads and more …

From Imperative To Reactive Thinking

From Imperative To Reactive Thinking

Todd Motto

July 10, 2017
Tweet

More Decks by Todd Motto

Other Decks in Programming

Transcript

  1. @
    todd
    motto
    @
    mrja
    me
    she
    nry

    View full-size slide

  2. "REACTIVE THINKING"

    View full-size slide

  3. "IMPERATIVE THINKING"

    View full-size slide

  4. DESIGN PATTERNS

    View full-size slide

  5. DISCOVERING PATTERNS
    Ob
    se
    rve
    r Pa
    tte
    rn
    Se
    que
    nce
    s a
    nd O
    pe
    ra
    tors

    View full-size slide

  6. OBSERVER PATTERN

    View full-size slide

  7. Observers
    Observable

    View full-size slide

  8. Consumers
    Producer

    View full-size slide

  9. SEQUENCES AND OPERATORS

    View full-size slide

  10. Producer
    Consumer

    View full-size slide

  11. Producer
    Pipeline
    Consumer

    View full-size slide

  12. Producer
    Pipeline
    Consumer

    View full-size slide

  13. Producer
    Pipeline
    (Sequence)
    .map()
    .filter()
    Consumer

    View full-size slide

  14. Producer
    Pipeline
    (Sequence)
    Produces values
    Business logic
    Final outcome
    Consumer

    View full-size slide

  15. Water
    heatWater() heatWater()

    View full-size slide

  16. Water
    heatWater() heatWater()
    addBeans() addBeans()

    View full-size slide

  17. Water
    heatWater() heatWater()
    addBeans() addBeans()
    addMilk()

    View full-size slide

  18. White coffee
    Water
    heatWater() heatWater()
    addBeans() addBeans()
    addMilk() Black coffee

    View full-size slide

  19. Consumer
    Producer
    Business logic
    Business logic
    Consumer

    View full-size slide

  20. PATTERNS DISCOVERED
    Ob
    se
    rve
    r Pa
    tte
    rn
    Se
    que
    nce
    s a
    nd O
    pe
    ra
    tors

    View full-size slide

  21. Imperative
    SOLUTION #1:

    View full-size slide

  22. Elements of our game
    1. James
    2. Todd
    3.
    4.
    5. Start

    View full-size slide

  23. Game Helpers
    6. const CHANCE_OF_BAD_THROW = 0.5;
    7.
    8. // Throw affects chances of catching
    9. function checkDropped(isBadThrow): boolean;
    1. // Helpers to move ball around in the game
    2. function addBall(player: Element): void;
    3. function removeBall(player: Element): void;
    4.
    5. // Simple 50/50 chance of bad throw
    We use the throw quality to determine whether the
    ball is caught or not.

    View full-size slide

  24. TODO
    1. S
    ta
    rt the ga
    me
    on `
    sta
    rtB
    tn` click
    2. Th
    row a
    nd ca
    tch
    the ball be
    twee
    n 2
    pla
    ye
    rs
    3. Check each
    th
    row to see if i
    t wa
    s “bad”
    4. Check ca
    tch, e
    ndi
    ng
    the ga
    me
    on d
    rop

    View full-size slide

  25. Starting the game
    1. function handleClick() {
    2. // our game code
    3. }
    4.
    5. startBtn.addEventListener('click', handleClick);

    View full-size slide

  26. TODO
    1. S
    ta
    rt the ga
    me
    on `
    sta
    rtB
    tn` click
    2. Th
    row a
    nd ca
    tch
    the ball be
    twee
    n 2
    pla
    ye
    rs
    3. Check each
    th
    row to see if i
    t wa
    s “bad”
    4. Check ca
    tch, e
    ndi
    ng
    the ga
    me
    on d
    rop

    View full-size slide

  27. 5. // TODO
    6. // - person1 starts with ball
    7. // - wait while they get ready to throw
    1. // Our two refs to the people DOM nodes
    2. throwAndCatchBetween(james, todd);
    3.
    4. function throwAndCatchBetween(person1, person2) {

    View full-size slide

  28. Core throwing and catching
    2. // person1 starts with ball
    1. function throwAndCatchBetween(person1, person2) {

    View full-size slide

  29. ...now for humans
    1. function throwAndCatchBetween(person1, person2) {
    2. // person1 starts with ball
    3. addBall(person1);
    4.
    5. // wait while they get ready to throw
    6. setTimeout(() => {
    7.
    8. // person1 throws ball
    9. removeBall(person1);
    10.
    11. // ball travels through the air
    12. setTimeout(() => {
    13.
    14. // person2 catches ball
    15. addBall(person2);
    16.
    17. // Back again!
    18. throwAndCatchBetween(person2, person1);
    19.
    Ball flies throught the air for 1 second before being
    caught.

    View full-size slide

  30. TODO
    1. S
    ta
    rt the ga
    me
    on `
    sta
    rtB
    tn` click
    2. Th
    row a
    nd ca
    tch
    the ball be
    twee
    n 2
    pla
    ye
    rs
    3. Check each
    th
    row to see if i
    t wa
    s “bad”
    4. Check ca
    tch, e
    ndi
    ng
    the ga
    me
    on d
    rop

    View full-size slide

  31. Check throw quality
    8. // person1 throws ball
    9. removeBall(person1);
    10. // capture if throw was bad
    11. const isBadThrow =
    12. Math.random() <= CHANCE_OF_BAD_THROW;
    1. function throwAndCatchBetween(person1, person2) {
    2. // person1 starts with ball
    3. addBall(person1);
    4.
    5. // wait while they get ready to throw
    6. setTimeout(() => {
    7.
    13.
    14. // ball travels through the air
    15. setTimeout(() => {
    16.
    17. // person2 catches ball
    18. addBall(person2);
    19.
    20. // Back again!
    21. throwAndCatchBetween(person2, person1);

    View full-size slide

  32. TODO
    1. S
    ta
    rt the ga
    me
    on `
    sta
    rtB
    tn` click
    2. Th
    row a
    nd ca
    tch
    the ball be
    twee
    n 2
    pla
    ye
    rs
    3. Check each
    th
    row to see if i
    t wa
    s “bad”
    4. Check ca
    tch, e
    ndi
    ng
    the ga
    me
    on d
    rop

    View full-size slide

  33. Check if ball was dropped
    10. // capture if throw was bad
    11. const isBadThrow =
    12. Math.random() <= CHANCE_OF_BAD_THROW;
    13.
    14. // ball travels through the air
    15. setTimeout(() => {
    16.
    17. if (checkDropped(isBadThrow)) {
    18. return // Game over: Ball dropped
    19. }
    3. addBall(person1);
    4.
    5. // wait while they get ready to throw
    6. setTimeout(() => {
    7.
    8. // person1 throws ball
    9. removeBall(person1);
    20.
    21. // person2 catches ball
    22. addBall(person2);
    23.
    24. // Back again!
    25. throwAndCatchBetween(person2, person1);
    26.

    View full-size slide

  34. 1. S
    ta
    rt the ga
    me
    on `
    sta
    rtB
    tn` click
    2. Th
    row a
    nd ca
    tch
    the ball be
    twee
    n 2
    pla
    ye
    rs
    3. Check each
    th
    row to see if i
    t wa
    s “bad”
    4. Check ca
    tch, e
    ndi
    ng
    the ga
    me
    on d
    rop

    View full-size slide

  35. Reactive
    SOLUTION #2:

    View full-size slide

  36. TODO
    1. Ob
    se
    rvableta
    rt b
    utton click
    s>
    2. Ob
    se
    rvablerowi
    ng
    the ball>
    3. Ob
    se
    rvabletchi
    ng (
    or not!)
    the ball>

    View full-size slide

  37. Observable
    6. // Start listening for clicks
    7. game$.subscribe();
    1. const startClick$ = Rx.Observable
    2. .fromEvent(startBtn, 'click');
    3.
    4. const game$ = startClick$;
    5.
    We subscribe to the Observable to begin actually
    listening for the start button click events.

    View full-size slide

  38. Turn a click into throw and catch!
    4. const game$ = startClick$
    5. .switchMap(
    6. handleThrowAndCatchBetween(james, todd)
    7. );
    1. const startClick$ = Rx.Observable
    2. .fromEvent(startBtn, 'click');
    3.
    8.
    9. // Start listening for clicks
    10. game$.subscribe();

    View full-size slide

  39. Core throwing and catching
    1. // Usage
    2. .switchMap(
    3. handleThrowAndCatchBetween(james, todd)
    4. );
    5.

    View full-size slide

  40. TODO
    1. Ob
    se
    rvableta
    rt b
    utton click
    s>
    2. Ob
    se
    rvablerson th
    rowi
    ng
    the ball>
    3. Ob
    se
    rvablerson ca
    tchi
    ng
    the ball>

    View full-size slide

  41. What events make up a "throw"?
    1. // person1 starts with ball
    2. addBall(person1);
    3.
    4. // wait while they get ready to throw
    5. setTimeout(() => {
    6.
    7. // person1 throws ball
    8. // capture if throw was bad
    9. removeBall(person1);
    10. const isBadThrow =
    11. Math.random() <= CHANCE_OF_BAD_THROW;
    12.
    We can extract the relevant concepts from our
    imperative example...

    View full-size slide

  42. Observable
    1. // capture if throw was bad
    2. const isBadThrow =
    3. Math.random() <= CHANCE_OF_BAD_THROW;
    4.
    5. const throw$ = Rx.Observable.of(isBadThrow);
    We can make our initial throw$ stream encapsulate the
    throw quality (so we can evaluate it later).

    View full-size slide

  43. Observable
    9. // ball travels through the air
    10. .delay(1000);
    1. // capture if throw was bad
    2. const throw$ = Rx.Observable.of(isBadThrow)
    3. // person1 starts with ball
    4. .do(() => addBall(person1))
    5. // wait while they get ready to throw
    6. .delay(1000)
    7. // person1 throws ball
    8. .do(() => removeBall(person1))

    View full-size slide

  44. Observable
    4. return Rx.Observable.of(isBadThrow)
    5. .do(() => addBall(person))
    6. .delay(1000)
    7. .do(() => removeBall(person))
    8. .delay(1000);
    9. }
    1. function handleThrow$From(person) {
    2. const isBadThrow =
    3. Math.random() <= CHANCE_OF_BAD_THROW;

    View full-size slide

  45. "Plug in" the throwing for p1 and p2
    1. // Usage
    2. .switchMap(
    3. handleThrowAndCatchBetween(james, todd)
    4. );
    5.

    View full-size slide

  46. TODO
    1. Ob
    se
    rvableta
    rt b
    utton click
    s>
    2. Ob
    se
    rvablerson th
    rowi
    ng
    the ball>
    3. Ob
    se
    rvablerson ca
    tchi
    ng
    the ball>

    View full-size slide

  47. What events make up a "catch"?
    5. // Ball is caught succesfully
    6. return Rx.Observable.of('')
    7. .do(() => addBall(person))
    1. // Ball is dropped
    2. if (checkDropped(isBadThrow)) {
    3. return Rx.Observable.throw(`Ball dropped`)
    4. }
    If the ball is caught, we return an Observable (the
    value isn't important) and add the ball to the person
    as normal.

    View full-size slide

  48. Observable
    2. // The returned function will be used within
    1. function handleCatch$By(person) {
    The `isBadThrow` value will be passed in via the
    switchMap from the previous throw$

    View full-size slide

  49. "Plug in" the throwing for p1 and p2
    1. // Usage
    2. .switchMap(
    3. handleThrowAndCatchBetween(james, todd)
    4. );
    5.

    View full-size slide

  50. 1. Ob
    se
    rvableta
    rt b
    utton click
    s>
    2. Ob
    se
    rvablerson th
    rowi
    ng
    the ball>
    3. Ob
    se
    rvablerson ca
    tchi
    ng
    the ball>

    View full-size slide

  51. Thank you!
    @
    to
    dd
    motto
    / @
    mr
    ja
    m
    e
    s
    he
    nry

    View full-size slide