Since the genesis of the browser in 1993 the reigning web paradigm has been request-response. A user who wanted to view a webpage sent a request to a content server; the server received the request, processed it, and responded with the webpage. This pattern lent itself to linear experiences punctuated by page refreshes. Given that the internet’s original intent was to view documents, request-response was satisfactory. Since then user needs & expectations have evolved.
AJAX technology was the first step in this evolution. It refined the web experience by allowing users to load new content without a page refresh, but was constrained because loading this content still required action from the user. While this was great for singular user experiences like browsing static documents it was untenable when it came to multi-user environments. The internet is not a solitary experience. In 2014 we expect our apps to be connected and react to changes from multiple users’ actions. We want to feel as if our digital connections have a physical presence. This is where realtime technology shines.
The introduction of user-friendly asynchronous frameworks like Node.js and now Meteor have lead to widespread adoption of realtime web technologies and a new set of challenges. Prior to realtime, the provenance of actions was clear. They could be attributed to a single user and were punctuated with a page refresh. Click a link, page flash, and voilà your content has arrived.
Now add several users to this system who act on the same data and whose interface is updated reactively –without a page refresh. Imagine the difficulty in communicating the rationality of the system to the end user. When the interface changes in front of someone despite their inaction there is opportunity for uncertainty to take hold. In the realtime world our challenges are not only to build delightful features, but to translate complexity and illuminate causation in data.
Translation is to express the sense of words in another language. It is expressing the complexity within our apps in a way that is natural and easy to understand. In practice, this is just reassuring users that our apps can understand, register, and respond to their intent.
Causation is the relationship between cause and effect. Our goal is to illuminate relationships in data which just means to show how two data points can conceivably lead to a new insight or that lever A affects lever B.
Creators can harness the power of realtime to drive next-generation web experiences. Percolate Studio has been fortunate to have a hand in crafting some of these experiences with our clients. We’ve also had our fair share of missteps. Out of these challenges emerged a set of simple principles that serve as the basis of our approach to designing realtime user experiences.
1. Be State Aware
The user should know the state of the system. At all times the product should communicate what’s happening and confirm user action.
Applications attempt to provide structure to an otherwise unstructured system. Since realtime reactive interfaces change can without inherent signals like a page refresh creators can be transparent by including the appropriate signals to communicate state.
Example: Connection status
Is your connection active? Connection dropouts are unavoidable. Communicate that there are factors outside of the apps control that could lead to unexpected results.
Figure 1. Bad: The user is not informed of a connection loss that may affect their experience.
Figure 2. Good: A notification appears to communicate that the connection is down and the system is trying to fix it.
Low bandwidth, weighty assets, and spotty connections interrupt experiences by causing users to wait. Be a proactive designer by highlighting that the system is processing user action and loading new data.
Figure 3. Bad: The user is not informed that the app is actually loading their content after interacting with an item.
Figure 4. Good: A progress indicator appears in response to the item tap to indicate how long to wait.
Responding to user actions shows that the system is listening and cares about their objectives.
Figure 5. Bad: The user lands on a new screen without indicating whether the deletion was successful.
Figure 6. Good: A confirmation appears to reinforce the delete when the user lands on a new screen.
2. Expect Change
The user should know what to expect. The product should communicate what will happen when a user acts.
Surprises in a logical system are not delightful. Consider the mechanical precision of an automobile as it transports passengers to their destination. Surprises in this system are flat tires and engine smoke. Like the car, an app facilitates a persons intent and attempts to translate immense machine effort in a user-friendly manner. Unlike the car, the digital medium allows us to anticipate and inform users of change.
Example: Communicate Results
When drastic state changes are possible, foreshadow the result of actions. Giving users opportunities to process what’s going to happen prevents surprises.
Figure 7. Bad: New results appear in view without indication or action.
Figure 8. Good: The system prompts action when new results are ready to be loaded, but doesn’t disrupt the experience by rendering the items automatically.
Example: Skeleton Templates
Showing a skeleton of your layout foreshadows new screens and sets the expectation that data will fill the empty spaces. As a side benefit, your app also feels more responsive.
Figure 9. Bad: The user is forced to wait for all content –including a heavy image– before showing the screen they want
Figure 10. Good : Instead of waiting for all content to load before showing the screen, the page loads with placeholders that indicate which content is ‘coming soon’.
3. Preserve Context
The user should know where content comes from and where it belongs.
Since we can’t possibly see or even consume what’s happening at all times in realtime apps, it’s important that we establish and reinforce the sense of space –where each screen and button lives in relation to other elements. Doing so means that we create landmarks that the user can rely on to get their bearings.
Example: Consistent Placement
New content should appear in a predictable location. Get users accustomed to navigating to key points in your app. Don’t dilute actions by providing several ways to accomplish the same thing.
Figure 11. Bad: New items appear in unpredictable locations.
Figure 12. Good: New items always appear in one location at the top of the list. Users are trained to navigate upwards to see the most recent additions to the list.
Example: Maintain Bearings
Articulate state changes that do not appear in a predictable locations. Animation can be used to great effect to communicate where new content is loading and its relationship to its surroundings. Slowing the user experience sometimes results in greater clarity.
Figure 13. Bad: A new item flashes into view causing adjacent content quickly to shift position.
Figure 14. Good: The new item and its siblings are animated into their positions over time thereby affording the user a moment to process state change.
Example: Save Scroll Position
When moving back and forth between distinct screens, ensure that users return to the same scroll position they entered from.
Figure 15. Bad: The scroll position is reset every screen. The user expends more effort to return to the same location and is discouraged from browsing.
Figure 16. Good: Position is saved between each screen. It reassures the user that they can always trace where they came from.
Principles are foundations to build upon. These principles serve as our starting point when crafting realtime experiences. I encourage all creators to discover what works for them, but for a head start try: be state aware, expect change, and preserve context.
Ideas in this article build upon and were inspired by these fantastic researchers, designers and companies:
Luke Wroblewski’s excellent UX video series
Sacha Grief’s insight into designing Telescope –a realtime Hacker News
Chartbeat’s inspiring realtime analytics product
Apple Human Interface Guidelines