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

What if the user was a function?

What if the user was a function?

An exploration of the true nature of user interfaces, and a cyclic async functional architecture which captures the essence of UIs and any other form of interaction.

André Staltz

May 14, 2015
Tweet

More Decks by André Staltz

Other Decks in Programming

Transcript

  1. “Easier to reason about”

    View full-size slide

  2. Reactive programming

    View full-size slide

  3. Unidirectional dataflow
    Functional reactive programming
    Immutable data structures
    Virtual DOM
    One-way data binding Dispatcher
    Flux
    Cursors
    Shadow DOM
    Components
    State and props
    Purity
    JavaScript in 2015
    Declarative
    Isomorphic

    View full-size slide

  4. Golden ratio

    View full-size slide

  5. Golden ratio
    Natural
    Beautiful
    Complex

    View full-size slide

  6. Equivalent

    in JavaScript

    UIs?

    View full-size slide

  7. What if the user

    was a function?
    @andrestaltz
    Exploring unidirectional dataflow, MV*, 

    reactive and functional programming

    View full-size slide

  8. Human
    Computer

    View full-size slide

  9. Insight #1: UIs are cycles

    View full-size slide

  10. “Output device” “Input device”

    View full-size slide

  11. Function f
    Input
    Output
    x
    f(x)

    View full-size slide

  12. Insight #1: UIs are cycles
    Insight #2: UIs are functions

    View full-size slide

  13. Blocking UIs

    View full-size slide

  14. Non-blocking UIs

    View full-size slide

  15. js jscon jsconf jsconf budap
    jsonline

    jstor
    js.com.ph

    jsconsole
    jsconf 2014

    jsconf 2015
    jsconf budapest
    Computer

    View full-size slide

  16. a•syn•chro•nous
    adj. Not synchronous; occurring at different times.
    adj. Allows the other to continue during processing.

    View full-size slide

  17. Insight #1: UIs are cycles
    Insight #2: UIs are functions

    Insight #3: UIs are async

    View full-size slide

  18. Interface
    Senses Expression

    View full-size slide

  19. Expression Senses
    Expression
    Senses
    Symmetry

    View full-size slide

  20. Insight #1: UIs are cycles
    Insight #2: UIs are functions

    Insight #3: UIs are async
    Insight #4: UIs are symmetric

    View full-size slide

  21. Output Input
    Output
    Input
    Symmetry

    View full-size slide

  22. User
    Scroll
    Scroll
    Scroll
    Click
    Scroll
    Scroll

    View full-size slide

  23. Insight #1: UIs are cycles
    Insight #2: UIs are functions

    Insight #3: UIs are async
    Insight #4: UIs are symmetric
    Insight #5: The User is a function

    View full-size slide

  24. How to code this?

    View full-size slide

  25. Computer
    jsconfbp.com
    Given URL…
    …render website.

    View full-size slide

  26. [2,  4,  6]
    ?

    View full-size slide

  27. [2,  4,  6]
    map(x  =>  10*x)
    [20,  40,  60]

    View full-size slide

  28. [2,  4,  6]
    filter(x  =>  x  <  5)
    [2,  4]

    View full-size slide

  29. map(x&=>&10*x)
    2
    20 40 60
    4 6

    View full-size slide

  30. filter(x)=>)x)<)5)
    2
    2 4
    4 6

    View full-size slide

  31. time
    Things happening at certain times

    View full-size slide

  32. time
    Events!
    Event Stream

    View full-size slide

  33. Array: sequence over space.
    Event Stream: sequence over time.

    View full-size slide

  34. delay
    2 4 6 8
    2 4 6 … ∞

    View full-size slide

  35. combineLatest

    View full-size slide

  36. withLatestFrom

    View full-size slide

  37. Computer
    jsconfbp.com
    interactionEvents
    screenEvents

    View full-size slide

  38. function  computer(x:  EventStream):  EventStream  {  
       //  ...  
    }
    1  
    2  
    3

    View full-size slide

  39. var  screenEvents  =  computer(interactionEvents);  
    screenEvents.listen(function  (ev)  {  ...  });  
    1  
    2

    View full-size slide

  40. User
    Scroll
    Scroll
    Scroll
    Click
    Scroll
    Scroll interactionEvents
    screenEvents

    View full-size slide

  41. function  user(screenEvents:  EventStream):  EventStream  {  
       //  one  does  not  simply  write  this  function  
    }
    1  
    2  
    3

    View full-size slide

  42. Scroll
    Scroll
    Scroll
    Click
    Scroll
    Scroll interactionEvents
    screenEvents
    User

    View full-size slide

  43. Scroll
    Scroll
    Scroll
    Click
    Scroll
    Scroll interactionEvents
    screenEvents
    Screen Eyes
    DOM Brain Hands
    DOM Event Dispatcher

    View full-size slide

  44. Scroll
    Scroll
    Scroll
    Click
    Scroll
    Scroll interactionEvents
    screenEvents
    Screen Eyes
    DOM Brain Hands
    DOM Event Dispatcher
    These

    are all 

    we need

    View full-size slide

  45. Scroll
    Scroll
    Scroll
    Click
    Scroll
    Scroll interactionEvents
    screenEvents
    Screen Eyes
    DOM Brain Hands
    DOM Event Dispatcher
    These

    are

    "remote"

    View full-size slide

  46. function  user(screenEvents:  EventStream):  EventStream  {  
       screenEvents.listen(function  (screen)  {  
           renderToDOM(screen);  
       });  
       var  interactionEvents  =  new  EventStream();

       document.addEventListener("*",  function  (ev)  {

           interactionEvents.emit(ev);  
       });

       return  interactionEvents;

    }
    1  
    2  
    3  
    4  
    5  
    6  
    7  
    8  
    9  
    10

    View full-size slide

  47. function  user(screenEvents:  EventStream):  EventStream  {  
       screenEvents.listen(function  (screen)  {  
           renderToDOM(screen);  
       });  
       var  interactionEvents  =  new  EventStream();

       document.addEventListener("*",  function  (ev)  {

           interactionEvents.emit(ev);  
       });

       return  interactionEvents;

    }
    1  
    2  
    3  
    4  
    5  
    6  
    7  
    8  
    9  
    10

    View full-size slide

  48. function  user(screenEvents:  EventStream):  EventStream  {  
       screenEvents.listen(function  (screen)  {  
           renderToDOM(screen);  
       });  
       var  interactionEvents  =  new  EventStream();

       document.addEventListener("*",  function  (ev)  {

           interactionEvents.emit(ev);  
       });

       return  interactionEvents;

    }
    1  
    2  
    3  
    4  
    5  
    6  
    7  
    8  
    9  
    10

    View full-size slide

  49. function  user(screenEvents:  EventStream):  EventStream  {  
       screenEvents.listen(function  (screen)  {  
           renderToDOM(screen);  
       });  
       var  interactionEvents  =  new  EventStream();

       document.addEventListener("*",  function  (ev)  {

           interactionEvents.emit(ev);  
       });

       return  interactionEvents;

    }
    1  
    2  
    3  
    4  
    5  
    6  
    7  
    8  
    9  
    10

    View full-size slide

  50. var  interactionEvents  =  user(screenEvents);  
    interactionEvents.listen(function  (ev)  {  ...  });  
    1  
    2

    View full-size slide

  51. var  screenEvents  =  computer(interactionEvents);

    var  interactionEvents  =  user(screenEvents);
    1  
    2
    Equivalent to…

    View full-size slide

  52. var  a  =  f(b);

    var  b  =  g(a);
    1  
    2

    View full-size slide

  53. var  a  =  f(b);

    var  b  =  g(a);
    1  
    2

    View full-size slide

  54. var  b  =  g(f(b));
    1
    Problem!

    View full-size slide

  55. var  b  ←  g(f(b));
    1
    “=” is assignment!
    What other types of “=”?

    View full-size slide

  56. Definition: a fixed point of a function f(x)

    is a point x0 such that f(x0) = x0.
    Example: cos(0.73908513…) = 0.73908513…

    View full-size slide

  57. Problem: Find screenEvents such that
    screenEvents = computer(user(screenEvents).

    View full-size slide

  58. var  screenEvents  =  computer(interactionEvents);

    var  interactionEvents  =  user(screenEvents);
    1  
    2
    㱺 interactionsEvents needs to exist 

    before applying computer() function

    View full-size slide

  59. var  interactionEvents  =  makeEmptyEventStream();  
    var  screenEvents  =  computer(interactionEvents);

    var  interactionEvents2  =  user(screenEvents);
    1  
    2  
    3  
    4

    View full-size slide

  60. var  interactionEvents  =  makeEmptyEventStream();  
    var  screenEvents  =  computer(interactionEvents);

    var  interactionEvents2  =  user(screenEvents);
    1  
    2  
    3  
    4

    View full-size slide

  61. var  interactionEvents  =  makeEmptyEventStream();  
    var  screenEvents  =  computer(interactionEvents);

    var  interactionEvents2  =  user(screenEvents);
    1  
    2  
    3  
    4

    View full-size slide

  62. First screen
    Computer
    User
    interactionEvents
    interactionEvents2
    screenEvents

    View full-size slide

  63. Computer
    User
    interactionEvents
    interactionEvents2
    screenEvents

    View full-size slide

  64. Computer
    User
    interactionEvents
    interactionEvents2
    screenEvents

    View full-size slide

  65. var  interactionEvents  =  makeEmptyEventStream();  
    var  screenEvents  =  computer(interactionEvents);

    var  interactionEvents2  =  user(screenEvents);  
    interactionEvents2.listen(function  (ev)  {  
       interactionEvents.emit(ev);  
    });
    1  
    2  
    3  
    4  
    5  
    6  
    7  
    8

    View full-size slide

  66. var  interactionEvents  =  makeEmptyEventStream();  
    var  screenEvents  =  computer(interactionEvents);

    user(screenEvents).listen(function  (ev)  {  
       interactionEvents.emit(ev);  
    });
    1  
    2  
    3  
    4  
    5  
    6

    View full-size slide

  67. var  interactionEvents  =  makeEmptyEventStream();  

    user(computer(interactionEvents))

       .listen(function  (ev)  {  
           interactionEvents.emit(ev);  
       });
    1  
    2  
    3  
    4  
    5  
    6
    b = g(f(b))

    View full-size slide

  68. Computer
    Huge!

    View full-size slide

  69. Updates Manipulates
    Manipulates
    Sees Uses






    View full-size slide

  70. Model
    View
    User
    ???

    View full-size slide

  71. Model
    View
    User
    ???
    01010001010110101
    What’s up? ❤

    View full-size slide

  72. Model
    View
    User
    ???
    Information
    User language

    View full-size slide

  73. Model
    View
    User
    ???
    Information
    User language
    New information
    User language

    View full-size slide

  74. Model
    View
    User
    Intent
    Information
    User language
    New information
    User language

    View full-size slide

  75. Intent
    View
    Model
    or…

    View full-size slide

  76. function
    function
    or…

    View full-size slide

  77. https://github.com/staltz/cycle
    Cycle.js
    Powered by RxJS

    View full-size slide

  78. var  interactionEvents  =  makeEmptyEventStream();  
    var  screenEvents  =  computer(interactionEvents);

    var  interactionEvents2  =  user(screenEvents);  
    interactionEvents2.listen(function  (ev)  {  
       interactionEvents.emit(ev);  
    });
    1  
    2  
    3  
    4  
    5  
    6  
    7  
    8

    View full-size slide

  79. var  interactionEvents  =  makeEmptyEventStream();  
    var  screenEvents  =  computer(interactionEvents);

    var  interactionEvents2  =  user(screenEvents);  
    interactionEvents2.listen(function  (ev)  {  
       interactionEvents.emit(ev);  
    });
    1  
    2  
    3  
    4  
    5  
    6  
    7  
    8
    Boilerplate

    View full-size slide

  80. var  interactionEvents  =  makeEmptyEventStream();  
    var  screenEvents  =  computer(interactionEvents);

    var  interactionEvents2  =  user(screenEvents);  
    interactionEvents2.listen(function  (ev)  {  
       interactionEvents.emit(ev);  
    });
    1  
    2  
    3  
    4  
    5  
    6  
    7  
    8
    Mutation

    View full-size slide

  81. var  interactionEvents  =  makeEmptyEventStream();  
    var  screenEvents  =  computer(interactionEvents);

    var  interactionEvents2  =  user(screenEvents);  
    interactionEvents2.listen(function  (ev)  {  
       interactionEvents.emit(ev);  
    });
    1  
    2  
    3  
    4  
    5  
    6  
    7  
    8
    Proxy stream and real stream

    View full-size slide

  82. var  interactionEvents  =  makeEmptyEventStream();  
    var  screenEvents  =  computer(interactionEvents);

    var  interactionEvents2  =  user(screenEvents);  
    interactionEvents2.listen(function  (ev)  {  
       interactionEvents.emit(ev);  
    });
    1  
    2  
    3  
    4  
    5  
    6  
    7  
    8

    View full-size slide

  83. var  interactionEvents  =  makeEmptyEventStream();  
    var  screenEvents  =  computer(interactionEvents);

    var  interactionEvents2  =  user(screenEvents);  
    interactionEvents2.listen(function  (ev)  {  
       interactionEvents.emit(ev);  
    });
    1  
    2  
    3  
    4  
    5  
    6  
    7  
    8
    Only this matters to you

    View full-size slide

  84. applyToDOM(container,  computerFn)

    registerCustomElement(tagName,  definitionFn)
    Cycle.js API

    View full-size slide

  85. Cycle.applyToDOM('#app',  function  computer(interactions)  {  











    });
    1  
    2  
    3  
    4  
    5  
    6  
    7  
    8  
    9

    10

    11

    12

    13

    View full-size slide

  86. Cycle.applyToDOM('#app',  function  computer(interactions)  {  
     











    });
    1  
    2  
    3  
    4  
    5  
    6  
    7  
    8  
    9

    10

    11

    12

    13
       var  changeName$  =  interactions.get('.field',  'input')  
           .map(ev  =>  ev.target.value);  









    View full-size slide

  87. Cycle.applyToDOM('#app',  function  computer(interactions)  {  
       var  changeName$  =  interactions.get('.field',  'input')  
           .map(ev  =>  ev.target.value);










    });
    1  
    2  
    3  
    4  
    5  
    6  
    7  
    8  
    9

    10

    11

    12

    13
     

       var  name$  =  changeName$.startWith('');









    View full-size slide

  88. Cycle.applyToDOM('#app',  function  computer(interactions)  {  
       var  changeName$  =  interactions.get('.field',  'input')  
           .map(ev  =>  ev.target.value);

       var  name$  =  changeName$.startWith('');









    });
    1  
    2  
    3  
    4  
    5  
    6  
    7  
    8  
    9

    10

    11

    12

    13
     

       

       var  screen$  =  name$.map(name  =>

             
               Name  
                 
               Hello  {name}  
             
       );


    View full-size slide

  89. Cycle.applyToDOM('#app',  function  computer(interactions)  {  
       var  changeName$  =  interactions.get('.field',  'input')  
           .map(ev  =>  ev.target.value);  
       var  name$  =  changeName$.startWith('');  
       var  screen$  =  name$.map(name  =>

             
               Name  
                 
               Hello  {name}  
             
       );

       return  screen$;

    });
    1  
    2  
    3  
    4  
    5  
    6  
    7  
    8  
    9

    10

    11

    12

    13

    View full-size slide

  90. Cycle.applyToDOM('#app',  function  computer(interactions)  {  
       return  interactions.get('.field',  'input')  
           .map(ev  =>  ev.target.value)  
           .startWith('')  
           .map(name  =>

                 
                   Name  
                     
                   Hello  {name}  
                 
           );

    });
    1  
    2  
    3  
    4  
    5  
    6  
    7  
    8  
    9

    10

    11

    12 From keyboard… to screen!

    View full-size slide

  91. Intent
    View
    Model

    View full-size slide

  92. function  intent(interactions)  {  
       return  interactions.get('.field',  'input')

           .map(ev  =>  ev.target.value);  
    }
    1  
    2  
    3  
    4

    View full-size slide

  93. function  model(changeName$)  {  
       return  Rx.Observable.just('').merge(changeName$);  
    }
    1  
    2  
    3

    View full-size slide

  94. function  view(name$)  {  
       return  name$.map(name  =>  (  
             
               Name  
                 
               Hello  {name}  
             
       ));  
    }
    1  
    2  
    3  
    4  
    5  
    6  
    7  
    8  
    9

    View full-size slide

  95. function  computer(interactions)  {  
       return  view(model(intent(interactions)));  
    }
    1

    2

    3

    View full-size slide

  96. Computer
    You choose
    or…

    View full-size slide

  97. function
    function
    or…

    View full-size slide

  98. Intent
    View
    Model

    View full-size slide

  99. model()
    view()
    user()
    intent()

    View full-size slide

  100. model()
    view()
    user()
    intent()
    name$
    screen$ interactions
    changeName$

    View full-size slide

  101. model()
    view()
    user()
    intent()
    name$
    vtree$ interaction$
    changeName$
    Unidirectional data flow

    View full-size slide

  102. [2,  4,  6]
    map(x  =>  10*x)
    [20,  40,  60]

    View full-size slide

  103. [2,  4,  6]
    map(x  =>  10*x)
    [20,  40,  60]
    Functional programming
    Immutability

    View full-size slide

  104. filter(x)=>)x)<)5)
    2
    2 4
    4 6

    View full-size slide

  105. filter(x)=>)x)<)5)
    2
    2 4
    4 6
    Reactive programming

    View full-size slide

  106. function  view(name$)  {  
       return  name$.map(name  =>  (  
             
               Name  
                 
               Hello  {name}  
             
       ));  
    }
    1  
    2  
    3  
    4  
    5  
    6  
    7  
    8  
    9

    View full-size slide

  107. 1  
    2  
    3  
    4  
    5  
    6  
    7  
    8  
    9
    function  view(name$)  {  
       return  name$.map(name  =>  (  
             
               Name  
                 
               Hello  {name}  
             
       ));  
    }
    Virtual DOM

    View full-size slide

  108. Unidirectional dataflow
    Functional reactive programming
    Immutable data structures
    Virtual DOM
    One-way data binding Dispatcher
    Flux
    Cursors
    Shadow DOM
    Components
    State and props
    Purity
    Not that scary…
    Declarative
    Isomorphic

    View full-size slide

  109. Insight #1: UIs are cycles
    Insight #2: UIs are functions

    Insight #3: UIs are async
    Insight #4: UIs are symmetric
    Insight #5: The User is a function

    View full-size slide

  110. Human
    Computer

    View full-size slide

  111. Expression Senses
    Expression
    Senses

    View full-size slide

  112. Expression Senses
    Expression
    Senses

    View full-size slide

  113. Alice
    What’s up?
    Fine! And you?

    View full-size slide

  114. What’s up? Good!
    Fine! And you?
    Fine! And you?
    Bob
    Alice

    View full-size slide

  115. merge
    What’s up? Good!
    Fine! And you?
    Fine! And you?
    What’s up? Good!

    View full-size slide

  116. merge
    What’s up? good!
    Fine! And you?
    Fine! And you?
    What’s up? good!
    Conversation

    View full-size slide

  117. Thank you
    @andrestaltz

    View full-size slide