You don’t need a single-page application

I am really annoyed by the recent trend of making every single website a single-page application even when it is not necessary and makes the product worse. Let’s take the example of the Reddit redesign and see why I think it’s a horrible idea, and then go over a few other websites with the same problem. We’ll ignore the user-hostile design decisions like explicitly degrading functionality and advertising the mobile app, and focus purely on the technical aspects (the user-hostility is a rant for another day).

The “new” Reddit #

First let’s take some measurements. This will be done on latest Safari on macOS Mojave with all add-ons (ad blockers, etc) disabled to make sure the website is rendered as the developers intended without any interference. The pages were first loaded to populate any caches and the graphs were taken on the second page load (so most of the assets should be cached).

Screenshot 2019-12-12 at 11.38.40.png

This is the new Reddit - the page loads in around 8 seconds.

Screenshot 2019-12-12 at 11.40.48.png

This is the “old” Reddit for the same page - it loads in around 4 seconds.

The “new” technology is making the product 2x slower and uses a lot more resources in terms of CPU, memory and network usage, for what exactly? What does this “new” technology allows them to do that the old one couldn’t? I can’t see anything they’ve done on the new one (including the user-hostile elements like ads, “download our app” popups, etc) they couldn’t have done on the old one.

Bear in mind, this is on a modern machine (2017 MacBook) with a fast network connection and zero packet loss.

YouTube #

YouTube switched to a single-page application a few years ago, and it’s still unusable in Safari. Navigating between pages is slower than loading the new page from scratch, to the point where I got into the habit of manually refreshing as soon as the address bar switches to the new page’s URL. When navigating to a video, even after the video player loads the other elements still take seconds to load, and best of all, if you switch to full-screen mode on the player the other elements will bring you back into windowed mode when they finally load. I am scared to interact with any unfamiliar element of the page in fear it’ll navigate to a different page and I’d have to waste 10 seconds waiting for the original page to fully reload.

Airbnb #

The Airbnb website is also a single-page application, and I believe it’s server-side rendered. It still doesn’t feel as fast as a conventional website and basic elements such as input field autocompletes feel heavy and consume an insane amount of CPU even though people have implemented such things in a much faster way decades ago on smaller CPUs & less advanced browsers with plain old vanilla Javascript or a bit of jQuery.

I’ve also had the displeasure to use their React Native app on iOS and it was a slow, horrible mess that would in certain cases get in an inconsistent state where it would either stop responding to touch events or just display a black screen. Thankfully, they finally saw the light and decided to drop the madness. I don’t even want to imagine how much engineering effort (and thus money) was wasted on this “experiment”.

The user-facing problems #

Unlike with a conventional HTML, CSS & JS website where each asset loads independently and the page may function even if some are missing (the CSS may not load, but the text will be still there), a single-page app will not function until all the Javascript has downloaded successfully which can be a major problem on flaky network connections like public Wi-Fi or mobile networks with low signal. The user may get stuck on a blank page or loading spinner forever. Browsers are also good at providing feedback when things fail to load, while on a single-page app it’s up to the developers to handle that manually and provide a way to retry the request when an API request fails.

The other problem is the CPU & battery life impact of parsing & executing all that code, even more so on older devices. This is something even server-side rendering (the standard response from the front-end crew when performance issues are brought up) won’t solve, as the code will still need to be parsed & executed before the SSR’d page actually becomes usable.

Bandwidth usage is also a problem, especially for mobile devices where people have a limited amount of data they can transfer in a month. The code for a single-page application is pretty much always larger than the content the application is supposed to display, so you’re wasting your user’s precious bandwidth for nothing.

Finally browsers had decades to optimise & perfect behaviours such as remembering form contents, scroll positions, etc when using the back button and people got used to them. All of these need to be manually implemented in a single-page application which takes a non-trivial amount of work to get right, and most companies don’t bother. As a user, I can no longer rely on these behaviours and need to guess what will happen.

The developer problems #

The toolchain required to build & run a single-page app is insane. We’re pulling in hundreds of megabytes of untrusted dependencies, using dozens of different polyfills & transpilers for what exactly? We’ve dug ourselves into a hole and now need even more tooling to have the illusion that we’re getting out of the hole, while in reality we’re just digging deeper and accumulating even more technical debt. We are introducing insane amounts of complexity for a worse experience.

I remember working on a project that used a backend with a REST API and a front-end in React. Only one page needed to be “real-time”, everything else was standard CRUD & data entry, but they’ve still decided to make the entire website a single-page app. The backend was always ahead of the front-end despite accomplishing a much more complex task, but despite months and several front-end developers, we still couldn’t even try out the basic features of the product because the front-end was stuck at the user signup stage which is just a sequence of forms (it could’ve easily been accomplished with HTML forms and our backend framework had lots of helpers for those so the entire feature could’ve been solved in a day or less).

Another company I was involved in had a REST API backend to which the mobile apps talked directly but for their web front-end they went for a React front-end consuming a GraphQL API provided by a custom proxy that in turn consumed the REST API. While it worked fine and no incidents occurred, why would you introduce all these extra moving parts, complexity and maintenance overhead in the future? What was the point of that whole GraphQL thing?

So when it is right to use a single-page app? #

My rule of thumb to determine whether a single-page app is justified or if it’s just resume-driven-development is as follows: if the application will only be loaded once in a single tab and the user will spend their entire day in it, then a single-page application makes sense as the performance drawbacks are only incurred once during initial page load. A data-entry application, point-of-sale, etc are good examples of this.

Content websites, where there’s a single page per content item and people may open multiple tabs never justify a single-page application - you’d be forcing them to download, parse & run an insane amount of code just to display the tiny amount of content they’re actually after.

Next time you’re building a product, please evaluate the options and choose the right tool for the job from your customers’ perspective. By the way, the same applies for a lot of other technologies - Kubernetes, “serverless”, etc. Remember that Stack Exchange runs a successful product using boring, old-school technology.


Now read this

Using a GnuPG smart card, Yubikey/NitroKey for SSH on Mac

Install GnuPG and a decent PIN entry program # $ brew install gnupg2 pinentry-mac Configure GnuPG # We’ll need to tell GnuPG to use the new PIN entry program as well as enable SSH support for its agent. In ~/.gnupg/gpg-agent.conf:... Continue →