46 ms·
The Elements of UI Engineering
- miguelrochefort 8y agoI've been building consumer apps professionally since 2013 on iOS, Android, Windows Phone and the web. I also spent a few years designing and implementing UI frameworks. I've had to deal with all of the problems listed in Dan's article (with and without frameworks). Over the years, I have grown convinced that designing and implementing UI by hand simply doesn't scale. There are too many things to consider, too many different users, too many preferences, too many possible states. Responsive design isn't just about screen sizes anymore, it's also about the user's language, culture, disabilities, input, context, preferences, connectivity, knowledge, focus, etc. We can't expect every restaurant, bank, festival and airlines to implement their own apps, and consider all of the above. You won't find a dark theme in the Domino's app. Why do we tolerate these compromises in the name of branding? Why should UIs be tightly coupled with the services and data? Why don't we have general purpose clients? I think the job of service providers should be to semantically annotate their data, so that a general purpose client can dynamically render it. All of these UI concerns would only have to be dealt with once, and we all would be able to sleep at night. Just let business people do business, and let UI/UX people do design.
- thenanyu 8y agoVanity is the reason, in my experience. For all the downsides of amp, it’s demonstrated that letting go of asthetic vanity in the name of fundamental soundness is a good trade to make.
- goliatone 8y agoWhat you want is gopher[1]. Instead of AMP I think sites could honor requests with an text/plain header, the issue is monetization. But AMP is for content based sites, SPA capture a completely different use cases. [1] https://en.m.wikipedia.org/wiki/Gopher_(protocol) https://en.m.wikipedia.org/wiki/Gopher_(protocol)
- hadsed 8y agoI've always thought AI would be a good solution for this. The ideal way to create a website is to just express what you see in your mind through drawings, essentially, with a simple way to represent transitions. Doing this in real time with a compiler like in Dreamweaver is awkward because there are too many nonsensical constraints (and other problems that real UI engineers can tell you, I'm just an AI guy). So to bridge the gap you really need a function that can translate your expression into reality by understanding what parts are important for your design to work and what isn't, and making it work on any platform/client/medium. The type of function that can approximate a potentially extremely complex reality, that can be trained incrementally given examples (bugs)... Sounds a lot like modern machine learning to me.
- aasasd 8y agoA related issue is that the means of making web UIs are too low-level. There's no standard ready-made widget kit like on desktops. HTML and CSS started as a solution for publishing text-based content, like the olde magazines but on the web. For that they are splendid: text rendering and basic input handling are taken care of, and wide variety of output devices were supported since day one (HTML 2.0 without tables works excellent on phones). Then web 2.0 and web apps happened, web idioms began to change, all of people's activity with computers started moving to the web. And it turned out that to create complex UIs for all of that you have to fiddle with rather low-level primitives and handle interactions between them, because outside of text layout HTML primarily knows about divs and a handful of input widgets. This may be good because high-level widgets will be developed independently and will evolve faster (and maybe better) than if they were built into browsers. But in the meantime we have to live with the chaos that we have.
- simion314 8y ago>This may be good because high-level widgets will be developed independently and will evolve faster (and maybe better) than if they were built into browsers. But in the meantime we have to live with the chaos that we have. I don't think that having some good built-in widgets (like a better dropdown, menus, DataGrid) would prevent third parties creating their own custom versions but it would help 99% of users that need the basic stuff (like a dropdown that can have icons)
- aasasd 8y ago(I need to add, though, that even if a compete and perfect-in-every-respect third-party widget kit for the web appears today, it will face a huge problem of adoption, or rather lack of it. In this regard, fragmentation on the web is unbelievable by desktop standards―also a consequence of the "web is for publishing" approach.)
- lucbocahut 8y agoOne UI to rule them all? This would be a really interesting tool for web developers. Thankfully, modern UI development is blessed with some really professional UI toolkits: elements UI for vue or Semantic React for instance do a great job of making us think in terms of generic interactions instead of reinventing the wheel. This means we get to focus on improving the existing as the project warrants which is significantly more rewarding.
- simion314 8y agoI would prefer powerful UI widgets built in and if your preferred framework wants it can wrap this widgets or if not it can just use nested divs and css to create an alternative.
- kakarot 8y ago> I think the job of service providers should be to semantically annotate their data, so that a general purpose client can dynamically render it. You mean like HTML? We tried that already and people disliked the lack of branding ability.
- miguelrochefort 8y ago> people disliked the lack of branding ability. What people? Brands or users?
- goliatone 8y agoI would argue both. Systems like Bootstrap still get a lot of flak
- madeofpalk 8y agoHow does that scale? It's more than just 'branding' or pretty colours. What about actual featureS? There's the standard say there's the standard 'airline' app, that handles booking flights and then the lifetime of managing that booking. Reserving a seat and so on. Airlines build the data and the APIs, OS vendors (?) build the frontends. Then Singapore Air or whoever comes out with a new product/service - you can book time in an onboard shower. The 'standard' doesn't allow for ancillary service bookies, so how does Singapore Air get this to their customers? Go through the 'standards body' and wait for that, rather than just building it into their own app that they control end-to-end. In reality, there are too many variations between different companies offering the same service, that it would be rather infeasible to have a single contract they all follow (without compromise) to develop these provider-agnostic client apps. In a way, browsers and native mobile SDKs is the solution to that problem - browser/OS vendors have created clients for common APIs and widget toolkits to create interfaces. The 'hard work' in delivery an application has already been done (no need for the bank to worry about HTTP, or building widgets like text fields), leaving them to delivery 'just' the layer on top of that.
- nojvek 8y agoYou create a standard that covers 90% of most used cases and an nice extension api that allows crazy customization of the last 10%
- madeofpalk 8y agoAhh cool, so like a web browser?
- deleted 8y ago[deleted]
- mwcampbell 8y agoFrom the part on accessibility: > But we also need to make it easy for product developers to do the right thing. What can we do to make accessibility a default rather than an afterthought? Yes! We accessibility advocates have been wishing for this for decades. In the context of web development, application developers should rarely, if ever, have to reach for the ARIA role attribute, because they should be able to re-use existing rich widgets rather than implementing custom ones. I'm hoping that Web Components-based toolkits like the new Ionic 4 will help here. Then project boilerplates should include some kind of accessibility testing by default, so developers will have to go out of their way to ignore it.
- ehnto 8y agoI have had this in mind for years but never followed through with it. Do you know of any groups currently working on the problem? The dream is framework agnostic Web Components that "just work" in a modern browser. You can make it happen with a bit of polyfill javascript. My worry has been spending a bunch of effort making them and then having to maintain separate sets for all the different frontend "web component-ish" frameworks so that people would actually use them.
- nojvek 8y agoFramework agnostic is hard because building a complex UI toolkit always needs some underlying way of binding model control logic and rendering together. So if you don’t end up using a modern popular framework, you have already invented one that is undocumented.
- danabramov 8y agoFor React, https://ui.reach.tech/ https://ui.reach.tech/ is a project that attempts to help that.
- ggurgone 8y agoReact Native for Web also aims to raise the bar.
- 8y ago
- miguelrochefort 8y agoNavigation Whenever we can't fit everything on the screen at once, we use some of the patterns below: - scroll view - virtualized list - tabs - drawer - master-detail - page navigation - modal navigation - alert - tooltip - combo box - collapsible - carousel - gallery It wouldn't make sense to use any of these patterns if we had ∞ sized displays. Would you call all of the above patterns "navigation"? Why not? Isn't navigation just a way to reach content that isn't immediately accessible? Why don't you think of scrolling through a list as some sort of navigation? I think you should. It really helps to re-frame all of the above patterns as simple layout strategies. Layouting is about putting content where it belongs. Whether that content is visible or not (covered, collapsed, out of bounds) doesn't really matter. Let's consider the classic master-detail example that so many people struggle with: Tablet (stacked on X axis) +-----+---------+ | | | | M | D | | | | +-----+---------+ --------X-------- Phone (stacked on Z axis) +-----+ +-----+ | / | | M | / | D | | Z | |----+ / +-----+ / The only difference between these two examples is the stacking axis. That's it. It's the only thing that should change when resizing a window. You don't need to recreate a completely new layout using frames and pages and what not. Re-framing the problem just makes everything much easier. Navigation is just layouting.
- danabramov 8y agoWhat do you make of route transition animations?
- miguelrochefort 8y agoThere's no reason for route transition to be a special case of state transition. Here are some examples of state transitions that can be augmented with animations: - reorder items in a lost - add/remove an item from a list - expand/collapse an element - hover/press/disable a button - show a popup - show an inline error message - open a drop down menu - open/close a burger menu - change the burger menu button to a back button - change the scroll offset to a new item/anchor - increase the height of a text field - show/hide the top menu/navigation bar - add an item to the cart (and the count badge appears/increases) - increase the value of a progress bar - image goes from loading/placeholder to loaded As you can imagine, most of these state changes benefit from transition animations (scale, translate, opacity). We just add linear interpolation to a discrete change. Can you think of a good reason to use different techniques and APIs to implement route transition animations and button state transitions? I can't. Once you think about using gestures for continuous transitions (swipe to go back on iOS), it makes even more sense to think of these components as physical overlapping sheets of material, with their own weight, inertia, grip/transition/friction, rails, anchors, springs. Consider these interactions: - swiping from the edge to reveal a side burger menu - swiping from the edge to reveal the previous page - swiping down to dismiss a bottom sheet - scrolling down to reveal additional list items - swiping horizontally to reveal actions under a list item - dragging horizontally to move the thumb of a slider around - pinching to zoom-in on a picture These are all types of continuous navigations. They don't require animations because you're continuously animating them using touch. These interactions should be easy to implent. Programmatic discrete state changes should automatically infer transitions based on physical characteristics of these materials. What's a route? Should the currently selected tab be part of the route? Should the expanded/collapsed state of a widget be part of the route? Should the visibility of a popup be part of the route? Should the vertical scroll offset be part of the route? Should the zoom level of a map be part of the route? Should the open/close state of a burger menu be part of the route? I think the concept of a route doesn't make a lot of sense if it doesn't capture the entire state and history of a person's interaction with an app. I see no reason why the browser history/backstack should discriminate against different navigation patterns, and only store pages. Adding all state changes to the history makes it easy to use the back button to dismiss a popup, close a burger menu, close the keyboard, etc. Heck, all apps should have universal undo/redo functionality. Another specific type of transition people are struggling with are shared element transitions. For example, you tap on a thumbnail and it seamlessly animates into a detail page with a larger version of that image. This is easier to do as a layout transition than as a route transition. A last thing to keep in mind is that layouts don't need to immediately create and render all of their elements. We can use virtualization, to only materialize what is currently visible. For example, a list of 1000 items will only materialize the 10 or so items it can display at once, and will dynamically create/recycle items as the user scrolls. The exact same strategy can be used if we're stacking items on a Z axis. For example, we could create and render the top 2 items (so that the previous item is immediately visible in a swipe back to reveal scneario), and only create and render other items as they get closer to the top of the stack.
- thenanyu 8y agoMuch thanks to Dan for taking the time to write this up. UI dev is a deep and highly technical field, but we’re often inundated with juniorish programmers because it’s often the entry point for folks coming out of school or boot camps. We need folks writing more about these kinds of principles and less about a new way to reinvent the wheel
- austincheney 8y agoAbsolutely. https://en.wikipedia.org/wiki/Invented_here https://en.wikipedia.org/wiki/Invented_here The name of the game is failure aversion. Frameworks and NPM packages for everything. When I interview JavaScript or UI developers this is my first discriminator. Why write original code or reinvent the wheel when somebody else has your simple solution behind 50mb of external code that you didn't write? If you are that fearful coward who believes in not writing original code I don't want to work with you. Have a nice life and go work somewhere else. I would rather work with somebody willing to take a chance on problem solving. If you are going to down vote please mention why. Don't be a troll. Hacker News tries very hard to not be an echo chamber.
- 0xCMP 8y agoYou're being toxic by calling people "cowards" for simply using a package instead of writing it themselves which reduces the amount of code they need to directly maintain. Displays a complete misunderstanding of the tradeoffs involved as well as being rude. And what's funny is that if you hadn't been a jerk the original point of Frameworks and NPM Packages for everything is a good point and probably would have been well received. Because, the fact is that, sometimes it IS better to do it yourself instead of using the package and most wouldn't. Sometimes.
- austincheney 8y agoThank you for having the balls to respond. I could have tap danced around that by using a bunch of words like: demonstrating a proportional degree of insecurity to the depth of requirements presented across the breadth of considerations required by this responsibility. I found the word coward to be more honest and fitting, though. Ultimately, the rampant insecurity isn't a technology problem. It is a personality consideration. > And what's funny is that if you hadn't been a jerk the original point... People on the internet tend to have big tears and thin skin. I don't like lying to people because they have sensitivity issues. I would rather take the down votes. All these few down votes from a few shattered JavaScript developer hearts are instantly wiped clean when I get 80 up votes for posting a single comment about analysis or interviewing. Being honest and transparent has always helped me in the offline real world.
- amelius 8y agoWow, this page made my top icon tray in Android turn pink. What is the CSS property responsible for this? (My guess would be: background-color)
- nulless 8y ago<meta name="theme-color" content="your-color-here">
- coogie 8y agoThis would be the "theme-color" meta tag[1] which I think only works in Chrome on Android, at the moment. [1]: https://html.spec.whatwg.org/multipage/semantics.html#meta-theme-color https://html.spec.whatwg.org/multipage/semantics.html#meta-t...
- deleted 8y ago[deleted]
- amelius 8y agoI wonder how the author would approach the "infinite scroll" problem.
- danabramov 8y agoThat’s the fun one because it’s at the intersection of several of these problems.
- 2Pacalypse- 8y agoWould love to hear your thoughts as well on this! Especially with regards to remembering scroll position between route navigations in an infinite scroll component that fetches its content asynchronously.
- djKianoosh 8y agoi've thought about this some.. seems to me the url/hash route needs to tell us both the app state and UI state, but most routers dont do this
- joshtynjala 8y agoYou can save arbitrary data when you push a new state with the HTML history API. This data is restored when you go back, and it does not affect the URL. Both React Router and Reach Router allow you to programmatically navigate and use this capability. I've used it on multiple occasions to restore both app state and UI state when navigating back. It's a little more work, of course. You can't just link to a simple URL. You need an event listener that creates the state object and tells the router to navigate manually. You may also need to ensure that any back buttons in your UI actually go back into the history instead of adding a new entry. It would be nice if it were easier, but once you get it working, the level of polish compared to most web apps makes it feel worth the effort.
- nenadg 8y agoEntropy. Good point. I don't think many brought up that issue, it's either ignored (we know what we're doing) or coped with when it's too late (we knew what we're doing). Entropy handling should be the goal for 2019 UI/Frontend engineering.
- Vinnl 8y agoI think the reduction of the cognitive load of entropy was what propelled React (and specifically its innovation of the Virtual DOM) to be the most widely-used front-end framework. Being able to write a function transforming state to a description of the view, without having to worry about getting from whatever the view currently looks like to what you want it to look like, is a huge advantage. It can certainly still be greatly improved, but I think we've already made great strides in entropy handling on the front-end in recent years.
- c-smile 8y ago> innovation of the Virtual DOM Virtual DOM is rather a desperate move - to support components life time constructor/destructor events componentWill/DidMount / Unmount. What if you will be able to define in standard HTML/CSS something like this (as it is supported natively in Sciter) // css div.mycomponent { behavior: MyComponent url(components.js); } // script in components.js class MyComponent : Element { function attached() { /*constructor*/ } function detached() { /*destructor*/ } … other custom component specific methods … } With that simple mechanism you don't need virtual DOM and its overhead at all. Component binding requires only inclusion of that CSS.
- pjmlp 8y agoIf I am not mistaken, Houdini will allow similar features. But it is still far away from standardization.
- c-smile 8y ago> still far away from standardization. Sciter uses this feature almost 10 years. All these 10 years we have libraries of reusable components and so no need for React. Same is about flexbox and grid: https://terrainformatica.com/2018/12/11/10-years-of-flexboxing/ https://terrainformatica.com/2018/12/11/10-years-of-flexboxi...
- escot 8y agoThe Entropy section is great. I’ve been experimenting with ways of leveling down entropy in React by using this little helper to express decision trees in your render function. Not totally happy with it yet though. https://github.com/scottyantipa/photonic https://github.com/scottyantipa/photonic
- aastronaut 8y agoYour approach seems to create an abstraction on top of react where the next step could only be a DSL. This is a first indicator for me that the developer will loose those programming capabilities that react carefully tries to retain and I'm not sure if this is a good approach. I think this doesn't solve the problems of entropy that Dan mentioned in his post and please let me explain a bit further... I think of JSX as a declarative way to redefine HTML and to make it fit to the desired design. Sometimes it's quite possible to find a common behavior of a component and it can become part of a library, but that's not always the case. I like to use react components as a slim layer and prefer to do the work (side-effects, data processing etc.) somewhere else (purely functional modules, redux-saga etc.). My goto-rule to create components became the following: "if I start naming my component with something else than with layout-related terms, then I'm using react as the wrong tool for the job". React is just the view layer, a data processor that puts the view-data into the DOM. And as such a view layer it's sole responsibility is to render conditionally, the responsibility that your linked library tries to extract. I personally prefer to read through early returns in the render method of a component as opposed to following the order of an array. There are behavioral UI problems in an SPA that are not related to the DOM itself. React can't do much about that and I think the problem of entropy stems from there: In the app at work one of the biggest struggles was to keep a global lock for a modal. This modal can pop-up to the user and show a notification, confirmation, form etc. Modals should never overlap with each other, give the user all the time she needs, but should also follow priorities (i.e. a push-notification to cancel the session being one of the highest). The difficulty in managing this lock was that actions from everywhere can pop-up that modal, be it a push notification over websockets, functions called from the native side, failed/succeeded API calls or behavioral inputs that should work differently all over the app (i.e. barcode scanning a product will search for a product in one view, will add it to the cart in another, or will prompt for a follow-up action if no product could be found). Thanks to redux-saga, we can make use of actions not solely to update the store state, but can additionally (if ignored by the reducers) use them like a message bus in a concurrent system. So with redux-saga (and inspired by elixir) I could make use of the actor-pattern and build a supervisor saga that keeps this behavior maintainable, but there is way to much complexity in this. Point being, react and redux do a great job at managing entropy as long as it's used in the correct way. I think each component that doesn't take props can in fact be the starting point into it's own (micro-)application. But I think the biggest difficulties are external influences for an SPA - those interconnected influences that make the web so attractive for an application. EDIT: typo
- revskill 8y agoOne example of hard problem in UI Engineering: Accessibility. In github markdown editor, we can format code by wrapping with ``` . But after that, what happens if we press Tab ? Should the code indent, or the focus move outside of the editor ? It's confusing and annoying currently to move the focus outside of editor.
- 73Solomon 8y agoUI enginerring is what is to be taught in universities
- pdrummond 8y agoI've been building UI for years now and all these points highlighted by Dan are spot on. Great post! I've been thinking lately about the "design system" trend that is becoming more and more popular where companies want more control over styling and behaviour to make their UX unique to their brand as well as consistent across all their products. Ready-made 3rd party components like the excellent react-select don't really fit into this world as general purpose components like this naturally have to make some choices regarding styling and behaviour. No matter how customisable they are, in the end they rarely integrate well into a UI based on a design system. This makes me feel like the abstraction is all wrong. Rather than aiming for fully-functional, out-of-the-box components that cater for all manner of general purpose requirements, how about a library/framework that focuses on a set of primitive components that deal with the lower level concerns like layout, scrolling, positioning, etc. Maybe the abstraction could be more like "composable shapes" than "ready-made components" or something along those lines. With this approach, you wouldn't ever start out with something like a ready-made Autocomplete component, for example. Instead, you would always build a custom Autocomplete and have complete control over styling and behaviour, but it would be built from solid foundations using some form of the "shape" abstraction. That way, you can focus on making the component's styling and behaviour consistent with the design system without having to worry so much about layout, accessibility, scrolling, positioning, etc - as all of these are taken care of by the framework.
- danabramov 8y agoThat's exactly how some of the newer libraries in React ecosystem work btw. For example, Downshift is that "DYI Autocomplete" — it handles a11y and mechanics but you can compose any kind of behavior and styling out of its primitives. https://github.com/paypal/downshift https://github.com/paypal/downshift I'm glad to see this trend.
- pdrummond 8y agoI've used Downshift before and while I like the idea, what I am suggesting is broader in scope. A set of primitives such as Overlay, Rectangle, Circle, List, Row, Column, etc that still allow you to apply styling but overall they sit at a lower level of abstraction than ready-made components, even ones based on something like Downshift. The more I think about this the more I feel like I'm describing exactly how "Qt Quick"[1] works, the declarative user interface markup language that is part of the Qt Framework. Of course, it's not a web technology but it would be interesting to see a web-based framework/lib based around some (if not all) of the ideas found in QML. [1] http://doc.qt.io/qt-5/qml-tutorial1.html http://doc.qt.io/qt-5/qml-tutorial1.html
- diaktifkan 8y agoRe: Entropy I was looking at a responsive thermostat component with an on/off control with a 4-state on/off button for a web miner. It had a ticker which displayed two metrics updating at time and framerate intervals intervals with time-based device status interstitials in multiple languages. XState is great for testing these situations.
- cityzen 8y agoMy experience with this type of intricate UI engineering is that often agencies and UI/UX consultants sell this romantic idea and fail miserably to execute on it. It is either that the agency way over extends itself on the theory that they leave no room in the budget for proper execution or the front end devs do not have the experience to do it right.
- ecp9 8y agoThe points are nice, it would be amazing if the 90% of the web wasn't dumpster fire of inconsistent slow and hard to use sites.
- nyadesu 8y agoIs there any book that actually cover those problems from a technical view point? Not from a UX/designer perspective
- obastard 8y agoOn the principle that you can solve every problem in computer science by adding a layer of indirection, we solved all the problems listed in that Dan Abramov article by adding a few layers of indirection. You didn’t write a fetch ever, you subscribed to a data feed from the data feed repository. To prevent redundant fetches, the data feed was served by a cache, which then filled cache entries by doing the fetch. Doing a POST invalidated the whole cache. Which triggered fetches of everything, but only once/API. The fetch return pushed out to all the subscribers. The subscription was driven by the JSX, so only visible items had active subscriptions. Essentially, you wrapped your UI with the fetcher component, during your JSX display tree into a data dependency tree. Optimizing the cache invalidation was a problem we ignored for later, because the fetch overhead wasn’t too bad, and we went from doing 40 fetches/page without the cache layer to 10, so the back end never noticed.