EmberConf 2016 – Idiomatic Ember: Finding the Sweet Spot of Performance & Productivity

EmberConf 2016 – Idiomatic Ember: Finding the Sweet Spot of Performance & Productivity

This talk was presented at EmberConf 2016. Watch it here! https://www.youtube.com/watch?v=lP9ap-AKBAM

With the release of Ember 2.0, many best practices established in the 1.x series are unfortunately no longer relevant. Lessons learnt from the React and Flux communities can help guide the path toward The Ember Way, with "Data Down, Actions Up" being one of the core philosophies.

In this beginner-friendly talk, we'll discuss patterns and anti-patterns for bringing Ember applications into the 2.x paradigm, and discover how ideas from Functional Programming and game rendering engines can inform us. We will also look at the roads ahead to see what future versions of Ember will bring.

C8fccffc013096c4b465b50c284a5208?s=128

Lauren Tan

March 30, 2016
Tweet

Transcript

  1. 1.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 IDIOMATIC EMBER Finding the Sweet Spot of Performance & Productivity h D O C K YA R D h
  2. 2.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 bit.ly/idiomatic-ember
  3. 5.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 LAUREN TAN SUGARPIRATE_ POTETO
  4. 8.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 I WORK AT DOCKYARD
  5. 11.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 THE STATE OF JAVASCRIPT IN 2016
  6. 17.
  7. 18.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 “I hand-rolled my own front-end stack using the most organic, gluten-free and artisanal micro- libraries.”
  8. 20.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 Performance Productivity
  9. 21.
  10. 22.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 THE EMBER WAY?
  11. 23.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 Data Component Owner Action
  12. 25.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 this.attrs.fooAction(val); this.get('fooAction')(val); VS
  13. 28.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 MORE JAVASCRIPT
  14. 29.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 DECORATORS Stage 1 https://github.com/wycats/javascript-decorators
  15. 30.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 https://github.com/rwjblue/ember-computed-decorators @computed('first', 'last') name(first, last) { return `${first} ${last}`; }
  16. 31.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 ASYNC/AWAIT Stage 3 https://github.com/tc39/ecmascript-asyncawait
  17. 32.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 await fillIn('.display-title', 'Hello!'); await click('.update-display-title'); assert.equal(find('.display-title').text(), 'Hello!'); https://github.com/emberjs/rfcs/pull/119
  18. 33.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 GENERATORS ES2015 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*
  19. 34.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 countingTask: task(function* () { this.set('count', 0); while (this.get('count') < 5) { this.incrementProperty('count'); yield timeout(300); } this.set('count', 'DONE!'); }).restartable() https://github.com/machty/ember-concurrency
  20. 36.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 – Yehuda Katz “All good ideas will eventually end up in Ember.”
  21. 37.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 THE EMBER WAY
  22. 38.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 I. Data Down, Actions Up? II. Controllers are Dead III.Declarative & Composable Templates
  23. 39.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 I. Data Down, Actions Up? II. Controllers are Dead III.Declarative & Composable Templates
  24. 42.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 Is MVC Dead? ☠
  25. 43.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 Is MVC Dead? ☠ NOPE
  26. 44.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 2 WAY BINDINGS
  27. 47.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 Who owns the data?
  28. 48.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 Component A Component A.1 Component A.2 Component A.3 Route Owns the shared state of A1 - A3
  29. 49.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 Component A Component A.1 Component A.2 Component A.3 Route Owns the shared state of A1 - A3 {{component configComponent user=user changeStep=(action "changeStep")}}
  30. 50.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 {{component configComponent user=user currentStep=currentStep}} // don't do this in the child component! export default Component.extend({ actions: { next() { set(this, 'currentStep', 'configure-foo'); } } }); This is bad ☹
  31. 51.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 …or someone else's state!
  32. 52.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 <configure-username user={{user}} currentStep={{currentStep}}> ... </configure-username>
  33. 53.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 export default Service.extend({ init() { this._super(...arguments); this.data = []; } });
  34. 54.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 I. Data Down, Actions Up? II. Controllers are Dead III.Declarative & Composable Templates
  35. 56.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 ROUTABLE CONTROLLER
  36. 57.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 export default Controller.extend({ queryParams: ['category'], category: null });
  37. 58.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 ROUTABLE CONTROLLER
  38. 59.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 ROUTABLE COMPONENT
  39. 60.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 Component = Controller + View
  40. 61.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 <h1>Alpaca Route Template</h1> <div class="my-amazing-template"> {{#each alpacas as |alpaca|}} <span> I'm a cute little {{alpaca}}! </span> {{/each}} </div> {{foo-alpaca alpacas=alpacas}} move to
  41. 62.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 // shopping-cart top-level component export default Component.extend({ shoppingCart: inject.service(), actions: { remove(product) { // ... } } }); {{#each shoppingCart.products as |product|}} <h2>{{product.title}}</h2> <p>{{product.description}}</p> <button {{action "remove" product}}>Remove</button> {{/each}}
  42. 63.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 Controller Action Action Action Route Action Action Action move to
  43. 64.
  44. 65.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 {{foo-bar submit="submit"}} {{foo-bar click=(action "submit")}}
  45. 66.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 New-style Actions aka Closure Actions
  46. 67.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 {{foo-bar click=(action "submit")}}
  47. 68.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 Classic Actions aka String Actions
  48. 69.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 {{foo-bar submit="submit"}}
  49. 70.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 this.sendAction('someMysteriousAction', args);
  50. 71.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 Your classic action
  51. 72.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 get(this, 'submit')(...args);
  52. 74.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 actions: { saveAndDoStuff(item) { get(this, 'save')(item) .then((savedItem) => // do stuff); } }
  53. 75.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 ember install ember-route-action-helper https://github.com/DockYard/ember-route-action-helper
  54. 76.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 {{foo-bar value=value updateFoo=(route-action "updateFoo") }}
  55. 77.
  56. 79.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 export default Service.extend({ init() { this._super(...arguments); this.cart = []; }, addToCart(item) { // ... }, removeFromCart(item) { // ... } });
  57. 81.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 I. Data Down, Actions Up? II. Controllers are Dead III.Declarative & Composable Templates
  58. 82.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 {{if (eq fullName "Jim Bob") "You're the chosen one"}} https://github.com/jmurphyau/ember-truth-helpers
  59. 83.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 {{concat "configure-" configName}} http://emberjs.com/api/classes/Ember.Templates.helpers.html
  60. 84.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 import Ember from 'ember'; export function add([a, b]) { return a + b; } export default Ember.Helper.helper(add);
  61. 85.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 export default Helper.extend({ // ... });
  62. 86.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 export default Helper.extend({ localesService: inject.service('locales'), currentLocale: readOnly('localesService.currentLocale'), compute([key]) { let currentLocale = get(this, 'currentLocale'); return get(this, 'localesService').lookup(currentLocale, key); }, localeDidChange: observer('currentLocale', function() { this.recompute(); }) });
  63. 88.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 export default Component.extend({ isDropdownDisplayed: false, actions: { saveUserAndHideDropdown(user) { get(this, 'save')(user) .then((user) => { // do stuff set(this, 'isDropdownDisplayed', false); }); } } });
  64. 89.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 export default Component.extend({ isDropdownDisplayed: false, actions: { hideDropdown() { set(this, 'isDropdownDisplayed', false); }, saveUser(user) { return get(this, 'save')(user); } } });
  65. 90.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 <button {{action (pipe saveUser hideDropdown) user}}> Save and Close </button>
  66. 91.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 A(B(C(D('E'), 'F'), 'G'), 'H');
  67. 92.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 filing = DB.find_customers |> Orders.for_customers |> sales_tax(2016) |> prepare_filing E |> D |> C("F") |> B("G") |> A("H") http://elixir-lang.org/
  68. 93.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 <button {{action (pipe addToCart purchase redirectToThankYouPage) item}}> 1-Click Buy </button>
  69. 94.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 ember install ember-composable-helpers https://github.com/DockYard/ember-composable-helpers
  70. 95.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 <button {{action (pipe save closeDropdown) item}}>Save and Close</button> <button {{action (pipe save quitApp) item}}>Save and Quit</button>
  71. 96.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 {{#if (eq (not (incr (count user))) (decr (count user))))}}
  72. 100.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 COMPUTED VS HELPER VS COMPONENT HOOKS
  73. 101.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 COMPUTEDS
  74. 103.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 export default Component.extend({ @computed('payment', 'rate', 'periods') annuity(payment, rate, periods) { let factor = ((1 - Math.pow(1 + rate, -periods)) / rate); return payment * factor; } });
  75. 104.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 export function customMacro(dependentKey, ...keys) { return computed(dependentKey, ...keys, { get() { // computed property logic } }); }
  76. 105.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 export default Component.extend({ myValue: customMacro('myKey', 'foo', 'bar'), someValue: customMacro('someKey', 'baz', 'qux'), otherValue: customMacro('otherKey', 'meow', 'woof') });
  77. 107.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 Business logic Reusable ⚛⚛⚛⚛ React to changes Changes can be implicit Totally arbitrary emojis
  78. 108.
  79. 109.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 {{#each (repeat 3) as |nil index|}} <div data-thing={{concat "foo-" index}}> {{!some HTML block}} </div> {{/each}} https://github.com/DockYard/ember-composable-helpers#repeat
  80. 110.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 {{capitalize "hello"}} {{capitalize "hello"}}
  81. 111.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 export function toggle([obj, prop]) { return function() { set(obj, prop, !get(obj, prop)); }; } https://github.com/DockYard/ember-composable-helpers#toggle
  82. 112.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 <button {{action (toggle this "isExpanded")}}> {{if isExpanded "I am expanded" "I am not"}} </button>
  83. 113.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 Express UI logic ✍❤ Composable Simple mental model Can be used as action No hooks available (yet) Totally arbitrary emojis
  84. 114.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 COMPONENT HOOKS
  85. 115.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 export default Component.extend({ didReceiveAttrs() { this.updateChart(get(this, 'data')); }, updateChart(data) { // update the chart's data } });
  86. 116.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 Initial Render init didReceiveAttrs willRender didInsertElement didRender External attr changed didUpdateAttrs didReceiveAttrs willUpdate willRender didUpdate didRender Internal value changed willUpdate willRender didUpdate didRender
  87. 117.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 export default Component.extend({ didRender() { // this is an infinite loop that will crash your browser let isFoo = get(this, 'isFoo'); set(this, 'isFoo', !isFoo); } });
  88. 118.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 Dealing with side effects ➿ Can cause infinite loops "Just re-render it" Not invoked in FastBoot environment Totally arbitrary ratings
  89. 119.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 SHOULD I USE AN OBSERVER?
  90. 121.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 https://youtu.be/vvZEddrClAQ
  91. 122.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 THE FUTURE
  92. 124.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 Game world state Front End IR Back End DirectX / OpenGL OS Screen
  93. 125.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 Application state Front End HTMLBars Glimmer DOM APIs Browser Screen
  94. 127.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 Hidden blocks rendered, CPU time wasted Line of Sight Camera Without occlusion culling
  95. 128.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 Hidden blocks not rendered, CPU time saved Line of Sight Camera With occlusion culling
  96. 130.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 https://air.mozilla.org/bay-area-rust-meetup-february-2016/#@1m53s
  97. 131.
  98. 133.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 I. Data Down, Actions Up? II. Controllers are Dead III.Declarative & Composable Templates
  99. 134.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 I. Data Down, Actions Up? II. Controllers are Dead III.Declarative & Composable Templates
  100. 135.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 I. Data Down, Actions Up? II. Controllers are Dead III.Declarative & Composable Templates
  101. 138.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 LAUREN TAN SUGARPIRATE_ POTETO
  102. 139.

    IDIOMATIC EMBER – FINDING THE SWEET SPOT OF PERFORMANCE &

    PRODUCTIVITY EMBERCONF 2016 Thanks! LAUREN TAN SUGARPIRATE_ POTETO