6 steps to improve your web app’s performance

We’ve created a set of guidelines that will help you improve your Web App’s performance from the get-go.

Roberto González
Aerolab Stories
11 min readNov 7, 2017

--

When you start building a modern Web App, one of the first things that hit you in the head like a brick is the fact that not only are most phones a lot slower than your computer, but the 3G/4G connections most users have are not strictly speaking awesome.

In fact, the differences between the experiences on localhost and the actual production servers can be so dramatic that if you don’t take a few precautions, the second you release your app you are going to realize that your product performs incredibly poorly for most users, and they’ll probably hate you for it.

To prevent this from happening to us, we created a set of guidelines with the most effective steps you can take to improve your web app’s performance from the get go, as well as preventing performance rot when you start piling on new features on top of that beautiful first release.

1) Set a Performance Budget, and stick to it

A Performance Budget is a clear objective of how fast your web app is expected to be. The goal is to prevent your team from turning the product into a mess of caked-on features that takes an eternity to load, which is pretty much inevitable in long-term projects. As you can imagine, there are two main components in this strategy:

  • Setting the Performance Budget itself
  • Actually following through with it (which is, incidentally, where everyone fails)

The best way to implement this is to get the Product Owner to clearly set performance as a priority. This will lead the team (designers and developers) to focus on mobile, where speed is one of the most important features.

Once that’s done, the next best step is to plug a rule into your CI Pipeline that blocks all pull requests that don’t fit the bill. And no, you can’t make exceptions (that’s kind of the point of a CI rule).

These are the two main rules we’re using at

. Feel free to copy them:

Don’t take more than 1 second to show the user what they want to see

(1 second Time To First Meaningful Paint on good WiFi on our standard issue Macbook Pros)

The web app has to be interactive in 1.5 seconds

(1.5 second Time To Interactive on good WiFi on our standard issue Macbook Pros)

Having a clear performance objective will touch everything in your stack, from the design and the Javascript libraries that you pick, all the way down to how your servers are being set up.

Implementing a performance budget -and defending it-, is a great way make your entire team work together on making the product fast.

Once everyone understands how their work impacts on this metric, you’ll be able to stop performance degradation right in its tracks, and that means you’ll keep the great speed from that pristine first release across the entire life of the product.

2) Keep your core as light as possible

This seems strangely relevant

There’s one thing that you should keep in mind when starting a new project:

The core frameworks and libraries you use to build your product are usually going to stick around for its entire life, making those decisions pretty much irreversible.

So, if you pick an impossibly large enterprise framework that somehow needs to run a Linux VM in the browser, you can say goodbye to your product’s performance until the next big refactor. Which is, of course, never going to happen because removing things is much, much, much more expensive than adding them back in.

The best piece of advice I can give you here is that you should pick the lightest possible solution that helps you do the job. If you are building a product that’s very close to what a browser can do on its own (like a news site, a blog, an ecommerce, or anything that mainly shows text, images and videos), you usually only need the bare minimum to help you have an organized codebase and try to keep the peace when merging pull requests.

Exercise your professional judgement here. If you are building a product for millions of mobile users, picking a insanely heavy enterprise stack can be catastrophic from both the UX and revenue side of things. If instead you are working on some intranet app that few people use once a year (or just trying out a new framework), you can just throw in all the crap you want because nobody’s really going to care about it.

If you want some reference here, our go-to libraries for web development are Preact (a fully compatible React clone in 3kb) and the Next.JS framework, which provides server side rendering, offline support, prefetching, great docs, and a fantastic community.

This hits the sweet spot for most projects and it’s very easy to add features on top of that tiny codebase. Combining this approach with the next tip we are able to load our latest web apps comfortably under the one second mark, which is fantastic from a UX standpoint.

3) Design a Loading Strategy

If you’ve been working on this field for a while you know that eventually you’re going to need to shove an impossibly heavy component into your product, destroying all of those performance gains from the first release. What’s worse, this will demotivate your team and make them feel that all their efforts on making the product fast were pointless.

But don’t despair! There’s a way to cheat when that happens, and it’s called Designing a Loading Strategy, which is a shared effort between designers and developers.

The main principle behind a good Loading Strategy is to never let our users know when our app is loading. Or if we simply have to (like when the app is starting up), make the process as fast and as pleasant as possible, loading the important things first and everything else either late or never.

The best way for trying this out is to grab the heaviest component in your app (you know, the one that requires a ton of JS but is used like twice in the entire site) and split the loading process into two subcomponents:

  • A placeholder version of the component, that requires just the bare minimum amount of code, but will otherwise fit neatly into the page and look just like the real thing. For example, if the component is a complex video player that loads dozens of ads, you typically just need to show the thumbnail and a play button. This is what you’ll show the user when the web app first loads. You get extra brownie points if you make it seem like it actually works.
  • The real version of the component, which you’ll load only after everything that’s actually important in the site loads properly. The best way to do this is to defer the loading of that component’s dependencies and other stuff after the window load event, and when you finally get all that code, you can transparently replace the placeholder component with the real, working one.

One of the most popular examples of this technique is the progressive image loading effect used by

, and a few others, which embeds a very low resolution image with the HTML (to act as a placeholder) which then transitions to the full image once it loads:

If you do both steps correctly, this new heavy component won’t interfere with your initial load times (letting users start using the product just as quickly as before). Everything will still load and function properly, and that component will load a few tenths of a second later than the rest of the web app. If the transition to a working component is believable, your users won’t notice it at all, which is the gold standard for performance.

Keep in mind that even with a clever loading strategy, loading large JS libraries will still lead to some noticeable stuttering on most phones. So, even if you have the most clever loading strategy in the world, you should still try to load as little code as possible.

4) Develop on a midrange phone

One of the best things you can do as a developer is to actually code on the same hardware that most of your users have.

You’re free to write your code on a top of the line Macbook Pro, but you should get a cheap used Nexus 5X or Moto G4 and pack it in your bag just to try your code live on a midrange device. If you want to truly commit to this tip, you can also throttle that phone’s connection so it mimics a reasonably decent 3G connection. Using Chrome with Remote Debugging will make the experience almost as good as developing on your computer.

This will open your eyes as to how most people are actually experiencing your app in the real world, and it’ll also give you a clear idea of how little CPU and RAM is actually available to a real user. The second you start getting frustrated because reloading takes way too long on your phone, you know that you are shipping way more code than you should.

The differences between devices and platforms can be dramatic. For starters, iPhones are usually twice as fast compared to the best Android phones according to most benchmarks.

Just to give you an idea of just how slow most phones actually are, Addy Osmani wrote a great article on JS Startup Performance, and one of the datasets he shows is how long it takes to parse and execute 1MB of Javascript on different devices:

According to this metric an iPhone 7 is about 8 times faster than a Nexus 5X (or 14 times faster than the more average Moto G4). So, if you are developing a javascript-intensive web app using the latest iPhone or Macbook as a reference, you’re going to get a very distorted idea of how your code performs of an average phone.

Testing on different devices isn’t just for solving a few CSS quirks here and there. It’s about the fact that 60%+ of web users are on a mobile device (and up to 80%+ in emerging markets), and very few of those users own super expensive flagship phones with unlimited data plans.

If your app works poorly on an average phone with a typical connection, it’ll also work poorly for the vast majority of your users.

5) Use Server Side Rendering

The best way to make sure all the JS behind your web app doesn’t interfere with your product is simply to get rid of it. While purists will tell you just to write plain HTML (which is not a bad idea by the way), working with modern frameworks like React will give you some very compelling productivity, tooling and teamwork benefits that are harder to achieve with an older stack.

A simple way to do this is to take advantage of Server Side Rendering, which renders your site on the server (including performing all of those pesky network requests), so you can deliver plain HTML to both your users and bots. Most good microframeworks (Next.JS, Create React App, Preact CLI, and a few others) will handle that for you, and the edge cases are few and easily solved with a few Google searches.

Since rendering HTML has been a core browser feature for the last few decades, this will help render your critical content very quickly and won’t force your users to wait for a few extra roundtrips for your servers to deliver a massive Javascript payload and a bunch of API requests. What’s more, since HTML is very easy to cache you won’t have to continuously hammer your frontend servers for rendering, and this can help take a few milliseconds off your initial load times.

You’ll also get some SEO and Sharing advantages, as plain HTML can be parsed with a simple curl request instead of having to run a headless browser. While the main search engines will execute and index Javascript-heavy sites, this will give you better compatibility with some other services (like Twitter, Linkedin, Pocket and quite a few more), as well as making that part of the product more predictable and less prone to bugs.

6) Build for Offline First

Mobile users tend to have very unpredictable network connections with varying speeds and rates of packet loss. My favorite word for this is Lie-Fi, where your phone tells you that you have a connection when you actually don’t -or it’s just infuriatingly slow-. Combined to the fact that most mobile users are usually on a rush and have very little patience, this doesn’t exactly help your product win over new users.

Making your product take advantage of Offline features like Service Workers or just caching everything under the sun is a critical requirement for most modern products. Most frameworks will help you with the hard problems, like cache invalidation or updating resources, but it’s up to you as a developer to take advantage of those features and make sure both your newest and your most loyal users get absolutely amazing load times.

The best thing about this is that there are libraries like Workbox that make setting up Service Workers a breeze, so you can relatively easily add it to your product and get a very nice feature working without many issues.

Ensuring your web app is designed to work well when offline is one of the key features of building products for mobile first. Mainly because it helps you get a more app-like experience, making your site more accessible when there’s bad connectivity (like during subway trips if you live in a big city), or just simply taking advantage of cache so everything loads pretty much instantly on return visits.

Final words

I know that focusing on performance usually doesn’t sound as sexy as adding a bunch of new features, but making your product fast can give you some absolutely amazing results when it comes to engagement and revenue, simply because people like using fast products, and the stats for good PWAs overwhelmingly support that conclusion.

If you truly want to build amazing products, it’s everyone’s responsibility to keep performance in mind. Having the entire team work towards the goal of making your web apps fast and lightweight is one of the most important steps you can take towards building products that people can truly enjoy.

If you are looking for more awesome reads on Design and Development, you should check out our blog✨

--

--