Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Effects, Coeffects & Subscriptions: a pit of success for SPAs


Published on

Effects, Coeffects & Subscriptions: a pit of success for SPAs using re-frame

Published in: Software
  • Be the first to comment

  • Be the first to like this

Effects, Coeffects & Subscriptions: a pit of success for SPAs

  1. 1. Effects, coeffects & subscriptions: a pit of success for SPAs Manuel Rivero @trikitrok
  2. 2. About me ● I’m Manuel Rivero (@trikitrok). ● I’m a member of Codesai. ● I collaborate with BCN Software Craftsmanship, Clojure Developers BCN and Aprendices (@deAprendices) communities. ● My current client is Green Power Monitor where we develop a SPA for monitoring and managing renewable energy portfolios using ClojureScript and Om.
  3. 3. Thanks to: ● All the members of Clojure Developers BCN for all the fun and evenings of sharing and learning. ● All the people in Codesai & Green Power Monitor that gave me feedback to improve this talk. ● Francesc Guillén for introducing me to ClojureScript, teaching me so much, and letting me participate in his re-frame + React Native adventure.
  4. 4. Context ● Rewrite in ClojureScript a browser SPA written in JavaScript that implements a visual method to practice spelling. ● Create a mobile version, adding some improvements and making it offline first. ● We wanted to share as much code as possible between browser and mobile versions.
  5. 5. Stack ● ClojureScript. ● re-frame, a framework for writing SPAs in Clojurescript. ● Reagent a minimalistic interface between ClojureScript and React. ● expo to build React Native apps that work across both iOS and Android.
  6. 6. Some things we have learned
  7. 7. 1. Effects & Coeffects
  8. 8. re-frame architecture (simplified version)
  9. 9. Unidirectional Data Flow Architecture from re-frame wonderful docs
  10. 10. Imagine a re-frame app as a reduce
  11. 11. State Management ● At any point in time, app state results from reducing over all events dispatched in the app up until that time. ● The combining function for the reduce is the set of registered event handlers.
  12. 12. Great if event handlers are pure functions
  13. 13. Pure Event Handlers ● Local reasoning ● Easier testing ● Events replay-ability
  14. 14. Side-effects are inevitable*
  15. 15. Side-causes Data a function requires but it does not receive in its argument list
  16. 16. Side-effects What a function does to the world
  17. 17. What’s the problem with effectful event handlers?
  18. 18. Effectful Event Handlers ● Action at a distance. ● Difficult to test. ● Events replay-ability is lost.
  19. 19. How do we usually try to fix this? ● Separation of concerns ● Test doubles We regain isolation but, events replay-ability is still lost...
  20. 20. Accidental Complexity!!!
  21. 21. DI in an event handler with a side effect extended version
  22. 22. Testing event handler with a side effect
  23. 23. Testing event handler with a side effect
  24. 24. Testing event handler with a side effect
  25. 25. DI in an event handler with a side cause extended version
  26. 26. Testing event handler with a side cause
  27. 27. Testing event handler with a side cause
  28. 28. Testing event handler with a side cause
  29. 29. Accidental Complexity!!!
  30. 30. Is there an easier way?
  31. 31. Effects and Coeffects ● Effects: describe your program’s side-effects (what it does to the world) ● Coeffects: track your program’s side-causes (what it requires from the world)
  32. 32. Declarative Effects pattern ● Event handlers are pure functions again ● They receive coeffects and return effects ● Injecting the values coeffects track and interpreting effects to actually perform side-effects are done by sth else (the language run-time, a framework, etc)
  33. 33. Declarative Effects pattern Effects as Data, Richard Feldman
  34. 34. What do we get?
  35. 35. Pure event handlers again! extended version
  36. 36. No test doubles!
  37. 37. Pure event handlers again! extended version
  38. 38. Pure event handlers again!* extended version * using destructuring
  39. 39. No test doubles!
  40. 40. Pure Event Handlers ● Local reasoning ● Easier testing ● Events replay-ability
  41. 41. Pure functional Core
  42. 42. How are effects & coeffects handled?
  43. 43. Effect & Coeffects handlers
  44. 44. Effect & Coeffects handlers in re-frame ● Built-in effects handlers (:db, :dispatch, :dispatch-later, etc) ● Built-in coeffects handlers (:db) ● You can create your own custom effects and coeffects handlers and register them into re-frame.
  45. 45. :timestamp is a custom coeffect extended version
  46. 46. Pure Functional Core, Imperative Shell
  47. 47. re-frame architecture
  48. 48. Advantages over ports & adapters ● Less accidental complexity in business logic ● Remove business logic fragility to interface changes in ports ● Still keeps pluggability (you can still use ports & adapters in the imperative shell)
  49. 49. 2. Subscriptions & Reactivity
  50. 50. re-frame architecture (simplified version)
  51. 51. re-frame subscriptions ● A novel and efficient de-duplicated signal graph which runs query functions on the app state ● These query functions extract data from the app state and provide it to view functions in the right format
  52. 52. re-frame subs
  53. 53. re-frame subs: Reactivity
  54. 54. Improve Performance ● By reducing renderings ● By de-duplicating computations
  55. 55. re-frame subs: Reactive signal graph from re-frame wonderful docs
  56. 56. re-frame subs: Reactive signal graph
  57. 57. Simpler model & Dumb Views ● Avoid having to keep derived state in the model (app state). ● Dumb down the views, that end up being simple “data in, screen out” functions
  58. 58. 3. UI modeled as FSMs
  59. 59. Unidirectional Data Flow Architecture from re-frame wonderful docs
  60. 60. re-frame architecture
  61. 61. Event Driven Data Flow
  62. 62. UI modeled as Finite State Machines from a great Jeb Beich’s post in Cognitect’s blog
  63. 63. 4. Design Constraints and Pits of success
  64. 64. Working against the architecture/design
  65. 65. Things could be much easier
  66. 66. A Pit of Success “A well-designed system makes it easy to do the right things and annoying (but not impossible) to do the wrong things.” Jeff Atwood
  67. 67. A Pit of Success Functional architecture: The pits of success, Mark Seemann
  68. 68. Only pure functions for business logic
  69. 69. Isolated effectful code
  70. 70. UI modeled as FSMs from a great Jeb Beich’s post in Cognitect’s blog
  71. 71. Subscriptions ● Reduce accidental complexity by avoiding derived state ● Dumb views down ● Allow separated optimization of query code using a reactive de-duplicated signal graph
  72. 72. We were in a pit of success!
  73. 73. For redux users Declarative effects: ● redux-saga or redux-loop Subscriptions: ● reselect
  74. 74. 5. Huge reuse
  75. 75. Views (browser)
  76. 76. Views (mobile)
  77. 77. Some effect handlers
  78. 78. 6. What did ClojureScript give us?
  79. 79. Elegant Weapons from amazing xkcd comic
  80. 80. Sound functional language ● Immutable data structures ● Powerful standard library ● Reference types ● Lightweight but powerful polymorphism
  81. 81. Interactive Development ● Great development experience ○ REPL & Figwheel ● Different flow: RDD + TDD ○ Faster feedback cycles
  82. 82. Avoid JS tooling fatigue ES5, ES6, ES7, JSX, Babel, TypeScript, Webpack, …
  83. 83. 7. No silver bullet
  84. 84. Hard things are still hard re-frame puts you in a great starting point However, you still have to work hard to get good naming, model your domain, discover useful abstractions and organize your code
  85. 85. Beware of “shape” coupling ● Avoid that your code knows too much about the app-state representation. ● Especially important for tests. Use builders.
  86. 86. Beware of long event cascades ● Some business logic might be difficult to follow. ● Common problem in all event-based systems: ● Paliate with tooling (re-frisk) and packaging by feature.
  87. 87. Living on the bleeding edge ● expo: early days & quickly evolving => ClojureScript bindings continually catching up. ● Still worth it though: avoids maintaining different views for iOS and Android. ● It’ll get better as it stabilizes.
  88. 88. 8. Conclusions
  89. 89. ● Browser and mobile versions share most of its code ● Effects, coeffects & subscriptions ○ Removes a lot of accidental complexity ○ A “pit of success” ● ClojureScript: ○ sound language ○ great interactive development flow
  90. 90. Thanks!! Manuel Rivero @trikitrok
  91. 91. References & Links ● Effects & Coeffects ○ Coeffects: The next big programming challenge, Tomas Petricek ○ Side-effect, Wikipedia ○ What is functional programming?, Kris Jenkins ○ Avoiding Action at a Distance Is the Fast Track to Functional Programming, Ashley Nelson-Hornstein ○ Effects as Data, Richard Felman ○ Unidirectional data flow architectures, Andre Staltz ○ Using coeffects in re-frame, Manuel Rivero ○ Using effects in re-frame, Manuel Rivero ○ Creating custom effects in re-frame, Manuel Rivero ○ An Introduction to Elm ○ Boundaries, Gary Bernhardt
  92. 92. References & Links ● UIs modeled as FSMs ○ Using State Machines to Simplify User Interface Development, Jeb Beich ○ Creating a User Interface with Re-frame and State Machines, Jeb Beich ● Pits of success ○ Functional architecture: The pits of success, Mark Seemann ○ Falling Into The Pit of Success, Jeff Atwood ○ A Good Language Conserves Programmer Energy, Eugene Wallingford ○ The deep synergy between testability and good design, Michael Feathers ● Simplifying React ○ 6 things Reacters do that Re-framers avoid, Eric Normand ○ A guide to the React Lifecycle Methods for Re-frame, Eric Normand ○ JSX vs Clojurescript: the showdown, Inge Solvoll ○ Comparing Reagent to React.js and Vue.js for dynamic tabular data, Dmitri Sotnikov
  93. 93. References & Links ● Interactivity ○ Developing ClojureScript With Figwheel, Bruce Hauman ○ Repl Driven Development, Stuart Sierra ● Other interesting links ○ Interview with Yassine Elouafi, creator of redux-saga ○ Elm architecture with React + Redux + Redux-loop, Egor Sapronov ○ Rethinking All Practices: Building Applications in Elm, Jamison Dance ○ Reduce side effects in React/Redux, Michal Zalecki ○ Managing side effects in Redux, Rico Sta. Cruz ○ Offline first ○ re-frame ○ Reagent
  94. 94. References & Links ○ React Native ○ re-natal ○ expo ○ Redux ○ reselect ○ redux-saga ○ redux-loop ○ Clojure Developers BCN Meetup ○ Aprendices Community on G+ ○ Clojure Barcelona Community on G+ Note for myself: inevitable actually exists and means unavoidable... (see the video of the talk when it comes out )
  95. 95. re-frame: how it works discarded slide copied from wonderful re-frame docs