Skip to content

Instantly share code, notes, and snippets.

@trek
Last active December 22, 2015 05:49
Show Gist options
  • Save trek/6426610 to your computer and use it in GitHub Desktop.
Save trek/6426610 to your computer and use it in GitHub Desktop.

Progressive Enhancement: It Depends

If you haven't visited Sigh, JavaScript for a good laugh, you should. It's the latest volley from the progressive enhancement community in response to the growing trend of writing full client applications that run in the browser and rely on a server for assets and data but not for rendering or state management.

Effectively, web applications written in this pattern mirror how client applications are written in any environment where the server doesn't pre-render a serialization of the interface. So, as an example, an iOS app doesn't request a pre-rendered screen from a server and display it to a user. This would require a rather odd tight coupling between server and client. Instead, the code for an iOS application contains all the necessary instructions to render the UI and a server is optionally used to retrieve any data that is stored centrally.

Progressive enhancement adherents seem incapable of seeing the distinction between documents viewed in the browser and apps that use HTML markup as their view drawing layer. People who both craft documents and program applications seem to have no trouble identifying each. I'm not going to get into a definition argument, so let's just assume there is some amount of connoisseurship involved.

Leaving the "document vs app" distinction aside, we can address the more important topic of interactions.

A web browser comes with two basic interactions enabled "natively": scroll and navigate1. Even the most basic browser supports these interactions. In GUI browsers we scroll via arrow keys, track pads, or continuos touch and navigate with mice, track pads, or finger tap. In command line interfaces it's arrow and <enter> keys.

Combining these interactions is all you need to build the rich and impressive experiences of a hypertext/hypermedia system.

Beyond Scroll and Navigate

Scroll and navigate can be combined to accomplish most user goals, but they can't cover everything. Even goals that a user accomplishes via scroll and navigate can, in many cases, be reached in fewer steps, with greater accuracy, and with better responsiveness using other interactions.

Google maps, which was arguably the killer app for these new emerging techniques, demonstrated this decisively in 2005.

MapQuest, then the only real game in town for online mapping, used scroll and navigate to control interaction of a tiled image series. To zoom in and out you clicked a vertical array of buttons that represented zoom levels. To load a new tile, you clicked a button at top, bottom, left, or right of the loaded tile to load a tile from the north, south, west, or east respectively. On top of this, MapQuest even progressively enhanced the tile with additional interactions, like viewing information about gas stations:

Map interaction via scroll and navigate is clearly possible, but not ideal. Google updated the interaction to use drag, which is not a "native" browser interaction, and vastly improved the experience in the opinion of some people. Actual users, at the time, were less enthusiastic. Because drag isn't native to the browser, people didn't expect to be able to use it on Google Maps. Novice users were often unaware that this style of interaction was even possible!

No human computer interaction is intrinsically "intuitive" or "usable". Every interaction requires learning on the user's end and education from the system's end. Early mouse users needed training manuals. Early websites included descriptions of how to navigate. Today, we get to make nicer experiences available by taking mouse use and website navigation as givens.

Progressive Enhancement or Pretty Little Lie?

So, what does any of that ramble have to do with advocating the use of progressive enhancement? Pretty much everything. Dan Mall, in his post about the Sigh, JavaScript site notes:

There are usually 1 of 2 problems that I often see with sites not properly utilizing good progressive enhancement techniques (which most of the sites on Sigh, JavaScript also suffer from):

All of the content—read: markup or HTML—is generated by JavaScript. Or, the markup is good but styles are written in such a way that JavaScript is required to view the site.

Dan then goes on to demonstrate how to take a list of stock quotes and progressively enhance it to do things like

like manipulating the markup for the table-to-graph conversion, adding points real-time, updating the time on the page to show that it’s real-time, and removing the prompt to refresh since it’s not necessary anymore.

Which I think highlights the key test for whether progressive enhancement is viable for your specific use case and demonstrates that unnamed distinction progressive enhancement advocates swear they don't understand. Notice anything about the interactions both before and after enhancement?

Yeah, it's still only about scroll and navigate.

What would happen if we blindly applied progressive enhancement to something like Google Maps where the main interaction doesn't have native support? We'd actually work counter to one of the stated goals of progressive enhancement by decreasing usability and accessibility. If a user expects to drag the map around to load new tiles and the dragging behavior isn't enabled for a time, what was the point of showing them a pre-rendered screen? They didn't visit to see an image of a map, they came to do things to a map. Without the interactions the content is useless. The more accessible option is not frustrating someone with a lie: the useful looking display that is secretly noting more than a pretty loading screen.

@trek @tobie @jaffathecake @necolas It’s basically a Potemkin village of UI until the JS finishes loading.

— Tom Dale (@tomdale) September 3, 2013
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

Holding Back The User

Of course, if progressive enhancement were a required feature, we could alter Maps to use it. Display arrow buttons à la old MapQuest that trigger a new page load and are enhanced to make this request via Ajax when possible.

This comes with some nasty usability issues too: what if a user never waits for the progressive enhancement and instead immediately clicks the North button. Then, when the new page loads, they click North again. And again, and again. They'll never see the benefit of nicer experience until you teach them to wait for it. Worse, we have to completely abandon the superior experience of drag interactions. The presence of a button means most users will never learn that dragging is possible. And, if they do know to drag, it mysteriously won't work sometimes but will work others times. They'll just use the buttons which work consistently.

Should you deliver a poor experience just so you can deliver it faster?

Performance

Progressive enhancement advocates usually mention performance as an important rationale for using the technique, bringing out Twitter's move to progressive enhancement as primary example of how progressive enhancement is a performance win. Performance, of course, is a complex, multi-dimensional measure. Twitter used "time to first tweet" as the primary metric for their rearchitecture:

The most important metric we used was “time to first Tweet”. This is a measurement we took from a sample of users, (using the Navigation Timing API) of the amount of time it takes from navigation (clicking the link) to viewing the first Tweet on each page’s timeline. The metric gives us a good idea of how snappy the site feels.

Moving from in-browser rendering to server rendering that becomes progressively enhanced certainly worked for Twitter: they got a 5x performance increase. You'd be crazy not use similar techniques if it nets a 5x performance boost... for the same specific measurement. If your product is primarily about the consumption of text then scroll and navigate are probably going to be the primary interactions and, yes, you can sugar nicer interactions on top of that after the primary interactions are available to the user.

In his article Progressive enhancement is faster Jake Archibald's demonstrates that progressive enhancement is indeed faster in a real world comparison of Twitter and Tweetdeck. The video examples are telling. You should head over and watch them but essentially they boil down to:

So Twitter gets the core content on the screen 7.91 seconds earlier than Tweetdeck, despite six windows fighting for resources. For the first bit of core content, Twitter gets it on screen 3.03 seconds sooner.

and

So, with a full cache, Twitter beats Tweetdeck to all core content by 2.77 seconds, and first core content by 2.01 seconds.

Progressive enhancement certainly trounces client rendering for this specific metric. But there are many metrics where progressive enhancement performs poorly in comparison. Test them out yourself:

  • I'd like to move Interactions to be the left-most column. In both Twitter and Tweetdeck, measure the time from page load to swapping the first and last columns.
  • I'm trying to find a specific Interaction that occurred in the last hour, but don't recall the exact term used. In both Twitter and Tweetdeck, measure the time from page load to a series of live filtering interactions until you have found the specific interaction.

Tweetdeck, in fact, accomplishes these tasks with infinitely more performance than Twitter. Now, we might say this is an unfair comparison because we're just exercising features that Twitter doesn't have but you could also say the "time to first tweet" comparison is unfair as well: Tweetdeck is more about doing than seeing.

If some of the features of Tweetdeck were needed in Twitter, could Twitter still use progressive enhancement and deliver a pleasant experience? Or would they make something like our hypothetically unpleasant progressively enhanced Google Maps so they could maintain a better performance on the "time to first tweet" measurement?

Scroll and Navigate Revisited

So, if the main goal of someone using your product is viewing content and the primary interactions will be scroll and navigate, you're pretty much guaranteed to provide a better experience if you send server-rendered HTML so they can reach this goal immediately.

Well, maybe.

There aren't many sites whose primary interaction is scroll and navigate that are built entirely in the browser, but recently one came out that is fairly impressive: Bustle. Go load Bustle and compare it to an article site that is server rendered with a similar number of articles of similar length. I picked TechCrunch as a counter example.

On the metric "time to first read" you'll notice both sites are, perceptually, identical.

Click to read an article of similar length on each site and you notice how Bustle loads so fast it appears instantaneous. For the metric of "time to next article", Bustle is almost 4x faster than the server rendered page. The initial page load includes the JSON data necessary to render itself, a second request for javascript loads the framework they use for rendering and the template compiled to a function. When navigating to another article, Bustle only has to fetch the subset of data needed for the article, not the entire page serialized as HTML, and combine that with the template the browser already has.

A year ago, I would have told anyone thinking of creating an article site entirely in JavaScript to rethink their decision. But, honestly, I was just being dogmatic. A "content site" seems like the right fit, architecturally, for server rendering. I don't think I would have spent the time testing my gut feeling against real, hard evidence. Bustle proves, to me, that some content sites can clearly be entirely client rendered, not sacrifice performance, and for some metrics (subsequent article loading) provide a better experience.

What is especially impressive about Bustle is that the tools and techniques for delivering client-rendered content sites are still in their infancy. I can't wait to see what happens when patterns and practices for delivering client-rendered content begins to get better native support.

Progressive Enhancement Is Dead Then?

Well, no. Like any technique, progressive enhancement has specific use cases and can deliver specific benefits. Every architecture choice comes with tradeoffs and anyone who pretends there is a correct architecture for all situations needs a solid dose of pragmatism.

Don't fall into the trap of mistaking the means for the end. We want to deliver a clear, fast, responsive, and useful experience to all our users in a way that won't complicate future development. The number of situations where progressive enhancement is the means to that end is much smaller than it was ten – or even five – years ago. Just like there's no reason to abandon old practices that still work, there's no shame in jettisoning ones that don't solve the problems you have today.

1 There is also form entry but it represents only a tiny fraction of interactions comparatively.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment