Copy
You're reading the Ruby/Rails performance newsletter by Speedshop.

Looking for an audit of the perf of your Rails app? I've partnered with Ombu Labs to do do just that.

日本語は話せますか?このニュースレターの日本語版を購読してください

5 simple rules that lead to web performance nirvana

Recently, I've been getting back into cycling. I've been training consistently for about 3 months now. One of the people I follow on Twitter to support this hobby is Alan Couzens, an exercise physiologist out of Boulder, Colorado. He tweeted:
  This idea - a short set of simple rules designed to get you 80% of the output with 20% of the thinking, reminded me a lot of the old Sandi Metz rules. Some of you may remember:
  • Classes can be no longer than one hundred lines of code.
  • Methods can be no longer than five lines of code.
  • Pass no more than four parameters into a method. Hash options are parameters.
  • Controllers can instantiate only one object. Therefore, views can only know about one instance variable and views should only send messages to that object (@object.collaborator.value is not allowed).
The point isn't the rules, of course. Rules are made to be broken. Not every class actually needs to be 100 lines of code or less for your codebase to be "good". But, just the act of trying to follow these rules forces you to follow good practices: how do you take a big class and make into a small class? You don't - you decompose one big class into several smaller, simpler classes that each do one thing. These rules are also simple and easy to follow, and none of them are really "anti-Rails" or far from the mainstream.

Of course, this got me thinking... what are the rules of web performance? What is the short set of rules you can follow and end up with an app that's a joy to use and feels nice and quick? We'll leave scalable and robust for another day - just focusing on user experience here.

I came up with a list of five rules. It turned out, none of them are Rails specific.
 

You must use Real User Monitoring (RUM) and Application Performance Monitoring (APM)


Web performance is an engineering discipline. There's quite little art to it, and a lot of numbers. We can't do performance work through "craftsmanship". That way leads to premature optimization, a navel-gazing kind of focus on every single line of code. We need tools to help us to know which pieces of code matter, because it's usually less than 1% of the lines of the entire codebase that contribute to 99% of the performance slowdown.

Real User Monitoring has become the entrypoint to this sort of discipline. These tools run in client web browsers, and beam back home information about how long the page took to load, what resources were downloaded, and what actions the user took. Vendors like Datadog and Sentry are the most popular, but there are even performance-focused RUM agents like Speedcurve. What's important is that you have something installed, and that it can tell you metrics like Largest Contentful Paint, and hopefully can measure details like which requests the client made and how long they took.

Application Performance Monitoring is an easy box to check. I would guess that 90% of the people reading this newsletter have New Relic, Sentry or Datadog installed and look at their server response time dashboards regularly. This is important, but not as important as RUM, which is unfortunate, as I see much fewer apps using RUM. Remember that the user's experience of performance happens in the web client - the browser - and not on your servers. Usually, server response time makes up just 15% or so of the time spent waiting in the browser. That's not nothing, but it's far from the most important part.
 

Use a Content Delivery Network (CDN) for everything


It doesn't matter which one. Cloudflare, Cloudfront, Fastly, whatever. They each have some different features and geographical coverage, but really, what matters is that you're even using one at all. CDNs are free speed boosts for connecting to your site - they allow the client to negotiate SSL and create a connection to a server somewhat close to them, not to your probably-far-away origin server in northern Virginia.

For US apps serving US customers, the gains are nice - 50 milliseconds here and there. But for those serving global traffic, it's absolutely critical. CDNs shave hundreds of milliseconds of latency off connections.

They're so easy to set up and nowadays quite cheap as well. It's free speed - take it.
 

Javascript cannot block page rendering


If you want a fast initial page load, there is simply no way to do it if the client has to first download and execute Javascript. This wasn't possible in 2011, when this first become popular, and it still isn't possible over ten years later, so don't count on things changing much more in the future. The speed of light hasn't gotten any faster, and as CPUs have gotten faster, JS developers have found plenty of ways to shove more and more code down the wire in glorious fulfillment of Wirth's Law.

What's a performance-minded application to do? Ship as much JS as you want, just don't let it block rendering. This means that all script tags must either be inline or have the async attribute attached.
It also means you have to ship actual HTML markup down the wire on initial page load.

JS developers pulled an excellent hoodwink in the mid-2010s convincing everyone that we could ship empty body tags to browsers and it would be Fast Enough, but it wasn't then and it still isn't in 2023. Server-side-rendering is a must. It doesn't really matter if you do it traditionally with Rails or if you use (in my opinion) a Rube Goldberg-ian setup to SSR your React application.

The fact is that web browsers can't display markup that doesn't exist - so if you're not shipping them any markup in the initial document, they have to wait until Javascript code downloads and executes. It's slower by definition.
 

Use a SPA or Hotwire/Turbo/HTMX


That's not to say Javascript is bad or in all cases to be avoided. Using traditional navigations on every click of your site is still much slower than the alternative. Using Javascript to swap out parts of the existing DOM is simply much faster than throwing away an entire Javascript VM and starting from scratch every time you click an anchor tag - usually 50% faster or more.

It doesn't matter if you choose to use a single-page application framework like React or use a Rails framework like Hotwire or even to use another ecosystem's less-JS alternative framework like HTMX. They all perform the same, so I leave the rest of the decision up to you.
 

75th percentile of LCP must be less than 2.5 seconds, and 75th percentile "route change" times should be less than 1 second.


When I say "route change" here, I mean any SPA-like navigation that changes the URL of the browser.
Set two automated alerts, or set a calendar reminder to check these two numbers once per week. These are the two metrics that really matter. Everything else is secondary, or is already covered by these metrics.

Server response time? Included already in both. JS execution time? A component of both. Everything in the performance experience is covered by these two numbers (except interactions which don't cause URLs to change - you have to instrument those separately).

The 2.5 second threshold for Largest Contentful Paint is Google's threshold for Core Web Vitals as well. I think it's a good metric and a good threshold, and meeting it has the bonus of ranking you higher in Google Search results. Great! 1 second route change times are what I've seen in my experience as being quite possible to achieve easily with SPA-like navigation, and 1 second is a nice threshold of human-computer interaction where we barely even notice the lag, and our minds stay on task.

So, those are my 5 performance rules. What do you think? Are there any I missed, or that you would add? Are you going to put these up on a poster in your office? Add a new dashboard or two to the wall? I hope they were useful.

-Nate
 
You can share this email with this permalink: https://mailchi.mp/railsspeed/5-performance-rules-for-fast-web-applications?e=[UNIQID]

Copyright © 2023 Nate Berkopec, All rights reserved.


Want to change how you receive these emails?
You can update your preferences or unsubscribe from this list.