How Reactive Programming can help reduce code spaghetti

How Reactive Programming can help reduce code spaghetti

Presented at http://mloc-js.com/2015/. When applications become large enough, complexity arises. Some of it is accidental complexity, which programmers often identify and know how to fix. On the other hand, essential complexity is unavoidable and hard to handle. Reactive Programming has been praised lately for its power in event-driven problems, but it has more aspects which make it useful in your codebase. We will see how the reactive pattern can help organize essential complexity and produce separation of concerns.

C8dbe3c6d219999ee0ecce86a450d0e3?s=128

André Staltz

June 18, 2015
Tweet

Transcript

  1. How Reactive Programming can help reduce code spaghetti

  2. @andrestaltz

  3. ReactiveX Cycle.js

  4. Large codebases

  5. InputStream fileInputStream = new FileInputStream(FILE_PATH); BufferedReader bufferedReader = new BufferedReader(

    new InputStreamReader(fileInputStream) ); String line=""; while((line = bufferedReader.readLine()) != null){ System.out.println(line); } Accidental complexity
  6. with open(FILE_PATH, "r") as file: for line in file: print(line)

    Accidental complexity
  7. None
  8. None
  9. Wrong abstraction or tool Over-engineering

  10. Essential complexity

  11. Find 
 creative solutions to make 
 essential complexity
 quickly

    understandable.
  12. Find 
 creative solutions to make 
 essential complexity
 quickly

    understandable.
  13. Understandable Traceable Predictable Familiar

  14. None
  15. None
  16. None
  17. None
  18. Modules

  19. None
  20. When yawns… …increments a counter.

  21. function yawn() { Bar.incrementCounter(); }

  22. function yawn() { Bar.incrementCounter(); } Proactive
 Responsible for the change

    Passive
 Unaware of the dependency
  23. None
  24. Foo.onYawn(function () { self.incrementCounter(); });

  25. Foo.onYawn(function () { self.incrementCounter(); }); Listenable
 Unaware of the dependency

    Reactive
 Responsible 
 for the change
  26. Foo.onYawn(function () { self.incrementCounter(); }); yawn event 
 is public

    incrementCounter is private
  27. function yawn() { Bar.incrementCounter(); } yawn is 
 private incrementCounter

    is public
  28. Passive Programming

  29. Reactive Programming

  30. “Reactive”?

  31. Reactive Manifesto?

  32. None
  33. None
  34. What does 
 Reactive mean? I don’t know!

  35. None
  36. Reactive Programming Andre’s definition

  37. addEventListener(callback)

  38. Event Streams

  39. RxJS Observables

  40. Bacon.js

  41. Kefir

  42. Channels

  43. Actors

  44. Spreadsheets!

  45. None
  46. None
  47. Passive
 is
 BAD

  48. IRRESPONSIBLE
 MODULES

  49. // speaker.js showSlide1(); showSlide2(); showSlide3(); // ... showLastSlide(); for (var

    i = 0; i < audience.length; i++) { audience[i].goGetCoffee(); }
  50. // participant1.js import {speaker} from 'speaker.js';
 speaker.addEventListener('speechEnd', function() { self.goGetCoffee();

    }); // participant2.js speaker.addEventListener('speechEnd', function() { self.tweet('Pretty decent presentation'); });
  51. None
  52. None
  53. Which modules does B affect? Look inside B

  54. How does B work? Find usages of B's methods

  55. “Find usages”

  56. None
  57. How does B work? Look inside B

  58. Which modules does B affect? Find usages of B’s events

  59. Passive Reactive How does it work? Find usages Look inside

    What does it affect? Look inside Find usages
  60. Passive Reactive How does it work? Find usages Look inside

    What does it affect? Look inside Find usages
  61. When is Passive good? Owned subcomponents Data structures Imperative bootstrapping

  62. Dependencies

  63. // participant1.js import {speaker} from 'speaker.js';
 speaker.addEventListener('speechEnd', function() { self.goGetCoffee();

    });
  64. All singletons!

  65. Dependencies What? versus How?

  66. // participant1.js import {speaker} from 'speaker.js';
 speaker.addEventListener('speechEnd', function() { self.goGetCoffee();

    }); What
  67. // participant1.js import {speaker} from 'speaker.js';
 speaker.addEventListener('speechEnd', function() { self.goGetCoffee();

    }); How
  68. // participant1.js import {speaker} from 'speaker.js';
 speaker.addEventListener('speechEnd', function() { self.goGetCoffee();

    }); Bad
  69. // participant1.js
 export default function inject(speaker) { speaker.addEventListener('speechEnd', () =>

    { self.goGetCoffee(); }); }
  70. Passive
 Unaware of the dependency

  71. How does it work? Reactive: look inside What does it

    depend on? Passive: unaware of the dependency Passively Reactive: 
 the best of two worlds
  72. Depends on 2 ? ? ?

  73. B: depend on A and C

  74. Sets own behavior
 depending on A and C

  75. None
  76. Example How do you set up analytics events?

  77. // login-page.js import * as Analytics from 'analytics';
 var loginButton

    = document.querySelector(‘.login'); loginButton.addEventListener('click', () => { Analytics.sendEvent('User clicked login button'); });
  78. None
  79. None
  80. // analytics.js function sendEvent(eventMessage) { // ... } export default

    function inject(loginPage) { loginPage.loginButtonClicks.listen(() => { sendEvent('User clicked login button'); }); }
  81. Mind the arrows!

  82. Reactive everywhere? RxJS Workshop at MLOC.JS!