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

Empirical Observations on the The Future of Sca...

Empirical Observations on the The Future of Scalable UI Architecture

Over the past twenty years, I have observed a handful of shifts in the UI paradigms driven by various architectural patterns and advancements. This session delves into these observations to offer a comprehensive overview of the trends and innovations that can be derived from the past. The session will highlight popular UI architecture patterns and the common problems that the community finds in these approaches and provide a concise course of action regarding the patterns we can introduce into our UI systems today and use these observations to exercise what UI architectures we can build today to scale the UI systems and guard ourselves against future system rewrites.

Willian Martins

June 23, 2024
Tweet

More Decks by Willian Martins

Other Decks in Technology

Transcript

  1. Hi!

  2. in 2005 • Browse api were not standard • Data

    flow everywhere • No stablished pattern in the ecosystem. The web app issue
  3. / / get elements by class $$('.foo'); / / or

    even: document.getElements('.foo'); / / selector with different elements $$('div.foo, div.bar, div.bar a'); / / get a single element document.getElement('div.foo'); / / attach a click event o a element myElement.addEvent('click', function(){ alert('clicked!'); });
  4. / / get elements by class $('.foo'); / / selector

    with different elements $('div.foo, div.bar, div.bar a'); / / get a single element $('div.foo'); / / attach a click event o a element $('div.foo').click(function(){ alert('clicked!'); });
  5. • Heavily relying on server side rendering • Js loaded

    per page • Browser api mismatch • 1st era of libs/framework • Lack of code organization MPA era
  6. • Custom Route handling with #!/ • Event delegation •

    Mediator Pattern • Require.js • NodeJs • MVC UI Framework Rich web app
  7. Mediator pattern const mediator = { events: {}, subscribe(event, callback)

    { if (!this.events[event]) { this.events[event] = []; } this.events[event].push(callback); }, publish(event, data) { if (this.events[event]) { this.events[event].forEach(callback = > callback(data)); } } };
  8. Mediator pattern mediator.subscribe("inputChanged", filterItems); function filterItems(query) { const items =

    document.querySelectorAll(“.item"); items.forEach((item) = > { if (item.textContent.toLowerCase().includes(query.toLowerCase())) { item.classList.add("visible"); } else { item.classList.remove("visible"); } }); }
  9. Require.js define([], function() { const mediator = { events: {},

    subscribe(event, callback) { if (!this.events[event]) { this.events[event] = []; } this.events[event].push(callback); }, publish(event, data) { if (this.events[event]) { this.events[event].forEach(callback = > callback(data)); } } }; return mediator; });
  10. Require.js define(['mediator'], function(mediator) { function handleInput(event) { mediator.publish('inputChanged', event.target.value); }

    function init() { const input = document.getElementById('filterInput'); input.addEventListener('input', handleInput); } return { init: init }; });
  11. Require.js define([], function() { function filterItems(query) { const items =

    document.querySelectorAll('.item'); items.forEach(item = > { if (item.textContent.toLowerCase().includes(query.toLowerCase())) { item.classList.add('visible'); } else { item.classList.remove('visible'); } }); } return filterItems; });
  12. • Better code organization • Less prone for memory leaks

    • Data flow improved • Lack of opinionated framework • Hard to transfer knowledge Rich web app
  13. Backbone.js example import { Model, Collection } from 'backbone'; const

    Item = Model.extend({ defaults: { name: '', visible: true } }); const ItemList = Collection.extend({ model: Item }); export { Item, ItemList };
  14. Backbone.js example import { View, Events } from 'backbone'; const

    InputView = View.extend({ el: '#filterInput', events: { 'input': 'handleInput' }, handleInput: function(event) { Events.trigger('inputChanged', event.target.value); } }); export default InputView;
  15. Backbone.js example const ItemView = View.extend({ tagName: 'li', className: 'item',

    initialize: function() { this.listenTo(this.model, 'change:visible', this.toggleVisible); }, render: function() { this.$el.text(this.model.get('name')); this.toggleVisible(); return this; }, toggleVisible: function() { this.$el.toggleClass('visible', this.model.get('visible')); } });
  16. Backbone.js example const FilterView = View.extend({ el: '#itemList', initialize: function()

    { this.listenTo(Events, 'inputChanged', this.filterItems); this.collection = new ItemList([ { name: 'item 1' }, { name: 'item 2' }, ]); this.render(); }, render: function() { this.$el.empty(); this.collection.each(item = > { const itemView = new ItemView({ model: item }); this.$el.append(itemView.render().el); }); }, filterItems: function(query) { this.collection.each(item = > { const isVisible = item.get(‘name’).toLowerCase() .includes(query.toLowerCase()); item.set('visible', isVisible); }); this.render(); } });
  17. The good parts • JSX • Pure function as UI

    representation • Rich ecosystem (redux, router, sagas, mobx, react query) • Improvements over time (hooks, context API, SSR, compiler) React.js
  18. The challenging parts • Trend driven development • Changes hard

    to follow on a mature system • Reactive is the new foundation • How to evolve the system without be lost on trends? React.js
  19. Scalability definition The ability of a computing process to be

    used or produced in a range of capabilities.
  20. Actionable items • Start small • Go from Botton-up approach

    • Hire a good CSS engineer • Make rule agreement with the design team • Avoid Solution w/ runtime penalty • Create code generation plugins Design system
  21. In practice • Foundation as a generic layer • Core

    as application specific layer • Features as detachable building block Feature Based Architecture
  22. Guidelines • Heuristics towards ease for deletion • No logic

    other than presentation logic • Aim for co-location • Feature registration should be simple Detachable Feature