David Larlet 3 лет назад
Родитель
Сommit
66734fb386

+ 451
- 0
cache/2021/45af171610f986077420b27c2da46ec1/index.html Просмотреть файл

@@ -0,0 +1,451 @@
<!doctype html><!-- This is a valid HTML5 document. -->
<!-- Screen readers, SEO, extensions and so on. -->
<html lang="fr">
<!-- Has to be within the first 1024 bytes, hence before the <title>
See: https://www.w3.org/TR/2012/CR-html5-20121217/document-metadata.html#charset -->
<meta charset="utf-8">
<!-- Why no `X-UA-Compatible` meta: https://stackoverflow.com/a/6771584 -->
<!-- The viewport meta is quite crowded and we are responsible for that.
See: https://codepen.io/tigt/post/meta-viewport-for-2015 -->
<meta name="viewport" content="width=device-width,initial-scale=1">
<!-- Required to make a valid HTML5 document. -->
<title>I bought 300 emoji domain names from Kazakhstan and built an email service (archive) — David Larlet</title>
<meta name="description" content="Publication mise en cache pour en conserver une trace.">
<!-- That good ol' feed, subscribe :). -->
<link rel="alternate" type="application/atom+xml" title="Feed" href="/david/log/">
<!-- Generated from https://realfavicongenerator.net/ such a mess. -->
<link rel="apple-touch-icon" sizes="180x180" href="/static/david/icons2/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/static/david/icons2/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/static/david/icons2/favicon-16x16.png">
<link rel="manifest" href="/static/david/icons2/site.webmanifest">
<link rel="mask-icon" href="/static/david/icons2/safari-pinned-tab.svg" color="#07486c">
<link rel="shortcut icon" href="/static/david/icons2/favicon.ico">
<meta name="msapplication-TileColor" content="#f0f0ea">
<meta name="msapplication-config" content="/static/david/icons2/browserconfig.xml">
<meta name="theme-color" content="#f0f0ea">
<!-- Documented, feel free to shoot an email. -->
<link rel="stylesheet" href="/static/david/css/style_2021-01-20.css">
<!-- See https://www.zachleat.com/web/comprehensive-webfonts/ for the trade-off. -->
<link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
<link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
<link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
<link rel="preload" href="/static/david/css/fonts/triplicate_t3_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
<link rel="preload" href="/static/david/css/fonts/triplicate_t3_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
<link rel="preload" href="/static/david/css/fonts/triplicate_t3_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
<script>
function toggleTheme(themeName) {
document.documentElement.classList.toggle(
'forced-dark',
themeName === 'dark'
)
document.documentElement.classList.toggle(
'forced-light',
themeName === 'light'
)
}
const selectedTheme = localStorage.getItem('theme')
if (selectedTheme !== 'undefined') {
toggleTheme(selectedTheme)
}
</script>

<meta name="robots" content="noindex, nofollow">
<meta content="origin-when-cross-origin" name="referrer">
<!-- Canonical URL for SEO purposes -->
<link rel="canonical" href="https://tinyprojects.dev/projects/mailoji">

<body class="remarkdown h1-underline h2-underline h3-underline em-underscore hr-center ul-star pre-tick">

<article>
<header>
<h1>I bought 300 emoji domain names from Kazakhstan and built an email service</h1>
</header>
<nav>
<p class="center">
<a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
<use xlink:href="/static/david/icons2/symbol-defs.svg#icon-home"></use>
</svg> Accueil</a> •
<a href="https://tinyprojects.dev/projects/mailoji" title="Lien vers le contenu original">Source originale</a>
</p>
</nav>
<hr>
<p>TLDR; I bought 300 emoji domain names from Kazakhstan and built an <a href="https://mailoji.com" target="_blank">emoji email address service</a>. In the process I went viral on TikTok, made $1000 in a week, hired a Japanese voice actor, and learnt about the weird world of emoji domains.</p>

<h3>🌅 The setup</h3>

<p>Not long ago I decided it would be a brilliant idea to buy the domain name <a href="/posts/i_bought_netflix_dot_soy" target="_blank">netflix.soy</a>.</p>

<p>Whilst arguably there are better ways to spend £17, I did learn a lot about domain names, including that it's possible to have emoji domains like <span class="domain">😊.ws</span>.</p>

<p>It's pretty hard to go a day without seeing an emoji somewhere on the internet. Yet, I'd never seen an emoji domain name before.</p>

<p>I wondered:</p>

<p>Could I buy an emoji domain name?</p>

<h3>💸 Buying an emoji domain name</h3>

<p>My goal was to buy a single character emoji domain name, like 💡 or 🍰. I didn't know what I'd do with it, I just wanted to see if I could get one.</p>

<p>I found a website that showed every available emoji domain for 4 different extensions.</p>

<p>Sadly, nearly every single one had been registered. I was late to the party.</p>

<p><img src="https://i.gyazo.com/6aa39e2f0e8e2f9039b61c95ea360cb7.png" alt="Taken emoji domains"></p>
<p>A simple mailbox emoji with a .ws extension was still available though, so I bought it.</p>

<h3>📪 The mailbox</h3>

<p><img src="https://i.gyazo.com/1b78a0aab3ca0b04649eacf46fd3bc0a.png" alt="Mailbox emoji domain in GoDaddy"></p>
<p><span class="domain">📪.ws</span> was now mine. Mission complete.</p>

<p>I set up a website and felt rather accomplished with my tiny mailbox.</p>

<p>I could've stopped there and called it a day. But, then I had another thought:</p>

<p>Could I use my little mailbox emoji domain in an email address?</p>

<p>That'd be pretty cute.</p>

<h3>✉️ Emoji mail attempt #1</h3>

<p>I gave it a go. I setup an email forwarder to route all email sent to <span class="domain">📪.ws</span> to my regular email address.</p>

<p>Eagerly I typed <span class="domain">ben@📪.ws</span> into the "to" field of gmail and hit send.</p>

<p><img src="https://i.gyazo.com/3ab67d13bcfad786b7f3ba9a01968272.png" alt="Sending first emoji mail"></p>
<h3>🛑 Blocked</h3>

<p>The email never hit my inbox. It was lost forever in cyberspace.</p>

<p>Turns out emoji domain names score very highly for spam and were going to be blocked to high heaven.</p>

<p>But, it was interesting that I could send mail towards an emoji email address.</p>

<p>So I wondered:</p>

<p>If a normal .com email address doesn't get blocked for spam, could I route my emoji mail through that?</p>

<h3>💌 Emoji mail attempt #2</h3>

<p>It would work like this: </p>

<ol>
<li>Email sent to <span class="domain">ben@📪.ws</span></li>
<li><span class="domain">ben@📪.ws</span> forwards to <span class="domain">nospam@normal.com</span></li>
<li><span class="domain">nospam@normal.com</span> forwards to my email address and won't get blocked.</li>
</ol>

<p>I cobbled together something using AWS, and tried my experiment again.</p>

<p>
</p>

<p>to: <span class="domain">ben@📪.ws</span></p>

<pre><code>&lt;p&gt;message: Hi Ben, how's it going?&lt;/p&gt;
</code></pre>
<p>Send.</p>

<p><img src="https://i.gyazo.com/bdc529a214b0e2019a96a86c933c4bcb.png" alt="First emoji mail"></p>
<p>It worked!</p>

<h3>🧨 Where things started to get out of control</h3>

<p>At this point I was inclined to stop and write a post about emoji email addresses. I'd had a good run.</p>

<p>But then I wondered:</p>

<p>My mailbox emoji email address is great and all, but do you know what would be better? <span class="domain">ben@⭐</span></p>

<p>Now how do I get one of those?</p>

<h3>🎣 Emoji domain name hunting</h3>

<p>Only 13 TLDs in the world accept registrations of emoji domain names: .cf, .ga, .gq, .la, .ml, .tk, .st, .fm, .to, .je, .gg, .kz, and .ws.</p>

<p>The website I had used to purchase <span class="domain">📪.ws</span> only showed 4 TLDs: .fm, .ws, .to and .ml. These are considered the gold standard of emoji domain name registrars.</p>

<p>Every emoji had been taken on these though. You could of course get multi-character emoji domains like <span class="domain">🎉🐢.ws</span>, but I wanted single character emoji domains only.</p>

<p>So I wondered:</p>

<p>Do any of those other TLDs have any emoji domains left?</p>

<h3>🔭 The great hunt</h3>

<p>I already had some code that performed WHOIS lookups to see if a domain name is available for a list of TLDs.</p>

<p>Previously I'd used this code to buy <a href="/posts/i_bought_netflix_dot_soy" target="_blank">facebook.网站</a>, only for Marky Z to snatch it back from me. Cheeky bugger.</p>

<p>I booted up the code and loaded in some A-tier emojis (e.g. ⭐,😂,❤️) and the 13 TLDs that accepted them.</p>

<p><i>&gt;node search.js</i> [ENTER]</p>

<h3>🎁 The results</h3>

<p><img src="https://i.gyazo.com/6adaeb53f45f75605749f78d4dcac8c3.png" alt="Console output showing available TLDs for emoji domains"></p>
<p>Instantly I was seeing results! .la, .ga, .gq, .je. There were plenty of emojis still out there on these alternative extensions.</p>

<p>An extension that stood out to me straight away was .gg, for the Island of Guernsey. "GG" is an acronym for "Good Game", and I say it often when I lose at online games. It was perfect.</p>

<p><span class="domain">⭐.gg</span> was available for €29. I hit purchase.</p>

<h3>💔 No GG for me</h3>

<p>The next day Guernsey sent me an email.</p>

<p><img src="https://i.gyazo.com/527c4941fbb3ddcffbc92a0c2ef1c828.png" alt="Email from Guernsey saying emoji domains not available on .gg"></p>
<p>Long story short, although you could register emoji domain names with them, they didn't actually work.</p>

<p>Good game Guernsey. Back to the drawing board.</p>

<h3>⭐ Crazy for KZ</h3>

<p>With every other extension I kept hitting walls. A lot of the registrars wouldn't even let me search for emoji domains. Nothing was working.</p>

<p>One extension that kept cropping up was .kz of Kazakhstan. But, I headed over to their registar website and it was entirely in Russian.</p>

<p><img src="https://i.gyazo.com/6c20c8eea912beb320555c0dace78b1b.png" alt="Russian domain name website"></p>
<p>I do not speak Russian.</p>

<p>Using Google Translate, I tried to navigate the website and buy a .kz emoji domain.</p>

<p>It was a long, painful process. But, after phoning my bank to confirm I was indeed trying to make a purchase using Kazakhstani tenge, <span class="domain">⭐.kz</span> was sitting in my account.</p>

<p>I plugged it into my email system and <span class="domain">ben@⭐.kz</span> worked.</p>

<p>Very nice.</p>

<h3>💼 Let's start an email service</h3>

<p>Something excited me. Nearly all single character emojis were available on .kz, and they were only $8 each.</p>

<p>So, I wondered:</p>

<p>What if you could get an email address with any emoji you wanted?</p>

<p>I pictured email addresses like <span class="domain">bob@🚀</span>, <span class="domain">alice@🌸</span>, <span class="domain">melvin@🍆</span>.</p>

<p>All I'd need to do is buy every emoji domain to build a service like this.</p>

<p>It was insane, but it was possible.</p>

<h3>🌙 The night of 150 emojis</h3>

<p>I decided I was going to do it.</p>

<p>If I was chuffed with my mailbox emoji email address, perhaps others would be too.</p>

<p>I got out my debit card, and, one by one, started buying Kazakhstan emoji domains.</p>

<p><span class="domain">💡.kz</span>, <span class="domain">👑.kz</span>, <span class="domain">🌈.kz</span>, <span class="domain">😎.kz</span>. Buy, buy, buy, buy.</p>

<p>It was slightly painful watching my bank account going down, and the number of emoji domains go up.</p>

<p>80 emojis in, forking over money for a goat emoji domain name, you seriously start to question what you're doing.</p>

<p>$1200 later, 150 emoji domains were mine.</p>

<h3>💻 Building an emoji email address website</h3>

<p>Finally, I needed a website where you could register an emoji email address and it would forward mail like <span class="domain">ben@📪.ws</span> did.</p>

<p>Using vanilla HTML, JS and CSS, plus Stripe's API for payments, I cobbled together an MVP over a few weeks.</p>

<p>Once it was done, I bought one last domain name: <a href="https://mailoji.com" target="_blank">mailoji.com</a>. My new emoji email address service <a href="https://mailoji.com" target="_blank">Mailoji</a> was ready. Get your emoji email addresses.</p>

<p><img src="https://i.gyazo.com/30c54b0bed4ffc85cb38940a2b26748e.png" alt="Mailoji emoji email address website"></p>
<h3>📱 TikTok</h3>

<p>I'd gone from being curious about emoji domain names to now owning 150 of Kazakhstan's finest.</p>

<p>The next step was to convince someone else to buy an emoji email address.</p>

<p>TikTok seemed like a good place to start given its demographic. So, I recorded a short video advert and started a "TikTok for business" application to publish it.</p>

<p>On the final page of the application I was asked for a VAT registration number. Mailoji was not a proper business yet, so there was no way I could publish my ad.</p>

<p>Screw it, I'll post the video normally.</p>

<p>Upload.</p>

<h3>🎉 First sales</h3>

<p>Here is the <a href="https://www.tiktok.com/@mailoji/video/6925405275201539334?lang=en&amp;is_copy_url=1&amp;is_from_webapp=v3" target="_blank">advert</a> if you're interested.</p>

<p>The video sat at 0 views for about 5 hours before the TikTok algorithm started to work its magic.</p>

<p>Slowly, the views started ramping up. 500 views, to 5k views, to 50k views. It was incredible to witness.</p>

<p>People were loving emoji email addresses, people were hating emoji email addresses.</p>

<p>It was like Marmite, a talking point. None of it mattered though because emoji email addresses were selling! <span class="domain">@🚀</span>, <span class="domain">@📷</span> &amp; <span class="domain">@💻</span> addresses were the most popular.</p>

<p>Over 2 days the TikTok video reached 200k+ views, and 60 emoji email addresses had been sold netting ~$300/yr in revenue.</p>

<p><img src="https://i.gyazo.com/e33fb288704cc42f58e50ff4a5d33fa8.png" alt="Stripe graph showing first sales from selling emoji domains"></p>
<p>I took this as a fantastic indicator. So guess what I did?</p>

<h3>💵 Buying more emoji domain names</h3>

<p>I decided to purchase 100 more emoji domains.</p>

<p>I cried into my keyboard forking out yet more money for a llama emoji that I probably didn't need.</p>

<p>In the end I had 250 emoji domains. If there was ever a moat into the emoji email address world, this was it.</p>

<h3>📅 Preparing for launch</h3>

<p>I figured the more people with emoji email addresses, the more people who would see them, and the more people who would buy them. A beautiful cycle.</p>

<p>My next goal was a Product Hunt launch to get exposure for Mailoji, and kickstart this cycle.</p>

<p>I prepped my launch post, carefully choosing each word and image.</p>

<p>I even created this over-hyped promotional video, complete with Japanese voice actor saying the words "Mailoji".</p>

<p class="video-container">
<iframe src="https://www.youtube.com/embed/JKxEXZv4G3c" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen>VIDEO</iframe></p>

<p>Mailoji was ready for launch.</p>

<h3>🚀 Launch Day</h3>

<p>At 12:03 AM PST Mailoji went live on <a href="https://www.producthunt.com/posts/mailoji" target="_blank">Product Hunt</a>. We had come a long way from that little mailbox emoji.</p>

<p><img src="https://i.gyazo.com/0cf1d62b2d820c8f456a95da3cffda01.png" alt="Product hunt launch thumbnail"></p>
<p>It was 8:03 AM UK time. Bleary eyed, with a cup of tea in hand, I watched as Mailoji did battle.</p>

<p>I had chosen to launch on a Wednesday against some stiff competition, but Mailoji really held its own.</p>

<p>At the end of the day it finished in 5th place. Here were the end of day stats: </p>

<ul>
<li>🌎 6.7k website views
</li><li>💌 150+ emoji email addresses sold</li>
<li>💵 $830/yr ARR</li>
<li>🔺 320 upvotes</li>
<li>🏅 5th place on Product Hunt</li>
<li>🎀 Most popular Mailoji: @🚀</li>
</ul>

<p>Over 150 emoji email addresses were sold in a day, and I received some fantastic feedback from the Product Hunt community.</p>

<p>It was done, Mailoji had officially launched.</p>

<h3>📙 The aftermath</h3>

<p>I wish this story ended with Mailoji blowing up and the queen registering an emoji email address or something (I'll reserve <span class="domain">Liz@👑.kz</span> just in case).</p>

<p>But, currently Mailoji is sitting at ~$1440/year in revenue. There's now 300 emoji domains to choose from though.</p>

<p><img src="https://i.gyazo.com/6eac0eb3bcdaa1ee78e57b6692ed9afc.png" alt="Final Stripe ARR chart for Mailoji"></p>
<p>Even though I still haven't made the money back on all the emoji domains I bought, creating an emoji email address service was so much fun.</p>

<p>It was an adventure. A rabbit hole containing multiple rabbit holes.</p>

<p>This project started out as an exploration into emoji domain names; a weird, forgotten about internet feature that I've now become quite fond of.</p>

<p>Yes emoji domains are hard to type on desktop, yes there's too many variations, and yes, most form validations hate them.</p>

<p>But they're fun, and I think tech should be more fun.</p>

<p>Thanks for reading. If you want to get in touch, I've got a brand new email address at the bottom of this website.</p>
</article>


<hr>

<footer>
<p>
<a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
<use xlink:href="/static/david/icons2/symbol-defs.svg#icon-home"></use>
</svg> Accueil</a> •
<a href="/david/log/" title="Accès au flux RSS"><svg class="icon icon-rss2">
<use xlink:href="/static/david/icons2/symbol-defs.svg#icon-rss2"></use>
</svg> RSS</a> •
<a href="http://larlet.com" title="Go to my English profile" data-instant><svg class="icon icon-user-tie">
<use xlink:href="/static/david/icons2/symbol-defs.svg#icon-user-tie"></use>
</svg> Pro</a> •
<a href="mailto:david%40larlet.fr" title="Envoyer un courriel"><svg class="icon icon-mail">
<use xlink:href="/static/david/icons2/symbol-defs.svg#icon-mail"></use>
</svg> Email</a> •
<abbr class="nowrap" title="Hébergeur : Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33184162340"><svg class="icon icon-hammer2">
<use xlink:href="/static/david/icons2/symbol-defs.svg#icon-hammer2"></use>
</svg> Légal</abbr>
</p>
<template id="theme-selector">
<form>
<fieldset>
<legend><svg class="icon icon-brightness-contrast">
<use xlink:href="/static/david/icons2/symbol-defs.svg#icon-brightness-contrast"></use>
</svg> Thème</legend>
<label>
<input type="radio" value="auto" name="chosen-color-scheme" checked> Auto
</label>
<label>
<input type="radio" value="dark" name="chosen-color-scheme"> Foncé
</label>
<label>
<input type="radio" value="light" name="chosen-color-scheme"> Clair
</label>
</fieldset>
</form>
</template>
</footer>
<script>
function loadThemeForm(templateName) {
const themeSelectorTemplate = document.querySelector(templateName)
const form = themeSelectorTemplate.content.firstElementChild
themeSelectorTemplate.replaceWith(form)

form.addEventListener('change', (e) => {
const chosenColorScheme = e.target.value
localStorage.setItem('theme', chosenColorScheme)
toggleTheme(chosenColorScheme)
})

const selectedTheme = localStorage.getItem('theme')
if (selectedTheme && selectedTheme !== 'undefined') {
form.querySelector(`[value="${selectedTheme}"]`).checked = true
}
}

const prefersColorSchemeDark = '(prefers-color-scheme: dark)'
window.addEventListener('load', () => {
let hasDarkRules = false
for (const styleSheet of Array.from(document.styleSheets)) {
let mediaRules = []
for (const cssRule of styleSheet.cssRules) {
if (cssRule.type !== CSSRule.MEDIA_RULE) {
continue
}
// WARNING: Safari does not have/supports `conditionText`.
if (cssRule.conditionText) {
if (cssRule.conditionText !== prefersColorSchemeDark) {
continue
}
} else {
if (cssRule.cssText.startsWith(prefersColorSchemeDark)) {
continue
}
}
mediaRules = mediaRules.concat(Array.from(cssRule.cssRules))
}

// WARNING: do not try to insert a Rule to a styleSheet you are
// currently iterating on, otherwise the browser will be stuck
// in a infinite loop…
for (const mediaRule of mediaRules) {
styleSheet.insertRule(mediaRule.cssText)
hasDarkRules = true
}
}
if (hasDarkRules) {
loadThemeForm('#theme-selector')
}
})
</script>
</body>
</html>

+ 296
- 0
cache/2021/45af171610f986077420b27c2da46ec1/index.md Просмотреть файл

@@ -0,0 +1,296 @@
title: I bought 300 emoji domain names from Kazakhstan and built an email service
url: https://tinyprojects.dev/projects/mailoji
hash_url: 45af171610f986077420b27c2da46ec1
<p>TLDR; I bought 300 emoji domain names from Kazakhstan and built an <a href="https://mailoji.com" target="_blank">emoji email address service</a>. In the process I went viral on TikTok, made $1000 in a week, hired a Japanese voice actor, and learnt about the weird world of emoji domains.</p>
<h3>🌅 The setup</h3>
<p>Not long ago I decided it would be a brilliant idea to buy the domain name <a href="/posts/i_bought_netflix_dot_soy" target="_blank">netflix.soy</a>.</p>
<p>Whilst arguably there are better ways to spend £17, I did learn a lot about domain names, including that it's possible to have emoji domains like <span class="domain">😊.ws</span>.</p>
<p>It's pretty hard to go a day without seeing an emoji somewhere on the internet. Yet, I'd never seen an emoji domain name before.</p>
<p>I wondered:</p>
<p>Could I buy an emoji domain name?</p>
<h3>💸 Buying an emoji domain name</h3>
<p>My goal was to buy a single character emoji domain name, like 💡 or 🍰. I didn't know what I'd do with it, I just wanted to see if I could get one.</p>
<p>I found a website that showed every available emoji domain for 4 different extensions.</p>
<p>Sadly, nearly every single one had been registered. I was late to the party.</p>
<img src="https://i.gyazo.com/6aa39e2f0e8e2f9039b61c95ea360cb7.png" alt="Taken emoji domains">
<p>A simple mailbox emoji with a .ws extension was still available though, so I bought it.</p>
<h3>📪 The mailbox</h3>
<img src="https://i.gyazo.com/1b78a0aab3ca0b04649eacf46fd3bc0a.png" alt="Mailbox emoji domain in GoDaddy">
<p><span class="domain">📪.ws</span> was now mine. Mission complete.</p>
<p>I set up a website and felt rather accomplished with my tiny mailbox.</p>
<p>I could've stopped there and called it a day. But, then I had another thought:</p>
<p>Could I use my little mailbox emoji domain in an email address?</p>
<p>That'd be pretty cute.</p>
<h3>✉️ Emoji mail attempt #1</h3>
<p>I gave it a go. I setup an email forwarder to route all email sent to <span class="domain">📪.ws</span> to my regular email address.</p>
<p>Eagerly I typed <span class="domain">ben@📪.ws</span> into the "to" field of gmail and hit send.</p>
<img src="https://i.gyazo.com/3ab67d13bcfad786b7f3ba9a01968272.png" alt="Sending first emoji mail">
<h3>🛑 Blocked</h3>
<p>The email never hit my inbox. It was lost forever in cyberspace.</p>
<p>Turns out emoji domain names score very highly for spam and were going to be blocked to high heaven.</p>
<p>But, it was interesting that I could send mail towards an emoji email address.</p>
<p>So I wondered:</p>
<p>If a normal .com email address doesn't get blocked for spam, could I route my emoji mail through that?</p>
<h3>💌 Emoji mail attempt #2</h3>
<p>It would work like this: </p>
<ol>
<li>Email sent to <span class="domain">ben@📪.ws</span></li>
<li><span class="domain">ben@📪.ws</span> forwards to <span class="domain">nospam@normal.com</span></li>
<li><span class="domain">nospam@normal.com</span> forwards to my email address and won't get blocked.</li>
</ol>
<p>I cobbled together something using AWS, and tried my experiment again.</p>
<p>
</p><p>to: <span class="domain">ben@📪.ws</span></p>
<p>message: Hi Ben, how's it going?</p>
<p>Send.</p>
<img src="https://i.gyazo.com/bdc529a214b0e2019a96a86c933c4bcb.png" alt="First emoji mail">
<p>It worked!</p>
<h3>🧨 Where things started to get out of control</h3>
<p>At this point I was inclined to stop and write a post about emoji email addresses. I'd had a good run.</p>
<p>But then I wondered:</p>
<p>My mailbox emoji email address is great and all, but do you know what would be better? <span class="domain">ben@⭐</span></p>
<p>Now how do I get one of those?</p>
<h3>🎣 Emoji domain name hunting</h3>
<p>Only 13 TLDs in the world accept registrations of emoji domain names: .cf, .ga, .gq, .la, .ml, .tk, .st, .fm, .to, .je, .gg, .kz, and .ws.</p>
<p>The website I had used to purchase <span class="domain">📪.ws</span> only showed 4 TLDs: .fm, .ws, .to and .ml. These are considered the gold standard of emoji domain name registrars.</p>
<p>Every emoji had been taken on these though. You could of course get multi-character emoji domains like <span class="domain">🎉🐢.ws</span>, but I wanted single character emoji domains only.</p>
<p>So I wondered:</p>
<p>Do any of those other TLDs have any emoji domains left?</p>
<h3>🔭 The great hunt</h3>
<p>I already had some code that performed WHOIS lookups to see if a domain name is available for a list of TLDs.</p>
<p>Previously I'd used this code to buy <a href="/posts/i_bought_netflix_dot_soy" target="_blank">facebook.网站</a>, only for Marky Z to snatch it back from me. Cheeky bugger.</p>
<p>I booted up the code and loaded in some A-tier emojis (e.g. ⭐,😂,❤️) and the 13 TLDs that accepted them.</p>
<p><i>&gt;node search.js</i> [ENTER]</p>
<h3>🎁 The results</h3>
<img src="https://i.gyazo.com/6adaeb53f45f75605749f78d4dcac8c3.png" alt="Console output showing available TLDs for emoji domains">
<p>Instantly I was seeing results! .la, .ga, .gq, .je. There were plenty of emojis still out there on these alternative extensions.</p>
<p>An extension that stood out to me straight away was .gg, for the Island of Guernsey. "GG" is an acronym for "Good Game", and I say it often when I lose at online games. It was perfect.</p>
<p><span class="domain">⭐.gg</span> was available for €29. I hit purchase.</p>
<h3>💔 No GG for me</h3>
<p>The next day Guernsey sent me an email.</p>
<img src="https://i.gyazo.com/527c4941fbb3ddcffbc92a0c2ef1c828.png" alt="Email from Guernsey saying emoji domains not available on .gg">
<p>Long story short, although you could register emoji domain names with them, they didn't actually work.</p>
<p>Good game Guernsey. Back to the drawing board.</p>
<h3>⭐ Crazy for KZ</h3>
<p>With every other extension I kept hitting walls. A lot of the registrars wouldn't even let me search for emoji domains. Nothing was working.</p>
<p>One extension that kept cropping up was .kz of Kazakhstan. But, I headed over to their registar website and it was entirely in Russian.</p>
<img src="https://i.gyazo.com/6c20c8eea912beb320555c0dace78b1b.png" alt="Russian domain name website">
<p>I do not speak Russian.</p>
<p>Using Google Translate, I tried to navigate the website and buy a .kz emoji domain.</p>
<p>It was a long, painful process. But, after phoning my bank to confirm I was indeed trying to make a purchase using Kazakhstani tenge, <span class="domain">⭐.kz</span> was sitting in my account.</p>
<p>I plugged it into my email system and <span class="domain">ben@⭐.kz</span> worked.</p>
<p>Very nice.</p>
<h3>💼 Let's start an email service</h3>
<p>Something excited me. Nearly all single character emojis were available on .kz, and they were only $8 each.</p>
<p>So, I wondered:</p>
<p>What if you could get an email address with any emoji you wanted?</p>
<p>I pictured email addresses like <span class="domain">bob@🚀</span>, <span class="domain">alice@🌸</span>, <span class="domain">melvin@🍆</span>.</p>
<p>All I'd need to do is buy every emoji domain to build a service like this.</p>
<p>It was insane, but it was possible.</p>
<h3>🌙 The night of 150 emojis</h3>
<p>I decided I was going to do it.</p>
<p>If I was chuffed with my mailbox emoji email address, perhaps others would be too.</p>
<p>I got out my debit card, and, one by one, started buying Kazakhstan emoji domains.</p>
<p><span class="domain">💡.kz</span>, <span class="domain">👑.kz</span>, <span class="domain">🌈.kz</span>, <span class="domain">😎.kz</span>. Buy, buy, buy, buy.</p>
<p>It was slightly painful watching my bank account going down, and the number of emoji domains go up.</p>
<p>80 emojis in, forking over money for a goat emoji domain name, you seriously start to question what you're doing.</p>
<p>$1200 later, 150 emoji domains were mine.</p>
<h3>💻 Building an emoji email address website</h3>
<p>Finally, I needed a website where you could register an emoji email address and it would forward mail like <span class="domain">ben@📪.ws</span> did.</p>
<p>Using vanilla HTML, JS and CSS, plus Stripe's API for payments, I cobbled together an MVP over a few weeks.</p>
<p>Once it was done, I bought one last domain name: <a href="https://mailoji.com" target="_blank">mailoji.com</a>. My new emoji email address service <a href="https://mailoji.com" target="_blank">Mailoji</a> was ready. Get your emoji email addresses.</p>
<img src="https://i.gyazo.com/30c54b0bed4ffc85cb38940a2b26748e.png" alt="Mailoji emoji email address website">
<h3>📱 TikTok</h3>
<p>I'd gone from being curious about emoji domain names to now owning 150 of Kazakhstan's finest.</p>
<p>The next step was to convince someone else to buy an emoji email address.</p>
<p>TikTok seemed like a good place to start given its demographic. So, I recorded a short video advert and started a "TikTok for business" application to publish it.</p>
<p>On the final page of the application I was asked for a VAT registration number. Mailoji was not a proper business yet, so there was no way I could publish my ad.</p>
<p>Screw it, I'll post the video normally.</p>
<p>Upload.</p>
<h3>🎉 First sales</h3>
<p>Here is the <a href="https://www.tiktok.com/@mailoji/video/6925405275201539334?lang=en&amp;is_copy_url=1&amp;is_from_webapp=v3" target="_blank">advert</a> if you're interested.</p>
<p>The video sat at 0 views for about 5 hours before the TikTok algorithm started to work its magic.</p>
<p>Slowly, the views started ramping up. 500 views, to 5k views, to 50k views. It was incredible to witness.</p>
<p>People were loving emoji email addresses, people were hating emoji email addresses.</p>
<p>It was like Marmite, a talking point. None of it mattered though because emoji email addresses were selling! <span class="domain">@🚀</span>, <span class="domain">@📷</span> &amp; <span class="domain">@💻</span> addresses were the most popular.</p>
<p>Over 2 days the TikTok video reached 200k+ views, and 60 emoji email addresses had been sold netting ~$300/yr in revenue.</p>
<img src="https://i.gyazo.com/e33fb288704cc42f58e50ff4a5d33fa8.png" alt="Stripe graph showing first sales from selling emoji domains">
<p>I took this as a fantastic indicator. So guess what I did?</p>
<h3>💵 Buying more emoji domain names</h3>
<p>I decided to purchase 100 more emoji domains.</p>
<p>I cried into my keyboard forking out yet more money for a llama emoji that I probably didn't need.</p>
<p>In the end I had 250 emoji domains. If there was ever a moat into the emoji email address world, this was it.</p>
<h3>📅 Preparing for launch</h3>
<p>I figured the more people with emoji email addresses, the more people who would see them, and the more people who would buy them. A beautiful cycle.</p>
<p>My next goal was a Product Hunt launch to get exposure for Mailoji, and kickstart this cycle.</p>
<p>I prepped my launch post, carefully choosing each word and image.</p>
<p>I even created this over-hyped promotional video, complete with Japanese voice actor saying the words "Mailoji".</p>
<p class="video-container">
<iframe src="https://www.youtube.com/embed/JKxEXZv4G3c" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen>VIDEO</iframe></p>
<p>Mailoji was ready for launch.</p>
<h3>🚀 Launch Day</h3>
<p>At 12:03 AM PST Mailoji went live on <a href="https://www.producthunt.com/posts/mailoji" target="_blank">Product Hunt</a>. We had come a long way from that little mailbox emoji.</p>
<img src="https://i.gyazo.com/0cf1d62b2d820c8f456a95da3cffda01.png" alt="Product hunt launch thumbnail">
<p>It was 8:03 AM UK time. Bleary eyed, with a cup of tea in hand, I watched as Mailoji did battle.</p>
<p>I had chosen to launch on a Wednesday against some stiff competition, but Mailoji really held its own.</p>
<p>At the end of the day it finished in 5th place. Here were the end of day stats: </p>
<ul>
<li>🌎 6.7k website views
</li><li>💌 150+ emoji email addresses sold</li>
<li>💵 $830/yr ARR</li>
<li>🔺 320 upvotes</li>
<li>🏅 5th place on Product Hunt</li>
<li>🎀 Most popular Mailoji: @🚀</li>
</ul>
<p>Over 150 emoji email addresses were sold in a day, and I received some fantastic feedback from the Product Hunt community.</p>
<p>It was done, Mailoji had officially launched.</p>
<h3>📙 The aftermath</h3>
<p>I wish this story ended with Mailoji blowing up and the queen registering an emoji email address or something (I'll reserve <span class="domain">Liz@👑.kz</span> just in case).</p>
<p>But, currently Mailoji is sitting at ~$1440/year in revenue. There's now 300 emoji domains to choose from though.</p>
<img src="https://i.gyazo.com/6eac0eb3bcdaa1ee78e57b6692ed9afc.png" alt="Final Stripe ARR chart for Mailoji">
<p>Even though I still haven't made the money back on all the emoji domains I bought, creating an emoji email address service was so much fun.</p>
<p>It was an adventure. A rabbit hole containing multiple rabbit holes.</p>
<p>This project started out as an exploration into emoji domain names; a weird, forgotten about internet feature that I've now become quite fond of.</p>
<p>Yes emoji domains are hard to type on desktop, yes there's too many variations, and yes, most form validations hate them.</p>
<p>But they're fun, and I think tech should be more fun.</p>
<p>Thanks for reading. If you want to get in touch, I've got a brand new email address at the bottom of this website.</p>

+ 437
- 0
cache/2021/d3a653c926aa97707653300947b65ab5/index.html Просмотреть файл

@@ -0,0 +1,437 @@
<!doctype html><!-- This is a valid HTML5 document. -->
<!-- Screen readers, SEO, extensions and so on. -->
<html lang="fr">
<!-- Has to be within the first 1024 bytes, hence before the <title>
See: https://www.w3.org/TR/2012/CR-html5-20121217/document-metadata.html#charset -->
<meta charset="utf-8">
<!-- Why no `X-UA-Compatible` meta: https://stackoverflow.com/a/6771584 -->
<!-- The viewport meta is quite crowded and we are responsible for that.
See: https://codepen.io/tigt/post/meta-viewport-for-2015 -->
<meta name="viewport" content="width=device-width,initial-scale=1">
<!-- Required to make a valid HTML5 document. -->
<title>The Mobile Performance Inequality Gap, 2021 (archive) — David Larlet</title>
<meta name="description" content="Publication mise en cache pour en conserver une trace.">
<!-- That good ol' feed, subscribe :). -->
<link rel="alternate" type="application/atom+xml" title="Feed" href="/david/log/">
<!-- Generated from https://realfavicongenerator.net/ such a mess. -->
<link rel="apple-touch-icon" sizes="180x180" href="/static/david/icons2/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/static/david/icons2/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/static/david/icons2/favicon-16x16.png">
<link rel="manifest" href="/static/david/icons2/site.webmanifest">
<link rel="mask-icon" href="/static/david/icons2/safari-pinned-tab.svg" color="#07486c">
<link rel="shortcut icon" href="/static/david/icons2/favicon.ico">
<meta name="msapplication-TileColor" content="#f0f0ea">
<meta name="msapplication-config" content="/static/david/icons2/browserconfig.xml">
<meta name="theme-color" content="#f0f0ea">
<!-- Documented, feel free to shoot an email. -->
<link rel="stylesheet" href="/static/david/css/style_2021-01-20.css">
<!-- See https://www.zachleat.com/web/comprehensive-webfonts/ for the trade-off. -->
<link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
<link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
<link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
<link rel="preload" href="/static/david/css/fonts/triplicate_t3_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
<link rel="preload" href="/static/david/css/fonts/triplicate_t3_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
<link rel="preload" href="/static/david/css/fonts/triplicate_t3_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
<script>
function toggleTheme(themeName) {
document.documentElement.classList.toggle(
'forced-dark',
themeName === 'dark'
)
document.documentElement.classList.toggle(
'forced-light',
themeName === 'light'
)
}
const selectedTheme = localStorage.getItem('theme')
if (selectedTheme !== 'undefined') {
toggleTheme(selectedTheme)
}
</script>

<meta name="robots" content="noindex, nofollow">
<meta content="origin-when-cross-origin" name="referrer">
<!-- Canonical URL for SEO purposes -->
<link rel="canonical" href="https://infrequently.org/2021/03/the-performance-inequality-gap/">

<body class="remarkdown h1-underline h2-underline h3-underline em-underscore hr-center ul-star pre-tick">

<article>
<header>
<h1>The Mobile Performance Inequality Gap, 2021</h1>
</header>
<nav>
<p class="center">
<a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
<use xlink:href="/static/david/icons2/symbol-defs.svg#icon-home"></use>
</svg> Accueil</a> •
<a href="https://infrequently.org/2021/03/the-performance-inequality-gap/" title="Lien vers le contenu original">Source originale</a>
</p>
</nav>
<hr>
<p><em><strong>TL;DR:</strong> A lot has changed since 2017 when we last <a href="https://infrequently.org/2017/10/can-you-afford-it-real-world-web-performance-budgets/">estimated a global baseline resource per-page resource budget of 130-170KiB</a>. Thanks to progress in networks and browsers (but not devices), a <a href="17/perf_budget_calculator/calc.html">more generous global budget cap has emerged</a> for sites constructed the "modern" way. We can now afford <strong>~100KiB of HTML/CSS/fonts and ~300-350KiB of JS (gzipped)</strong>. This rule-of-thumb limit should hold for at least a year or two. As always, the devil's in the footnotes, but the top-line is unchanged: when we construct the digital world to the limits of the best devices, we build a less usable one for <a href="https://www.idc.com/promo/smartphone-market-share/os">80+% of the world's users</a>.</em></p>

<p>Way back in 2016, I <a href="https://www.youtube.com/watch?v=4bZvq3nodf4">tried to raise the alarm about the causes and effects of the terrible performance</a> for <a href="https://www.idc.com/promo/smartphone-market-share/vendor">most users</a> from sites using popular frontend tools. The negative effects were particularly pronounced in the fastest-growing device segment: low-end to mid-range Android phones.</p>

<p><lite-youtube videoid="4bZvq3nodf4" videotitle="Progressive Performance: Chrome Dev Summit 2016">
</lite-youtube></p>

<p>Bad individual experiences can colour expectations of the entire ecosystem. Your company's poor site performance can manifest as lower engagement, higher bounce rates, or a reduction in conversions. While this local story is important, it isn't the whole picture. If a large enough proportion of sites behave poorly, <a href="https://services.google.com/fh/files/blogs/google_delayexp.pdf">performance hysteresis</a> may colour user views of <em>all</em> web experiences.</p>

<p>Unless a site is launched from the home screen as a <a href="https://web.dev/progressive-web-apps/">PWA</a>, pages are co-mingled. Pages are experienced as a series of taps, flowing effortlessly across sites; a river of links. A bad experience in the flow is a bad experience <em>of the flow</em>, with constituent parts blending together.</p>

<p>If tapping links tends to feel bad...why keep tapping? It's not as though slow websites are the only way to access information. Plenty of native apps are happy to aggregate content and serve it up in a reliably fast package, given half a chance. The consistency of those walled gardens is a large part of what the mobile web is up against — and <a href="http://vimeo.com/364402896">losing to</a>.</p>

<p><lite-vimeo videoid="364402896" videotitle="Alex Russell - The Mobile Web: MIA">
<a href="http://vimeo.com/364402896">The Mobile Web: MIA</a>
</lite-vimeo></p>

<p>Poor performance of sites that link to and from yours negatively impacts engagement <em>on your site</em>, even if it is consistently snappy. Live by the link, die by the link.</p>

<p>The harmful business impact of poor performance is constantly re-validated. Big decreases in performance predictably lead to (somewhat lower) decreases in user engagement and conversion. The scale of the effect can be deeply situational or hard to suss out without solid metrics, but it's there.</p>

<p>Variance contributes another layer of concern; high variability in responsiveness may create effects that perceptually dominate averages, or even medians. If 9 taps in 10 respond in 100ms, but every 10th takes a full second, what happens to user confidence and engagement? These deep-wetware effects and their cross-origin implications mean that your site's success is, partially, a function of the health of the commons.</p>

<p>From this perspective, it's helpful to consider what it might take to set baselines that can help ensure minimum quality across link taps, so in 2017 I followed up with <a href="https://infrequently.org/2017/10/can-you-afford-it-real-world-web-performance-budgets/">a post sketching a rubric for thinking about a global baseline</a>.</p>

<p>The punchline:</p>

<blockquote>
<p>The default global baseline is a ~$200 Android device on a 400Kbps link with a 400ms round-trip-time ("RTT"). This translates into a budget of ~130-170KB of critical-path resources, depending on composition — the more JS you include, the smaller the bundle must be.</p>
</blockquote>

<p>A $200USD device at the time featured 4-8 (slow, in-order, low-cache) cores, ~2GiB of RAM, and pokey MLC NAND flash storage. The <a href="https://www.gsmarena.com/motorola_moto_g4-8103.php">Moto G4</a>, for example.</p>

<p>The 2017 baseline represented a conservative, but evidence-driven, interpretation of the best information I could get regarding network performance, along with trend lines regarding device shipment volumes and price points. Getting accurate global information that isn't artificially reduced to averages remains an ongoing challenge. Performance work often focuses on high percentile users (the slowest), after all.</p>

<p>Since then, the metrics conversation has moved forward significantly, culminating in <a href="https://web.dev/vitals/">Core Web Vitals</a>, reported via <a href="https://developers.google.com/web/tools/chrome-user-experience-report">the Chrome User Experience Report</a> to reflect the real-world experiences of users.</p>

<p>Devices and networks have evolved too:</p>

<p>Meanwhile, developer behaviour <a href="https://httparchive.org/reports/state-of-javascript">offers little hope:</a></p>

<figure>
<a href="https://httparchive.org/reports/state-of-javascript" alt="Median mobile JavaScript payloads have only grown since 2016, now hovering above 400KiB of script transferred, or nearly 2.5MiB of uncompressed JS.">
<picture>
<source sizes="(max-width: 1200px) 70vw, 400px" srcset="https://infrequently.org/2021/03/the-performance-inequality-gap/http_archive_median_js.png?nf_resize=fit&amp;w=2400 2400w,
/2021/03/the-performance-inequality-gap/http_archive_median_js.png?nf_resize=fit&amp;w=1600 1600w,
/2021/03/the-performance-inequality-gap/http_archive_median_js.png?nf_resize=fit&amp;w=1200 1200w,
/2021/03/the-performance-inequality-gap/http_archive_median_js.png?nf_resize=fit&amp;w=800 800w,
/2021/03/the-performance-inequality-gap/http_archive_median_js.png?nf_resize=fit&amp;w=600 600w,
/2021/03/the-performance-inequality-gap/http_archive_median_js.png?nf_resize=fit&amp;w=400 400w">
<img src="https://infrequently.org/2021/03/the-performance-inequality-gap/http_archive_median_js.png?nf_resize=fit&amp;w=400" alt="Median mobile JavaScript payloads have only grown since 2016, now hovering above 400KiB of script transferred, or nearly 2.5MiB of uncompressed JS." decoding="async" loading="lazy">
</source></picture>

</a>
<figcaption>Median mobile JavaScript payloads have only grown since 2016, now hovering above 400KiB of script transferred, or nearly 2.5MiB of uncompressed JS.</figcaption>
</figure>

<p>A silver lining on this dark cloud is that mobile JavaScript payload growth paused in 2020. How soon will low-end and middle-tier phones be able to handle such chonky payloads? If the median site continued to send 3x the recommended amount of script, when would the web start to feel usable on most of the world's devices?</p>

<p>Here begins our 2021 adventure.</p>

<h2 id="hard-reset">Hard Reset</h2>

<p>To update our global baseline from 2017, we want to update our priors on a few dimensions:</p>

<ul>
<li>The evolved device landscape</li>
<li>Modern network performance and availability</li>
<li>Advances in browser content processing</li>
</ul>

<h3 id="king-content">Content Is Dead, Long Live Content</h3>

<p>Good news has consistently come from the steady pace of browser progress. The single largest improvements visible in traces come from <a href="https://v8.dev/blog/scanner">improved</a> <a href="https://v8.dev/blog/preparser">parsing</a> and <a href="https://v8.dev/blog/background-compilation">off-thread compilation of JavaScript</a>. This step-change, along with <a href="https://v8.dev/blog/v8-release-75#script-streaming-directly-from-network">improvements to streaming compilation</a>, has helped to ensure that users are less likely to notice the unreasonably-sized JS payloads that "modern" toolchains generate more often than not. Better use of more cores (moving compilation off-thread) has given sites that provide HTML and CSS content a fighting chance of remaining responsive, even when saddled with staggering JS burdens.</p>

<p>A <a href="https://v8.dev/blog/adaptor-frame">steady</a> <a href="https://v8.dev/blog/embedded-builtins">drumbeat</a> of <a href="https://v8.dev/blog/high-performance-es2015">improvements</a> have contributed to reduced runtime costs, too, though I fear they most often create an <a href="https://en.wikipedia.org/wiki/Induced_demand">induced demand</a> effect.</p>

<p>The residual main-thread compilation, allocation, and script-driven DOM/Layout tasks pose a challenge for delivering a good user experinece. As we'll see below, CPUs are not improving fast enough to cope with frontend engineers' rosy resource assumptions. If there is unambiguously good news on the tooling front, multiple popular tools now include options to prevent sending first-party JS in the first place (<a href="https://chrisbrownie.dev/creating-a-completely-static-build-with-nextjs">Next.js</a>, <a href="https://www.gatsbyjs.com/plugins/gatsby-plugin-no-javascript/">Gatsby</a>), though the JS community remains in stubborn denial about the costs of client-side script. Hopefully, toolchain progress of this sort can provide a more accessible bridge as we transition costs to a reduced-script-emissions world.</p>

<h3 id="oh-em-gee">4G Is A Miracle, 5G Is A Mirage</h3>

<p>The 2017 baseline post included <a href="https://infrequently.org/17/perf_budget_calculator/index.html">a small model</a> for thinking about how to think about how various factors of a page's construction influence the likelihood of hitting a 5-second first load goal.</p>

<p>The hard floor of that model (~1.6s) came from the contributions DNS, TCP/IP, and TLS connection setup over a then-reasonable <a href="https://infrequently.org/2017/10/can-you-afford-it-real-world-web-performance-budgets/#content:~:text=On%20a%20slow%203G%20network%2C%20emulated,400Kbps%20transfer">3G network baseline</a>, leaving only 3400ms to work with, fighting Nagle and weak CPUs the whole way. Adding just one extra connection to a CDN for a critical path resource could sink the entire enterprise. Talk about a hard target.</p>

<p>Four years later, has anything changed? I'm happy to report that it has. Not as much as we'd like, of course, but the worldwide baseline has changed <em>enormously</em>. How? Why?</p>

<p><a href="https://www.kaiostech.com/reliance-jio-became-worlds-fastest-growing-mobile-network/">Reliance Jio, mostly</a>.</p>

<p>India has been the <a href="https://www.statista.com/statistics/283331/smartphone-shipments-worldwide/">epicentre of smartphone growth</a> in recent years, owing to the sheer size of its market and an <a href="https://www.outlookindia.com/newsscroll/india-feature-phone-market-declines-24-in-q1-2020/1814178">accelerating shift away from feature phones</a> which made up the majority of Indian mobile devices until as late as 2019. Continued projections of <a href="https://economictimes.indiatimes.com/tech/tech-bytes/indias-smartphone-market-is-set-for-double-digit-growth-in-2021/articleshow/80106597.cms">double-digit market growth for smartphones</a>, on top of a doubling of shipments in the past 5 years, paint a vivid picture.</p>

<p>Key to this growth is the <a href="https://www.wsj.com/articles/two-years-ago-india-lacked-fast-cheap-internetone-billionaire-changed-all-that-1536159916">effect of Reliance Jio's entry into the carrier market</a>. Before Jio's disruptive pricing and aggressive rollout, data services in India were among the most expensive in the world relative to income and heavily reliant on 3G outside wealthier "tier 1" cities. Worse, 3G service often performed like 2G in other markets, thanks to over-provisioning and data rate throttling by incumbent carriers.</p>

<p>In 2016, Jio swept over the subcontinent like a monsoon dropping a torrent of 4G infrastructure and free data rather than rain.</p>

<p>Competing carriers responded instantly, dropping prices aggressively, leading to <a href="https://www.business-standard.com/article/pti-stories/mobile-data-price-down-by-95-but-revenue-up-2-5-times-in-5-yrs-trai-119082101291_1.html">reductions in per-packet prices approaching 95%</a>.</p>

<p>Jio's blanket <a href="https://www.opensignal.com/reports/2017/04/india/state-of-the-mobile-network">4G rollout blitzkrieg</a> <a href="https://www.thehindu.com/data/data-where-indias-mobile-internet-speed-ranks-globally-which-operator-offers-the-fastest-download-speeds-and-more/article30800987.ece">shocked incumbents with a superior product at an unheard-of price</a>, forcing the entire market to improve data rates and coverage. India became a <a href="https://www.opensignal.com/reports/2020/09/india/mobile-network-experience">4G-centric market</a> sometime in 2018.</p>

<p>If there's a bright spot in our construction of a 2021 baseline for performance, this is it. We can finally <a href="https://www.opensignal.com/sites/opensignal-com/files/data/reports/pdf-only/data-2020-05/state_of_mobile_experience_may_2020_opensignal_3_0.pdf">upgrade our assumptions about the network to assume slow-ish 4G almost everywhere (pdf)</a>.</p>

<p>5G looks set to continue a <a href="https://www.opensignal.com/2021/02/03/benchmarking-the-global-5g-experience">bumpy rollout</a> for the next half-decade. Carriers make different frequency band choices in different geographies, and 5G performance is heavily sensitive to mast density, which will add confusion for years to come. Suffice to say, 5G isn't here yet, even if wealthy users in a few geographies come to think of it as "normal" far ahead of worldwide deployment.</p>

<h3 id="hardware-destiny">Hardware Past As Performance Prologue</h3>

<p>Whatever progress runtimes and networks have made in the past half-decade, browsers are stubbornly situated in the devices carried by real-world users, and the single most important thing to understand about the landscape of devices your sites will run on is that they are <em>not new phones</em>.</p>

<p>This makes some intuitive sense: smartphones are not in their first year (and haven't been for more than a dozen years), and most users do not replace their devices every year. Most smartphone sales today are replacements (that is, to users who have previously owned a smartphone), and the longevity of devices continues to rise.</p>

<p>The worldwide device replacement <em>average</em> is <a href="https://www.statista.com/statistics/786876/replacement-cycle-length-of-smartphones-worldwide/">now 33 months</a>. In markets near <a href="https://www.theverge.com/2019/1/3/18166399/iphone-android-apple-samsung-smartphone-sales-peak">smartphone saturation</a>, that means we can expect the median device to be nearly 18 months old. Newer devices continue to be faster for the same dollar spent. Assuming <a href="https://statinvestor.com/data/35666/smartphone-average-selling-price-worldwide/">average selling prices (ASPs) remaining in a narrow year-on-year band in most geographies</a>, a good way to think of the "average phone" as being <em>the average device sold 18 months ago</em>. ASPs, however, have started to rise, making <a href="https://infrequently.org/2017/10/can-you-afford-it-real-world-web-performance-budgets/">my prognostications from 2017</a> only <em>technically</em> correct:</p>

<blockquote>
<p>The true median device from 2016 sold at about ~$200 unlocked. This year's median device is even cheaper, but their performance is roughly equivalent. Expect continued performance stasis at the median for the next few years. This is part of the reason I suggested the Moto G4 last year and recommend it or the Moto G5 Plus this year.</p>
</blockquote>

<p>Median devices continue to be different from averages, but we can squint a little as we're abstracting over multi-year cohorts. The worldwide ASP <a href="https://statinvestor.com/data/35666/smartphone-average-selling-price-worldwide/">18 months ago was ~$300USD</a>, so the <em>average</em> performance in the deployed fleet can be represented by <a href="https://www.businessinsider.com/best-phones-under-300-apple-samsung-2019-8">a $300 device from mid-2019</a>. The <a href="https://en.wikipedia.org/wiki/Moto_G7">Moto G7</a> very much <a href="https://www.gsmarena.com/motorola_moto_g7-9357.php">looks the part</a>.</p>

<p>Compared to devices wealthy developers carry, the performance is <a href="https://nanoreview.net/en/soc-compare/qualcomm-snapdragon-632-vs-apple-a14-bionic">night and (blinding) day</a>. However shocking a 6x difference in single-thread CPU performance might be, it's nothing compared to where we <em>should</em> be setting the global baseline: the P75+ device. Using our little mental model for device age and replacement, we can naively estimate what the 75th percentile (or higher) device could be in terms of device price + age, either by tracking devices at half the ASP at half the replacement age, or by looking at ASP-priced devices 3/4 of the way through the replacement cycle. Today, either method returns a similar answer.</p>

<p>This is inexact for dozens of reasons, not least of all markets with lower ASPs not yet achieving smartphone saturation. Using a global ASP as a benchmark can further mislead thanks to the distorting effect of ultra-high-end prices rising while shipment volumes stagnate. It's hard to know which way these effects cut when combined, so we're going to make a further guess: we'll take half the average price and note how wrong this likely is.</p>

<p>So what did $150USD fetch in 2019?</p>

<p>Say hello to the <a href="https://www.cnet.com/news/motorolas-moto-e6-is-a-150-phone-that-feels-like-a-150-phone/">Moto E6</a>! <a href="https://www.gsmarena.com/motorola_moto_e6-9682.php">This 2GiB RAM, Android 9 stalwart</a> features the all-too classic lines of a Quad-core A53 (1.4GHz, small mercies) CPU, tastefully presented in a charming 5.5" package.</p>

<figure>
<a href="https://www.gsmarena.com/motorola_moto_e6-9682.php" alt="The smooth, dulcet tones of 2019's Moto E6.">
<picture>
<source sizes="(max-width: 1200px) 70vw, 400px" srcset="https://infrequently.org/2021/03/the-performance-inequality-gap/motorola-moto-e6-xt2005-navy-blue.jpg?nf_resize=fit&amp;w=2400 2400w,
/2021/03/the-performance-inequality-gap/motorola-moto-e6-xt2005-navy-blue.jpg?nf_resize=fit&amp;w=1600 1600w,
/2021/03/the-performance-inequality-gap/motorola-moto-e6-xt2005-navy-blue.jpg?nf_resize=fit&amp;w=1200 1200w,
/2021/03/the-performance-inequality-gap/motorola-moto-e6-xt2005-navy-blue.jpg?nf_resize=fit&amp;w=800 800w,
/2021/03/the-performance-inequality-gap/motorola-moto-e6-xt2005-navy-blue.jpg?nf_resize=fit&amp;w=600 600w,
/2021/03/the-performance-inequality-gap/motorola-moto-e6-xt2005-navy-blue.jpg?nf_resize=fit&amp;w=400 400w">
<img src="https://infrequently.org/2021/03/the-performance-inequality-gap/motorola-moto-e6-xt2005-navy-blue.jpg?nf_resize=fit&amp;w=400" alt="The smooth, dulcet tones of 2019's Moto E6." decoding="async" loading="lazy">
</source></picture>

</a>
<figcaption>The smooth, dulcet tones of 2019's Moto E6.</figcaption>
</figure>

<p>If those specs sound eerily familiar, it's perhaps because they're <a href="https://www.gsmarena.com/motorola_moto_g4-8103.php">identical</a> to 2016's <a href="https://www.cnet.com/reviews/motorola-moto-g4-review/">$200USD Moto G4</a>, all the way down to the <a href="https://en.wikichip.org/wiki/28_nm_lithography_process">2011-vintage 28nm SoC process node</a> used to fab the chip's <a href="https://en.wikipedia.org/wiki/ARM_Cortex-A53">anemic, 2012-vintage A53 cores</a>. There are differences, of course, but <a href="https://browser.geekbench.com/v5/cpu/compare/6839107?baseline=5281022">not where it counts</a>.</p>

<p>You might recall the Moto G4 as a baseline recommendation from 2016 for forward-looking performance work. It's also the model we sent several dozen of to <a href="https://twitter.com/patmeenan">Pat Meenan</a> — devices that power <a href="https://webpagetest.org/easy"><code>webpagetest.org/easy</code></a> to this day. There was no way to know that the already-ageing in-order, near-zero-cache A53 + too-hot-to-frequency-scale 28nm process duo would continue to haunt us five year on. Today's P75 devices tell the story of the yawning <em>Performance Inequality Gap</em>: performance for those at the top end continues to accelerate away from the have-nots who are perpetually stuck with 2014's hardware.</p>

<p>The good news is that chip progress has begun to move, if glacially, in the past couple of years. 28nm chips are being supplanted at the sub-$200USD price-point by 14nm and <a href="https://www.gsmarena.com/motorola_moto_g_play_(2021)-10673.php">even 11nm parts</a>. Specs are finally improving quickly at the bottom of the market now, with <a href="https://www.gsmarena.com/tecno_spark_6_debuts_with_68_display_helio_g70_chipset_-news-45483.php">new ~$135USD devices sporting CPUs that should give last year's mid-range a run for its money</a>.</p>

<h3 id="mind-the-gap">Mind The Gap</h3>

<p>Regardless, the overall story for hardware progress remains grim, particularly when we recall how long device replacement cycles are:</p>

<figure>
<a href="https://infrequently.org/2021/03/the-performance-inequality-gap/single_core_scores_large.png" alt="&lt;em&gt;Tap for a larger version.&lt;/em&gt;&lt;br&gt;Updated Geekbench 4 single-core scores for each mobile price-point.">
<picture>
<source sizes="(max-width: 1200px) 70vw, 400px" srcset="https://infrequently.org/2021/03/the-performance-inequality-gap/single_core_scores.png?nf_resize=fit&amp;w=2400 2400w,
/2021/03/the-performance-inequality-gap/single_core_scores.png?nf_resize=fit&amp;w=1600 1600w,
/2021/03/the-performance-inequality-gap/single_core_scores.png?nf_resize=fit&amp;w=1200 1200w,
/2021/03/the-performance-inequality-gap/single_core_scores.png?nf_resize=fit&amp;w=800 800w,
/2021/03/the-performance-inequality-gap/single_core_scores.png?nf_resize=fit&amp;w=600 600w,
/2021/03/the-performance-inequality-gap/single_core_scores.png?nf_resize=fit&amp;w=400 400w">
<img src="https://infrequently.org/2021/03/the-performance-inequality-gap/single_core_scores.png?nf_resize=fit&amp;w=400" alt="&lt;em&gt;Tap for a larger version.&lt;/em&gt;&lt;br&gt;Updated Geekbench 4 single-core scores for each mobile price-point." decoding="async" loading="lazy">
</source></picture>

</a>
<figcaption><em>Tap for a larger version.</em><br>Updated Geekbench 4 single-core scores for each mobile price-point.</figcaption>
</figure>

<p>Recall that single-core performance most directly translates into speed on the web. Android-ecosystem SoC performance is, in a word, disastrous.</p>

<p>How bad is it?</p>

<p>We can think about each category in terms of years behind contemporary iPhone releases:</p>

<ul>
<li>2020's high-end Androids sport the single-core performance of an iPhone 8, a phone released in Q3'17</li>
<li>mid-priced Androids were slightly faster than 2014's iPhone 6</li>
<li>low-end Androids have finally caught up to the iPhone 5 from 2012</li>
</ul>

<p>You're reading that right: single core Android performance at the low end is both shockingly bad and dispiritingly stagnant.</p>

<figure>
<a href="https://infrequently.org/2021/03/the-performance-inequality-gap/multi_core_scores_large.png" alt="&lt;em&gt;Tap for a larger version.&lt;/em&gt;&lt;br&gt;Android ecosystem SoC's fare slightly better on multi-core performance, but the Performance Inequality Gap is growing there, too.">
<picture>
<source sizes="(max-width: 1200px) 70vw, 400px" srcset="https://infrequently.org/2021/03/the-performance-inequality-gap/multi_core_scores.png?nf_resize=fit&amp;w=2400 2400w,
/2021/03/the-performance-inequality-gap/multi_core_scores.png?nf_resize=fit&amp;w=1600 1600w,
/2021/03/the-performance-inequality-gap/multi_core_scores.png?nf_resize=fit&amp;w=1200 1200w,
/2021/03/the-performance-inequality-gap/multi_core_scores.png?nf_resize=fit&amp;w=800 800w,
/2021/03/the-performance-inequality-gap/multi_core_scores.png?nf_resize=fit&amp;w=600 600w,
/2021/03/the-performance-inequality-gap/multi_core_scores.png?nf_resize=fit&amp;w=400 400w">
<img src="https://infrequently.org/2021/03/the-performance-inequality-gap/multi_core_scores.png?nf_resize=fit&amp;w=400" alt="&lt;em&gt;Tap for a larger version.&lt;/em&gt;&lt;br&gt;Android ecosystem SoC's fare slightly better on multi-core performance, but the Performance Inequality Gap is growing there, too." decoding="async" loading="lazy">
</source></picture>

</a>
<figcaption><em>Tap for a larger version.</em><br>Android ecosystem SoC's fare slightly better on multi-core performance, but the Performance Inequality Gap is growing there, too.</figcaption>
</figure>

<p>The multi-core performance shows the same basic story: iOS's high-end and the most expensive Androids are pulling away from the volume-shipment pack. The fastest Androids predictably remain 18-24 months behind, owing to cheapskate choices about cache sizing by Qualcomm, Samsung Semiconductor, MediaTek, and the rest. Don't pay a lot for an Android-shaped muffler.</p>

<p><a href="https://twitter.com/slightlylate/status/1370133443695190018">Chip design choices</a> and silicon economics are the defining feature of the still-growing <em>Performance Inequality Gap</em>.</p>

<p>Things continue to get better and better for the wealthy, leaving the rest behind. <strong>When we construct a digital world to the limits of the best devices, the worse an experience we build, on average, for those who cannot afford iPhones or $800 Samsung flagships.</strong></p>

<p>It is perhaps predictable that, instead of presenting a bulwark against stratification, technology outcomes have tracked society's growing inequality. A yawning chasm of disparities is playing out in our phones at the same time it has come to shape <a href="https://news.un.org/en/story/2020/01/1055681">our economic and political lives</a>. It's hard to escape thinking they're connected.</p>

<p>Developers, particularly in Silicon Valley firms, are definitionally wealthy and enfranchised by world-historical standards. Like upper classes of yore, comfort ("<a href="https://infrequently.org/2018/09/the-developer-experience-bait-and-switch/">DX</a>") comes with courtiers happy to declare how important comfort must surely be. It's bunk, or at least most of it is.</p>

<p>As frontenders, our task is to make services that work well for all, not just the wealthy. If improvements in our tools or our comfort <em>actually</em> deliver improvements in that direction, so much the better. But we must never forget that measurable improvement for <em>users</em> is the yardstick.</p>

<p>Instead of measurement, we seem to suffer a proliferation of postulates about how each new increment of comfort must <em>surely</em> result in better user experiences. But the postulates are not tied to robust evidence. Instead, experience teaches that it's the process of taking care to attend to those least-well-off that changes outcomes. Trickle-down user experience from developer-experience is, in 2021, as fully falsified as the <a href="https://www.washingtonpost.com/politics/2019/06/01/trump-is-giving-arthur-laffer-presidential-medal-freedom-economists-arent-laughing/">Laffer Curve</a>. There's no durable substitute for compassion.</p>

<h2 id="baseline-next">A 2021 Global Baseline</h2>

<p>It's in that spirit that I find it important to build to a strawperson baseline device and network target. Such a benchmark serves as a stand-in <em>until one gets situated data</em> about a site or service's users, from whom we can derive informed conclusions about user needs and appropriate resource budgets.</p>

<p>A global baseline is doubly important for generic frameworks and libraries, as they <em>will</em> be included in projects targeted at global-baseline users, whether or not developers have that in mind. Tools that cannot fit comfortably within, say, 10% of our baseline budget should be labelled as desktop-only or replaced in our toolchains. Many popular tools over the past 5 years have been blithely punctured these limits relative to the 2017 baseline, and the results have been predictably poor.</p>

<p>Given all the data we've slogged through, we can assemble a sketch of the browsers, devices, and networks today's P50 and P75 users will access sites from. Keep in mind that this baseline <em>might be too optimistic</em>, depending on your target market. Trust but verify.</p>

<p>OpenSignal's global report on connection speeds (<a href="https://www.opensignal.com/sites/opensignal-com/files/data/reports/pdf-only/data-2020-05/state_of_mobile_experience_may_2020_opensignal_3_0.pdf">pdf</a>) suggest that <a href="https://github.com/WPO-Foundation/webpagetest/blob/master/www/settings/connectivity.ini.sample#L48">WebPageTest's default 4G configuration (9Mbps w/ 170ms RTT)</a> is a reasonable stand-in for the P75 network link. WPT's <a href="https://github.com/WPO-Foundation/webpagetest/blob/master/www/settings/connectivity.ini.sample#L54">LTE configuration (12Mbps w/ 70ms RTT)</a> may actually be too conservative for a P50 estimate today; something closer to 25Mbps seems to approach the worldwide median today. Network progress has been astonishing, particularly channel capacity (bandwidth). Sadly, data on latency is harder to get, even from Google's perch, so progress there is somewhat more difficult to judge.</p>

<p>As for devices, the P75 situation remains dire and basically unchanged from the baseline I suggested more than five years ago. Slow A53 cores — a design <a href="https://en.wikipedia.org/wiki/ARM_Cortex-A53">first introduced nearly a decade ago</a> — continue to dominate the landscape, differing only slightly in frequency scaling (through improved process nodes) and GPU pairing. The good news is that this will change rapidly in the next few years. The median <em>new</em> device is already benefiting; modern designs and fab processes are powering a ramp-up in performance for a $300USD device, particularly in multi-core workloads. But the hardware future is not evenly distributed, and web workloads aren't heavily parallel.</p>

<p>Astonishingly, I believe this means that for at least the next year we should consider the venerable Moto G4 to still be our baseline. If you can't buy one new, the 2020-vintage <a href="https://www.gsmarena.com/motorola_moto_e6s_(2020)-10135.php">Moto E6</a> does a stirring rendition of the classic; it's <a href="https://browser.geekbench.com/v4/cpu/compare/15954576?baseline=15987586">basically the same phone, after all</a>. The <a href="https://www.gsmarena.com/motorola_moto_e7_plus-10436.php">Moto E7 Plus</a> is a <a href="https://browser.geekbench.com/v4/cpu/compare/15987586?baseline=15667410">preview of better days to come</a>, and they can't arrive soon enough.</p>

<p>Putting it all together, where does that leave us? Back-of-the napkin, and accepting our previous targets of 5 seconds for first load and two seconds for second load, what can we afford?</p>

<p>Plugging the new P75 numbers in, the impact of network improvements are dramatic. Initial connection setup times are cut in half, dropping from 1600ms to 700ms, which frees up significant headroom to transmit more data in the same time window. The channel capacity increase to 9Mbps is enough to transmit more than 4MiB (megabytes) of content over a single connection in our 5 second window (1 Byte == 8 bits, so 9Mbps is just over ~1MBps). Of course, if most of this content is JavaScript, it must be compiled and run, shrinking our content window back down significantly. Using a single connection (thanks to the magic of HTTP/2), a site composed primarily of JavaScript loaded <em>perfectly</em> can, in 2021, weigh nearly 600KiB and still hit the first-load bar.</p>

<p>That's a very fine point to balance on, though. A single additional TCP/TLS connection setup in the critical path reduces the amount by 100KiB (as do subsequent critical-path network handshakes). Serialized requests for data, high TTFBs, and ever-present font serving issues make these upper limits far higher than what a site shooting for consistently good load times should be aiming for. In practice, you can't actually afford 600KiB of content if your application is build in the increasingly popular "single page app" style.</p>

<p>As networks have improved, client-side CPU time now dominates script download, adding further variability. Not all script parses and runs in the same amount of time for the same size. The contribution of connection setup also looms large.</p>

<p>If you want to play with the factors and see how they contribute, you can try this slightly updated version of 2017's calculator (launch a larger version in a new tab <a href="https://infrequently.org/2021/03/the-performance-inequality-gap/chart/index.html" target="_new">here</a>):</p>

<figure>
<a href="https://infrequently.org/2021/03/the-performance-inequality-gap/chart/index.html" alt="&lt;em&gt;Tap to try the interactive version.&lt;/em&gt;">
<picture>
<source sizes="(max-width: 1200px) 70vw, 400px" srcset="https://infrequently.org/2021/03/the-performance-inequality-gap/chart.png?nf_resize=fit&amp;w=2400 2400w,
/2021/03/the-performance-inequality-gap/chart.png?nf_resize=fit&amp;w=1600 1600w,
/2021/03/the-performance-inequality-gap/chart.png?nf_resize=fit&amp;w=1200 1200w,
/2021/03/the-performance-inequality-gap/chart.png?nf_resize=fit&amp;w=800 800w,
/2021/03/the-performance-inequality-gap/chart.png?nf_resize=fit&amp;w=600 600w,
/2021/03/the-performance-inequality-gap/chart.png?nf_resize=fit&amp;w=400 400w">
<img src="https://infrequently.org/2021/03/the-performance-inequality-gap/chart.png?nf_resize=fit&amp;w=400" alt="&lt;em&gt;Tap to try the interactive version.&lt;/em&gt;" decoding="async" loading="lazy">
</source></picture>
</a>
<figcaption><em>Tap to try the interactive version.</em></figcaption>
</figure>

<p>This model of browser behaviour, network impacts, and device processing time is, of course, wrong for your site. It could be wrong in ways big and small. Perhaps your content is purely HTML, CSS, and images which would allow for a much higher budget. Or perhaps your JS isn't visually critical path, but still creates long delays because of delayed fetching. And nobody, realistically, can predict how much main-thread work a given amount of JS will cause. So it's an educated guess with some padding built in to account for worst-case content-construction (which is more common than you or I would like to believe).</p>

<p>Conservatively then, assuming at least 2 connections need to be set up (burning ~1400 of our 5000ms), and that script resources are in the critical path, the <strong>new global baseline leaves space for ~100KiB (gzipped) of HTML/CSS/fonts and 300-350KiB of JavaScript on the wire (compressed)</strong>. Critical path images for LCP, if any, need to subtract their transfer size from one of these buckets, with trades against JS bundle size potentially increasing total download budget, but the details matter a great deal. For "modern" pages, half a megabyte is a decent hard budget.</p>

<p>Is that a lot? Well, 2-4x our <a href="https://infrequently.org/2017/10/can-you-afford-it-real-world-web-performance-budgets/">previous budget</a>, and as low-end CPUs finally begin to get faster over the next few years, we can expect it to loosen further for well-served content.</p>

<p>Sadly, most sites aren't perfectly served or structured, and <em>most</em> mobile web pages send more than this amount of JS. But there's light at the end of the tunnel: if we can just hold back the growth of JS payloads for another year or two — or reverse the trend slightly — we might achieve a usable web for the majority of the world's users by the middle of the decade.</p>

<p>Getting there involves no small amount of class traitorship; the frontend community will need to value the the commons over personal comfort for a little while longer to ease our ecosystem back toward health. The past 6 years of consulting with partner teams has felt like a dark remake of Groundhog Day, with a constant parade of sites failing from the get-go thanks to Framework + Bundler + SPA architectures that are mismatched to the tasks and markets at hand. Time (and chips) can heal these wounds if we only let it. We only need to hold the line on script bloat for a few years for devices and networks to overtake the extreme, unconscionable excesses of the 2010's.</p>

<h3 id="vital-baselines">Baselines And Budgets Remain Vital</h3>

<p>I mentioned near the start of this too-long piece that metrics better than Time-to-Interactive have been developed since 2017. The professionalism with which the <a href="https://web.dev/vitals/">new Core Web Vitals (CWV)</a> have been developed, tested, and iterated on inspires real confidence. CWV's <a href="https://web.dev/vitals/#core-web-vitals">constituent metrics and limits</a> work to capture important aspects of page experiences as users perceive them on real devices and networks.</p>

<p>As RUM (field) metrics rather than bench tests, they represent ground truth for a site, and are <a href="https://support.google.com/webmasters/answer/9205520">reported in aggregate by the Chrome User Experience Report (CrUX) pipeline</a>. Getting user-population level data about the performance of sites without custom tooling is a 2016-era dream come true. Best of all, the metrics and limits can continue to evolve in the future as we gain confidence that we can accurately measure other meaningful components of a user's journey.</p>

<p>These field metrics, however valuable, don't yet give us enough information to guide global first-best-guess making when developing new sites. Continuing to set <a href="https://timkadlec.com/remembers/2019-03-07-performance-budgets-that-stick/">performance budgets</a> is necessary for teams in development, not least of all because conformance can be automated in CI/CD flows. CrUX data collection and <a href="https://github.com/GoogleChrome/web-vitals">first-party RUM analytics</a> of these metrics require live traffic, meaning results can be predicted but only verified once deployed.</p>

<p>Both budgets and RUM analytics will continue to be powerful tools in piercing the high-performance privilege bubble that surrounds today's frontend discourse. Grounding our choices against a baseline and measuring how it's going for real users are the only proven approaches I know that reliably help teams take the first step toward frontend's first and highest calling: a web that's truly <a href="https://www.youtube.com/watch?v=UMNFehJIi0E">for everyone</a>.</p>
</article>


<hr>

<footer>
<p>
<a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
<use xlink:href="/static/david/icons2/symbol-defs.svg#icon-home"></use>
</svg> Accueil</a> •
<a href="/david/log/" title="Accès au flux RSS"><svg class="icon icon-rss2">
<use xlink:href="/static/david/icons2/symbol-defs.svg#icon-rss2"></use>
</svg> RSS</a> •
<a href="http://larlet.com" title="Go to my English profile" data-instant><svg class="icon icon-user-tie">
<use xlink:href="/static/david/icons2/symbol-defs.svg#icon-user-tie"></use>
</svg> Pro</a> •
<a href="mailto:david%40larlet.fr" title="Envoyer un courriel"><svg class="icon icon-mail">
<use xlink:href="/static/david/icons2/symbol-defs.svg#icon-mail"></use>
</svg> Email</a> •
<abbr class="nowrap" title="Hébergeur : Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33184162340"><svg class="icon icon-hammer2">
<use xlink:href="/static/david/icons2/symbol-defs.svg#icon-hammer2"></use>
</svg> Légal</abbr>
</p>
<template id="theme-selector">
<form>
<fieldset>
<legend><svg class="icon icon-brightness-contrast">
<use xlink:href="/static/david/icons2/symbol-defs.svg#icon-brightness-contrast"></use>
</svg> Thème</legend>
<label>
<input type="radio" value="auto" name="chosen-color-scheme" checked> Auto
</label>
<label>
<input type="radio" value="dark" name="chosen-color-scheme"> Foncé
</label>
<label>
<input type="radio" value="light" name="chosen-color-scheme"> Clair
</label>
</fieldset>
</form>
</template>
</footer>
<script>
function loadThemeForm(templateName) {
const themeSelectorTemplate = document.querySelector(templateName)
const form = themeSelectorTemplate.content.firstElementChild
themeSelectorTemplate.replaceWith(form)

form.addEventListener('change', (e) => {
const chosenColorScheme = e.target.value
localStorage.setItem('theme', chosenColorScheme)
toggleTheme(chosenColorScheme)
})

const selectedTheme = localStorage.getItem('theme')
if (selectedTheme && selectedTheme !== 'undefined') {
form.querySelector(`[value="${selectedTheme}"]`).checked = true
}
}

const prefersColorSchemeDark = '(prefers-color-scheme: dark)'
window.addEventListener('load', () => {
let hasDarkRules = false
for (const styleSheet of Array.from(document.styleSheets)) {
let mediaRules = []
for (const cssRule of styleSheet.cssRules) {
if (cssRule.type !== CSSRule.MEDIA_RULE) {
continue
}
// WARNING: Safari does not have/supports `conditionText`.
if (cssRule.conditionText) {
if (cssRule.conditionText !== prefersColorSchemeDark) {
continue
}
} else {
if (cssRule.cssText.startsWith(prefersColorSchemeDark)) {
continue
}
}
mediaRules = mediaRules.concat(Array.from(cssRule.cssRules))
}

// WARNING: do not try to insert a Rule to a styleSheet you are
// currently iterating on, otherwise the browser will be stuck
// in a infinite loop…
for (const mediaRule of mediaRules) {
styleSheet.insertRule(mediaRule.cssText)
hasDarkRules = true
}
}
if (hasDarkRules) {
loadThemeForm('#theme-selector')
}
})
</script>
</body>
</html>

+ 185
- 0
cache/2021/d3a653c926aa97707653300947b65ab5/index.md Просмотреть файл

@@ -0,0 +1,185 @@
title: The Mobile Performance Inequality Gap, 2021
url: https://infrequently.org/2021/03/the-performance-inequality-gap/
hash_url: d3a653c926aa97707653300947b65ab5

<p><em><strong>TL;DR:</strong> A lot has changed since 2017 when we last <a href="https://infrequently.org/2017/10/can-you-afford-it-real-world-web-performance-budgets/">estimated a global baseline resource per-page resource budget of 130-170KiB</a>. Thanks to progress in networks and browsers (but not devices), a <a href="17/perf_budget_calculator/calc.html">more generous global budget cap has emerged</a> for sites constructed the "modern" way. We can now afford <strong>~100KiB of HTML/CSS/fonts and ~300-350KiB of JS (gzipped)</strong>. This rule-of-thumb limit should hold for at least a year or two. As always, the devil's in the footnotes, but the top-line is unchanged: when we construct the digital world to the limits of the best devices, we build a less usable one for <a href="https://www.idc.com/promo/smartphone-market-share/os">80+% of the world's users</a>.</em></p>
<p>Way back in 2016, I <a href="https://www.youtube.com/watch?v=4bZvq3nodf4">tried to raise the alarm about the causes and effects of the terrible performance</a> for <a href="https://www.idc.com/promo/smartphone-market-share/vendor">most users</a> from sites using popular frontend tools. The negative effects were particularly pronounced in the fastest-growing device segment: low-end to mid-range Android phones.</p>
<p><lite-youtube videoid="4bZvq3nodf4" videotitle="Progressive Performance: Chrome Dev Summit 2016">
</lite-youtube></p>
<p>Bad individual experiences can colour expectations of the entire ecosystem. Your company's poor site performance can manifest as lower engagement, higher bounce rates, or a reduction in conversions. While this local story is important, it isn't the whole picture. If a large enough proportion of sites behave poorly, <a href="https://services.google.com/fh/files/blogs/google_delayexp.pdf">performance hysteresis</a> may colour user views of <em>all</em> web experiences.</p>
<p>Unless a site is launched from the home screen as a <a href="https://web.dev/progressive-web-apps/">PWA</a>, pages are co-mingled. Pages are experienced as a series of taps, flowing effortlessly across sites; a river of links. A bad experience in the flow is a bad experience <em>of the flow</em>, with constituent parts blending together.</p>
<p>If tapping links tends to feel bad...why keep tapping? It's not as though slow websites are the only way to access information. Plenty of native apps are happy to aggregate content and serve it up in a reliably fast package, given half a chance. The consistency of those walled gardens is a large part of what the mobile web is up against — and <a href="http://vimeo.com/364402896">losing to</a>.</p>
<p><lite-vimeo videoid="364402896" videotitle="Alex Russell - The Mobile Web: MIA">
<a href="http://vimeo.com/364402896">The Mobile Web: MIA</a>
</lite-vimeo></p>
<p>Poor performance of sites that link to and from yours negatively impacts engagement <em>on your site</em>, even if it is consistently snappy. Live by the link, die by the link.</p>
<p>The harmful business impact of poor performance is constantly re-validated. Big decreases in performance predictably lead to (somewhat lower) decreases in user engagement and conversion. The scale of the effect can be deeply situational or hard to suss out without solid metrics, but it's there.</p>
<p>Variance contributes another layer of concern; high variability in responsiveness may create effects that perceptually dominate averages, or even medians. If 9 taps in 10 respond in 100ms, but every 10th takes a full second, what happens to user confidence and engagement? These deep-wetware effects and their cross-origin implications mean that your site's success is, partially, a function of the health of the commons.</p>
<p>From this perspective, it's helpful to consider what it might take to set baselines that can help ensure minimum quality across link taps, so in 2017 I followed up with <a href="https://infrequently.org/2017/10/can-you-afford-it-real-world-web-performance-budgets/">a post sketching a rubric for thinking about a global baseline</a>.</p>
<p>The punchline:</p>
<blockquote>
<p>The default global baseline is a ~$200 Android device on a 400Kbps link with a 400ms round-trip-time ("RTT"). This translates into a budget of ~130-170KB of critical-path resources, depending on composition — the more JS you include, the smaller the bundle must be.</p>
</blockquote>
<p>A $200USD device at the time featured 4-8 (slow, in-order, low-cache) cores, ~2GiB of RAM, and pokey MLC NAND flash storage. The <a href="https://www.gsmarena.com/motorola_moto_g4-8103.php">Moto G4</a>, for example.</p>
<p>The 2017 baseline represented a conservative, but evidence-driven, interpretation of the best information I could get regarding network performance, along with trend lines regarding device shipment volumes and price points. Getting accurate global information that isn't artificially reduced to averages remains an ongoing challenge. Performance work often focuses on high percentile users (the slowest), after all.</p>
<p>Since then, the metrics conversation has moved forward significantly, culminating in <a href="https://web.dev/vitals/">Core Web Vitals</a>, reported via <a href="https://developers.google.com/web/tools/chrome-user-experience-report">the Chrome User Experience Report</a> to reflect the real-world experiences of users.</p>
<p>Devices and networks have evolved too:</p>

<p>Meanwhile, developer behaviour <a href="https://httparchive.org/reports/state-of-javascript">offers little hope:</a></p>
<figure>
<a href="https://httparchive.org/reports/state-of-javascript" alt="Median mobile JavaScript payloads have only grown since 2016, now hovering above 400KiB of script transferred, or nearly 2.5MiB of uncompressed JS.">
<picture>
<source sizes="(max-width: 1200px) 70vw, 400px" srcset="https://infrequently.org/2021/03/the-performance-inequality-gap/http_archive_median_js.png?nf_resize=fit&amp;w=2400 2400w,
/2021/03/the-performance-inequality-gap/http_archive_median_js.png?nf_resize=fit&amp;w=1600 1600w,
/2021/03/the-performance-inequality-gap/http_archive_median_js.png?nf_resize=fit&amp;w=1200 1200w,
/2021/03/the-performance-inequality-gap/http_archive_median_js.png?nf_resize=fit&amp;w=800 800w,
/2021/03/the-performance-inequality-gap/http_archive_median_js.png?nf_resize=fit&amp;w=600 600w,
/2021/03/the-performance-inequality-gap/http_archive_median_js.png?nf_resize=fit&amp;w=400 400w">
<img src="https://infrequently.org/2021/03/the-performance-inequality-gap/http_archive_median_js.png?nf_resize=fit&amp;w=400" alt="Median mobile JavaScript payloads have only grown since 2016, now hovering above 400KiB of script transferred, or nearly 2.5MiB of uncompressed JS." decoding="async" loading="lazy">
</source></picture>

</a>
<figcaption>Median mobile JavaScript payloads have only grown since 2016, now hovering above 400KiB of script transferred, or nearly 2.5MiB of uncompressed JS.</figcaption>
</figure>
<p>A silver lining on this dark cloud is that mobile JavaScript payload growth paused in 2020. How soon will low-end and middle-tier phones be able to handle such chonky payloads? If the median site continued to send 3x the recommended amount of script, when would the web start to feel usable on most of the world's devices?</p>
<p>Here begins our 2021 adventure.</p>
<h2 id="hard-reset">Hard Reset</h2>
<p>To update our global baseline from 2017, we want to update our priors on a few dimensions:</p>
<ul>
<li>The evolved device landscape</li>
<li>Modern network performance and availability</li>
<li>Advances in browser content processing</li>
</ul>
<h3 id="king-content">Content Is Dead, Long Live Content</h3>
<p>Good news has consistently come from the steady pace of browser progress. The single largest improvements visible in traces come from <a href="https://v8.dev/blog/scanner">improved</a> <a href="https://v8.dev/blog/preparser">parsing</a> and <a href="https://v8.dev/blog/background-compilation">off-thread compilation of JavaScript</a>. This step-change, along with <a href="https://v8.dev/blog/v8-release-75#script-streaming-directly-from-network">improvements to streaming compilation</a>, has helped to ensure that users are less likely to notice the unreasonably-sized JS payloads that "modern" toolchains generate more often than not. Better use of more cores (moving compilation off-thread) has given sites that provide HTML and CSS content a fighting chance of remaining responsive, even when saddled with staggering JS burdens.</p>
<p>A <a href="https://v8.dev/blog/adaptor-frame">steady</a> <a href="https://v8.dev/blog/embedded-builtins">drumbeat</a> of <a href="https://v8.dev/blog/high-performance-es2015">improvements</a> have contributed to reduced runtime costs, too, though I fear they most often create an <a href="https://en.wikipedia.org/wiki/Induced_demand">induced demand</a> effect.</p>
<p>The residual main-thread compilation, allocation, and script-driven DOM/Layout tasks pose a challenge for delivering a good user experinece. As we'll see below, CPUs are not improving fast enough to cope with frontend engineers' rosy resource assumptions. If there is unambiguously good news on the tooling front, multiple popular tools now include options to prevent sending first-party JS in the first place (<a href="https://chrisbrownie.dev/creating-a-completely-static-build-with-nextjs">Next.js</a>, <a href="https://www.gatsbyjs.com/plugins/gatsby-plugin-no-javascript/">Gatsby</a>), though the JS community remains in stubborn denial about the costs of client-side script. Hopefully, toolchain progress of this sort can provide a more accessible bridge as we transition costs to a reduced-script-emissions world.</p>
<h3 id="oh-em-gee">4G Is A Miracle, 5G Is A Mirage</h3>
<p>The 2017 baseline post included <a href="https://infrequently.org/17/perf_budget_calculator/index.html">a small model</a> for thinking about how to think about how various factors of a page's construction influence the likelihood of hitting a 5-second first load goal.</p>
<p>The hard floor of that model (~1.6s) came from the contributions DNS, TCP/IP, and TLS connection setup over a then-reasonable <a href="https://infrequently.org/2017/10/can-you-afford-it-real-world-web-performance-budgets/#content:~:text=On%20a%20slow%203G%20network%2C%20emulated,400Kbps%20transfer">3G network baseline</a>, leaving only 3400ms to work with, fighting Nagle and weak CPUs the whole way. Adding just one extra connection to a CDN for a critical path resource could sink the entire enterprise. Talk about a hard target.</p>
<p>Four years later, has anything changed? I'm happy to report that it has. Not as much as we'd like, of course, but the worldwide baseline has changed <em>enormously</em>. How? Why?</p>
<p><a href="https://www.kaiostech.com/reliance-jio-became-worlds-fastest-growing-mobile-network/">Reliance Jio, mostly</a>.</p>
<p>India has been the <a href="https://www.statista.com/statistics/283331/smartphone-shipments-worldwide/">epicentre of smartphone growth</a> in recent years, owing to the sheer size of its market and an <a href="https://www.outlookindia.com/newsscroll/india-feature-phone-market-declines-24-in-q1-2020/1814178">accelerating shift away from feature phones</a> which made up the majority of Indian mobile devices until as late as 2019. Continued projections of <a href="https://economictimes.indiatimes.com/tech/tech-bytes/indias-smartphone-market-is-set-for-double-digit-growth-in-2021/articleshow/80106597.cms">double-digit market growth for smartphones</a>, on top of a doubling of shipments in the past 5 years, paint a vivid picture.</p>
<p>Key to this growth is the <a href="https://www.wsj.com/articles/two-years-ago-india-lacked-fast-cheap-internetone-billionaire-changed-all-that-1536159916">effect of Reliance Jio's entry into the carrier market</a>. Before Jio's disruptive pricing and aggressive rollout, data services in India were among the most expensive in the world relative to income and heavily reliant on 3G outside wealthier "tier 1" cities. Worse, 3G service often performed like 2G in other markets, thanks to over-provisioning and data rate throttling by incumbent carriers.</p>
<p>In 2016, Jio swept over the subcontinent like a monsoon dropping a torrent of 4G infrastructure and free data rather than rain.</p>
<p>Competing carriers responded instantly, dropping prices aggressively, leading to <a href="https://www.business-standard.com/article/pti-stories/mobile-data-price-down-by-95-but-revenue-up-2-5-times-in-5-yrs-trai-119082101291_1.html">reductions in per-packet prices approaching 95%</a>.</p>
<p>Jio's blanket <a href="https://www.opensignal.com/reports/2017/04/india/state-of-the-mobile-network">4G rollout blitzkrieg</a> <a href="https://www.thehindu.com/data/data-where-indias-mobile-internet-speed-ranks-globally-which-operator-offers-the-fastest-download-speeds-and-more/article30800987.ece">shocked incumbents with a superior product at an unheard-of price</a>, forcing the entire market to improve data rates and coverage. India became a <a href="https://www.opensignal.com/reports/2020/09/india/mobile-network-experience">4G-centric market</a> sometime in 2018.</p>
<p>If there's a bright spot in our construction of a 2021 baseline for performance, this is it. We can finally <a href="https://www.opensignal.com/sites/opensignal-com/files/data/reports/pdf-only/data-2020-05/state_of_mobile_experience_may_2020_opensignal_3_0.pdf">upgrade our assumptions about the network to assume slow-ish 4G almost everywhere (pdf)</a>.</p>
<p>5G looks set to continue a <a href="https://www.opensignal.com/2021/02/03/benchmarking-the-global-5g-experience">bumpy rollout</a> for the next half-decade. Carriers make different frequency band choices in different geographies, and 5G performance is heavily sensitive to mast density, which will add confusion for years to come. Suffice to say, 5G isn't here yet, even if wealthy users in a few geographies come to think of it as "normal" far ahead of worldwide deployment.</p>
<h3 id="hardware-destiny">Hardware Past As Performance Prologue</h3>
<p>Whatever progress runtimes and networks have made in the past half-decade, browsers are stubbornly situated in the devices carried by real-world users, and the single most important thing to understand about the landscape of devices your sites will run on is that they are <em>not new phones</em>.</p>
<p>This makes some intuitive sense: smartphones are not in their first year (and haven't been for more than a dozen years), and most users do not replace their devices every year. Most smartphone sales today are replacements (that is, to users who have previously owned a smartphone), and the longevity of devices continues to rise.</p>
<p>The worldwide device replacement <em>average</em> is <a href="https://www.statista.com/statistics/786876/replacement-cycle-length-of-smartphones-worldwide/">now 33 months</a>. In markets near <a href="https://www.theverge.com/2019/1/3/18166399/iphone-android-apple-samsung-smartphone-sales-peak">smartphone saturation</a>, that means we can expect the median device to be nearly 18 months old. Newer devices continue to be faster for the same dollar spent. Assuming <a href="https://statinvestor.com/data/35666/smartphone-average-selling-price-worldwide/">average selling prices (ASPs) remaining in a narrow year-on-year band in most geographies</a>, a good way to think of the "average phone" as being <em>the average device sold 18 months ago</em>. ASPs, however, have started to rise, making <a href="https://infrequently.org/2017/10/can-you-afford-it-real-world-web-performance-budgets/">my prognostications from 2017</a> only <em>technically</em> correct:</p>
<blockquote>
<p>The true median device from 2016 sold at about ~$200 unlocked. This year's median device is even cheaper, but their performance is roughly equivalent. Expect continued performance stasis at the median for the next few years. This is part of the reason I suggested the Moto G4 last year and recommend it or the Moto G5 Plus this year.</p>
</blockquote>
<p>Median devices continue to be different from averages, but we can squint a little as we're abstracting over multi-year cohorts. The worldwide ASP <a href="https://statinvestor.com/data/35666/smartphone-average-selling-price-worldwide/">18 months ago was ~$300USD</a>, so the <em>average</em> performance in the deployed fleet can be represented by <a href="https://www.businessinsider.com/best-phones-under-300-apple-samsung-2019-8">a $300 device from mid-2019</a>. The <a href="https://en.wikipedia.org/wiki/Moto_G7">Moto G7</a> very much <a href="https://www.gsmarena.com/motorola_moto_g7-9357.php">looks the part</a>.</p>
<p>Compared to devices wealthy developers carry, the performance is <a href="https://nanoreview.net/en/soc-compare/qualcomm-snapdragon-632-vs-apple-a14-bionic">night and (blinding) day</a>. However shocking a 6x difference in single-thread CPU performance might be, it's nothing compared to where we <em>should</em> be setting the global baseline: the P75+ device. Using our little mental model for device age and replacement, we can naively estimate what the 75th percentile (or higher) device could be in terms of device price + age, either by tracking devices at half the ASP at half the replacement age, or by looking at ASP-priced devices 3/4 of the way through the replacement cycle. Today, either method returns a similar answer.</p>
<p>This is inexact for dozens of reasons, not least of all markets with lower ASPs not yet achieving smartphone saturation. Using a global ASP as a benchmark can further mislead thanks to the distorting effect of ultra-high-end prices rising while shipment volumes stagnate. It's hard to know which way these effects cut when combined, so we're going to make a further guess: we'll take half the average price and note how wrong this likely is.</p>
<p>So what did $150USD fetch in 2019?</p>
<p>Say hello to the <a href="https://www.cnet.com/news/motorolas-moto-e6-is-a-150-phone-that-feels-like-a-150-phone/">Moto E6</a>! <a href="https://www.gsmarena.com/motorola_moto_e6-9682.php">This 2GiB RAM, Android 9 stalwart</a> features the all-too classic lines of a Quad-core A53 (1.4GHz, small mercies) CPU, tastefully presented in a charming 5.5" package.</p>
<figure>
<a href="https://www.gsmarena.com/motorola_moto_e6-9682.php" alt="The smooth, dulcet tones of 2019's Moto E6.">
<picture>
<source sizes="(max-width: 1200px) 70vw, 400px" srcset="https://infrequently.org/2021/03/the-performance-inequality-gap/motorola-moto-e6-xt2005-navy-blue.jpg?nf_resize=fit&amp;w=2400 2400w,
/2021/03/the-performance-inequality-gap/motorola-moto-e6-xt2005-navy-blue.jpg?nf_resize=fit&amp;w=1600 1600w,
/2021/03/the-performance-inequality-gap/motorola-moto-e6-xt2005-navy-blue.jpg?nf_resize=fit&amp;w=1200 1200w,
/2021/03/the-performance-inequality-gap/motorola-moto-e6-xt2005-navy-blue.jpg?nf_resize=fit&amp;w=800 800w,
/2021/03/the-performance-inequality-gap/motorola-moto-e6-xt2005-navy-blue.jpg?nf_resize=fit&amp;w=600 600w,
/2021/03/the-performance-inequality-gap/motorola-moto-e6-xt2005-navy-blue.jpg?nf_resize=fit&amp;w=400 400w">
<img src="https://infrequently.org/2021/03/the-performance-inequality-gap/motorola-moto-e6-xt2005-navy-blue.jpg?nf_resize=fit&amp;w=400" alt="The smooth, dulcet tones of 2019's Moto E6." decoding="async" loading="lazy">
</source></picture>

</a>
<figcaption>The smooth, dulcet tones of 2019's Moto E6.</figcaption>
</figure>
<p>If those specs sound eerily familiar, it's perhaps because they're <a href="https://www.gsmarena.com/motorola_moto_g4-8103.php">identical</a> to 2016's <a href="https://www.cnet.com/reviews/motorola-moto-g4-review/">$200USD Moto G4</a>, all the way down to the <a href="https://en.wikichip.org/wiki/28_nm_lithography_process">2011-vintage 28nm SoC process node</a> used to fab the chip's <a href="https://en.wikipedia.org/wiki/ARM_Cortex-A53">anemic, 2012-vintage A53 cores</a>. There are differences, of course, but <a href="https://browser.geekbench.com/v5/cpu/compare/6839107?baseline=5281022">not where it counts</a>.</p>
<p>You might recall the Moto G4 as a baseline recommendation from 2016 for forward-looking performance work. It's also the model we sent several dozen of to <a href="https://twitter.com/patmeenan">Pat Meenan</a> — devices that power <a href="https://webpagetest.org/easy"><code>webpagetest.org/easy</code></a> to this day. There was no way to know that the already-ageing in-order, near-zero-cache A53 + too-hot-to-frequency-scale 28nm process duo would continue to haunt us five year on. Today's P75 devices tell the story of the yawning <em>Performance Inequality Gap</em>: performance for those at the top end continues to accelerate away from the have-nots who are perpetually stuck with 2014's hardware.</p>
<p>The good news is that chip progress has begun to move, if glacially, in the past couple of years. 28nm chips are being supplanted at the sub-$200USD price-point by 14nm and <a href="https://www.gsmarena.com/motorola_moto_g_play_(2021)-10673.php">even 11nm parts</a>. Specs are finally improving quickly at the bottom of the market now, with <a href="https://www.gsmarena.com/tecno_spark_6_debuts_with_68_display_helio_g70_chipset_-news-45483.php">new ~$135USD devices sporting CPUs that should give last year's mid-range a run for its money</a>.</p>
<h3 id="mind-the-gap">Mind The Gap</h3>
<p>Regardless, the overall story for hardware progress remains grim, particularly when we recall how long device replacement cycles are:</p>
<figure>
<a href="https://infrequently.org/2021/03/the-performance-inequality-gap/single_core_scores_large.png" alt="&lt;em&gt;Tap for a larger version.&lt;/em&gt;&lt;br&gt;Updated Geekbench 4 single-core scores for each mobile price-point.">
<picture>
<source sizes="(max-width: 1200px) 70vw, 400px" srcset="https://infrequently.org/2021/03/the-performance-inequality-gap/single_core_scores.png?nf_resize=fit&amp;w=2400 2400w,
/2021/03/the-performance-inequality-gap/single_core_scores.png?nf_resize=fit&amp;w=1600 1600w,
/2021/03/the-performance-inequality-gap/single_core_scores.png?nf_resize=fit&amp;w=1200 1200w,
/2021/03/the-performance-inequality-gap/single_core_scores.png?nf_resize=fit&amp;w=800 800w,
/2021/03/the-performance-inequality-gap/single_core_scores.png?nf_resize=fit&amp;w=600 600w,
/2021/03/the-performance-inequality-gap/single_core_scores.png?nf_resize=fit&amp;w=400 400w">
<img src="https://infrequently.org/2021/03/the-performance-inequality-gap/single_core_scores.png?nf_resize=fit&amp;w=400" alt="&lt;em&gt;Tap for a larger version.&lt;/em&gt;&lt;br&gt;Updated Geekbench 4 single-core scores for each mobile price-point." decoding="async" loading="lazy">
</source></picture>

</a>
<figcaption><em>Tap for a larger version.</em><br>Updated Geekbench 4 single-core scores for each mobile price-point.</figcaption>
</figure>
<p>Recall that single-core performance most directly translates into speed on the web. Android-ecosystem SoC performance is, in a word, disastrous.</p>
<p>How bad is it?</p>
<p>We can think about each category in terms of years behind contemporary iPhone releases:</p>
<ul>
<li>2020's high-end Androids sport the single-core performance of an iPhone 8, a phone released in Q3'17</li>
<li>mid-priced Androids were slightly faster than 2014's iPhone 6</li>
<li>low-end Androids have finally caught up to the iPhone 5 from 2012</li>
</ul>
<p>You're reading that right: single core Android performance at the low end is both shockingly bad and dispiritingly stagnant.</p>
<figure>
<a href="https://infrequently.org/2021/03/the-performance-inequality-gap/multi_core_scores_large.png" alt="&lt;em&gt;Tap for a larger version.&lt;/em&gt;&lt;br&gt;Android ecosystem SoC's fare slightly better on multi-core performance, but the Performance Inequality Gap is growing there, too.">
<picture>
<source sizes="(max-width: 1200px) 70vw, 400px" srcset="https://infrequently.org/2021/03/the-performance-inequality-gap/multi_core_scores.png?nf_resize=fit&amp;w=2400 2400w,
/2021/03/the-performance-inequality-gap/multi_core_scores.png?nf_resize=fit&amp;w=1600 1600w,
/2021/03/the-performance-inequality-gap/multi_core_scores.png?nf_resize=fit&amp;w=1200 1200w,
/2021/03/the-performance-inequality-gap/multi_core_scores.png?nf_resize=fit&amp;w=800 800w,
/2021/03/the-performance-inequality-gap/multi_core_scores.png?nf_resize=fit&amp;w=600 600w,
/2021/03/the-performance-inequality-gap/multi_core_scores.png?nf_resize=fit&amp;w=400 400w">
<img src="https://infrequently.org/2021/03/the-performance-inequality-gap/multi_core_scores.png?nf_resize=fit&amp;w=400" alt="&lt;em&gt;Tap for a larger version.&lt;/em&gt;&lt;br&gt;Android ecosystem SoC's fare slightly better on multi-core performance, but the Performance Inequality Gap is growing there, too." decoding="async" loading="lazy">
</source></picture>

</a>
<figcaption><em>Tap for a larger version.</em><br>Android ecosystem SoC's fare slightly better on multi-core performance, but the Performance Inequality Gap is growing there, too.</figcaption>
</figure>
<p>The multi-core performance shows the same basic story: iOS's high-end and the most expensive Androids are pulling away from the volume-shipment pack. The fastest Androids predictably remain 18-24 months behind, owing to cheapskate choices about cache sizing by Qualcomm, Samsung Semiconductor, MediaTek, and the rest. Don't pay a lot for an Android-shaped muffler.</p>
<p><a href="https://twitter.com/slightlylate/status/1370133443695190018">Chip design choices</a> and silicon economics are the defining feature of the still-growing <em>Performance Inequality Gap</em>.</p>
<p>Things continue to get better and better for the wealthy, leaving the rest behind. <strong>When we construct a digital world to the limits of the best devices, the worse an experience we build, on average, for those who cannot afford iPhones or $800 Samsung flagships.</strong></p>
<p>It is perhaps predictable that, instead of presenting a bulwark against stratification, technology outcomes have tracked society's growing inequality. A yawning chasm of disparities is playing out in our phones at the same time it has come to shape <a href="https://news.un.org/en/story/2020/01/1055681">our economic and political lives</a>. It's hard to escape thinking they're connected.</p>
<p>Developers, particularly in Silicon Valley firms, are definitionally wealthy and enfranchised by world-historical standards. Like upper classes of yore, comfort ("<a href="https://infrequently.org/2018/09/the-developer-experience-bait-and-switch/">DX</a>") comes with courtiers happy to declare how important comfort must surely be. It's bunk, or at least most of it is.</p>
<p>As frontenders, our task is to make services that work well for all, not just the wealthy. If improvements in our tools or our comfort <em>actually</em> deliver improvements in that direction, so much the better. But we must never forget that measurable improvement for <em>users</em> is the yardstick.</p>
<p>Instead of measurement, we seem to suffer a proliferation of postulates about how each new increment of comfort must <em>surely</em> result in better user experiences. But the postulates are not tied to robust evidence. Instead, experience teaches that it's the process of taking care to attend to those least-well-off that changes outcomes. Trickle-down user experience from developer-experience is, in 2021, as fully falsified as the <a href="https://www.washingtonpost.com/politics/2019/06/01/trump-is-giving-arthur-laffer-presidential-medal-freedom-economists-arent-laughing/">Laffer Curve</a>. There's no durable substitute for compassion.</p>
<h2 id="baseline-next">A 2021 Global Baseline</h2>
<p>It's in that spirit that I find it important to build to a strawperson baseline device and network target. Such a benchmark serves as a stand-in <em>until one gets situated data</em> about a site or service's users, from whom we can derive informed conclusions about user needs and appropriate resource budgets.</p>
<p>A global baseline is doubly important for generic frameworks and libraries, as they <em>will</em> be included in projects targeted at global-baseline users, whether or not developers have that in mind. Tools that cannot fit comfortably within, say, 10% of our baseline budget should be labelled as desktop-only or replaced in our toolchains. Many popular tools over the past 5 years have been blithely punctured these limits relative to the 2017 baseline, and the results have been predictably poor.</p>
<p>Given all the data we've slogged through, we can assemble a sketch of the browsers, devices, and networks today's P50 and P75 users will access sites from. Keep in mind that this baseline <em>might be too optimistic</em>, depending on your target market. Trust but verify.</p>
<p>OpenSignal's global report on connection speeds (<a href="https://www.opensignal.com/sites/opensignal-com/files/data/reports/pdf-only/data-2020-05/state_of_mobile_experience_may_2020_opensignal_3_0.pdf">pdf</a>) suggest that <a href="https://github.com/WPO-Foundation/webpagetest/blob/master/www/settings/connectivity.ini.sample#L48">WebPageTest's default 4G configuration (9Mbps w/ 170ms RTT)</a> is a reasonable stand-in for the P75 network link. WPT's <a href="https://github.com/WPO-Foundation/webpagetest/blob/master/www/settings/connectivity.ini.sample#L54">LTE configuration (12Mbps w/ 70ms RTT)</a> may actually be too conservative for a P50 estimate today; something closer to 25Mbps seems to approach the worldwide median today. Network progress has been astonishing, particularly channel capacity (bandwidth). Sadly, data on latency is harder to get, even from Google's perch, so progress there is somewhat more difficult to judge.</p>
<p>As for devices, the P75 situation remains dire and basically unchanged from the baseline I suggested more than five years ago. Slow A53 cores — a design <a href="https://en.wikipedia.org/wiki/ARM_Cortex-A53">first introduced nearly a decade ago</a> — continue to dominate the landscape, differing only slightly in frequency scaling (through improved process nodes) and GPU pairing. The good news is that this will change rapidly in the next few years. The median <em>new</em> device is already benefiting; modern designs and fab processes are powering a ramp-up in performance for a $300USD device, particularly in multi-core workloads. But the hardware future is not evenly distributed, and web workloads aren't heavily parallel.</p>
<p>Astonishingly, I believe this means that for at least the next year we should consider the venerable Moto G4 to still be our baseline. If you can't buy one new, the 2020-vintage <a href="https://www.gsmarena.com/motorola_moto_e6s_(2020)-10135.php">Moto E6</a> does a stirring rendition of the classic; it's <a href="https://browser.geekbench.com/v4/cpu/compare/15954576?baseline=15987586">basically the same phone, after all</a>. The <a href="https://www.gsmarena.com/motorola_moto_e7_plus-10436.php">Moto E7 Plus</a> is a <a href="https://browser.geekbench.com/v4/cpu/compare/15987586?baseline=15667410">preview of better days to come</a>, and they can't arrive soon enough.</p>

<p>Putting it all together, where does that leave us? Back-of-the napkin, and accepting our previous targets of 5 seconds for first load and two seconds for second load, what can we afford?</p>
<p>Plugging the new P75 numbers in, the impact of network improvements are dramatic. Initial connection setup times are cut in half, dropping from 1600ms to 700ms, which frees up significant headroom to transmit more data in the same time window. The channel capacity increase to 9Mbps is enough to transmit more than 4MiB (megabytes) of content over a single connection in our 5 second window (1 Byte == 8 bits, so 9Mbps is just over ~1MBps). Of course, if most of this content is JavaScript, it must be compiled and run, shrinking our content window back down significantly. Using a single connection (thanks to the magic of HTTP/2), a site composed primarily of JavaScript loaded <em>perfectly</em> can, in 2021, weigh nearly 600KiB and still hit the first-load bar.</p>
<p>That's a very fine point to balance on, though. A single additional TCP/TLS connection setup in the critical path reduces the amount by 100KiB (as do subsequent critical-path network handshakes). Serialized requests for data, high TTFBs, and ever-present font serving issues make these upper limits far higher than what a site shooting for consistently good load times should be aiming for. In practice, you can't actually afford 600KiB of content if your application is build in the increasingly popular "single page app" style.</p>
<p>As networks have improved, client-side CPU time now dominates script download, adding further variability. Not all script parses and runs in the same amount of time for the same size. The contribution of connection setup also looms large.</p>
<p>If you want to play with the factors and see how they contribute, you can try this slightly updated version of 2017's calculator (launch a larger version in a new tab <a href="https://infrequently.org/2021/03/the-performance-inequality-gap/chart/index.html" target="_new">here</a>):</p>

<figure>
<a href="https://infrequently.org/2021/03/the-performance-inequality-gap/chart/index.html" alt="&lt;em&gt;Tap to try the interactive version.&lt;/em&gt;">
<picture>
<source sizes="(max-width: 1200px) 70vw, 400px" srcset="https://infrequently.org/2021/03/the-performance-inequality-gap/chart.png?nf_resize=fit&amp;w=2400 2400w,
/2021/03/the-performance-inequality-gap/chart.png?nf_resize=fit&amp;w=1600 1600w,
/2021/03/the-performance-inequality-gap/chart.png?nf_resize=fit&amp;w=1200 1200w,
/2021/03/the-performance-inequality-gap/chart.png?nf_resize=fit&amp;w=800 800w,
/2021/03/the-performance-inequality-gap/chart.png?nf_resize=fit&amp;w=600 600w,
/2021/03/the-performance-inequality-gap/chart.png?nf_resize=fit&amp;w=400 400w">
<img src="https://infrequently.org/2021/03/the-performance-inequality-gap/chart.png?nf_resize=fit&amp;w=400" alt="&lt;em&gt;Tap to try the interactive version.&lt;/em&gt;" decoding="async" loading="lazy">
</source></picture>
</a>
<figcaption><em>Tap to try the interactive version.</em></figcaption>
</figure>
<p>This model of browser behaviour, network impacts, and device processing time is, of course, wrong for your site. It could be wrong in ways big and small. Perhaps your content is purely HTML, CSS, and images which would allow for a much higher budget. Or perhaps your JS isn't visually critical path, but still creates long delays because of delayed fetching. And nobody, realistically, can predict how much main-thread work a given amount of JS will cause. So it's an educated guess with some padding built in to account for worst-case content-construction (which is more common than you or I would like to believe).</p>
<p>Conservatively then, assuming at least 2 connections need to be set up (burning ~1400 of our 5000ms), and that script resources are in the critical path, the <strong>new global baseline leaves space for ~100KiB (gzipped) of HTML/CSS/fonts and 300-350KiB of JavaScript on the wire (compressed)</strong>. Critical path images for LCP, if any, need to subtract their transfer size from one of these buckets, with trades against JS bundle size potentially increasing total download budget, but the details matter a great deal. For "modern" pages, half a megabyte is a decent hard budget.</p>
<p>Is that a lot? Well, 2-4x our <a href="https://infrequently.org/2017/10/can-you-afford-it-real-world-web-performance-budgets/">previous budget</a>, and as low-end CPUs finally begin to get faster over the next few years, we can expect it to loosen further for well-served content.</p>
<p>Sadly, most sites aren't perfectly served or structured, and <em>most</em> mobile web pages send more than this amount of JS. But there's light at the end of the tunnel: if we can just hold back the growth of JS payloads for another year or two — or reverse the trend slightly — we might achieve a usable web for the majority of the world's users by the middle of the decade.</p>
<p>Getting there involves no small amount of class traitorship; the frontend community will need to value the the commons over personal comfort for a little while longer to ease our ecosystem back toward health. The past 6 years of consulting with partner teams has felt like a dark remake of Groundhog Day, with a constant parade of sites failing from the get-go thanks to Framework + Bundler + SPA architectures that are mismatched to the tasks and markets at hand. Time (and chips) can heal these wounds if we only let it. We only need to hold the line on script bloat for a few years for devices and networks to overtake the extreme, unconscionable excesses of the 2010's.</p>
<h3 id="vital-baselines">Baselines And Budgets Remain Vital</h3>
<p>I mentioned near the start of this too-long piece that metrics better than Time-to-Interactive have been developed since 2017. The professionalism with which the <a href="https://web.dev/vitals/">new Core Web Vitals (CWV)</a> have been developed, tested, and iterated on inspires real confidence. CWV's <a href="https://web.dev/vitals/#core-web-vitals">constituent metrics and limits</a> work to capture important aspects of page experiences as users perceive them on real devices and networks.</p>
<p>As RUM (field) metrics rather than bench tests, they represent ground truth for a site, and are <a href="https://support.google.com/webmasters/answer/9205520">reported in aggregate by the Chrome User Experience Report (CrUX) pipeline</a>. Getting user-population level data about the performance of sites without custom tooling is a 2016-era dream come true. Best of all, the metrics and limits can continue to evolve in the future as we gain confidence that we can accurately measure other meaningful components of a user's journey.</p>
<p>These field metrics, however valuable, don't yet give us enough information to guide global first-best-guess making when developing new sites. Continuing to set <a href="https://timkadlec.com/remembers/2019-03-07-performance-budgets-that-stick/">performance budgets</a> is necessary for teams in development, not least of all because conformance can be automated in CI/CD flows. CrUX data collection and <a href="https://github.com/GoogleChrome/web-vitals">first-party RUM analytics</a> of these metrics require live traffic, meaning results can be predicted but only verified once deployed.</p>

<p>Both budgets and RUM analytics will continue to be powerful tools in piercing the high-performance privilege bubble that surrounds today's frontend discourse. Grounding our choices against a baseline and measuring how it's going for real users are the only proven approaches I know that reliably help teams take the first step toward frontend's first and highest calling: a web that's truly <a href="https://www.youtube.com/watch?v=UMNFehJIi0E">for everyone</a>.</p>

+ 4
- 0
cache/2021/index.html Просмотреть файл

@@ -153,6 +153,8 @@
<li><a href="/david/cache/2021/46b31e34a075d66aa6e4b8d8c91bd535/" title="Accès à l’article dans le cache local : Almost a third of recovered Covid patients return to hospital in five months and one in eight die">Almost a third of recovered Covid patients return to hospital in five months and one in eight die</a> (<a href="https://www.telegraph.co.uk/news/2021/01/17/almost-third-recovered-covid-patients-return-hospital-five-months/" title="Accès à l’article original distant : Almost a third of recovered Covid patients return to hospital in five months and one in eight die">original</a>)</li>
<li><a href="/david/cache/2021/d3a653c926aa97707653300947b65ab5/" title="Accès à l’article dans le cache local : The Mobile Performance Inequality Gap, 2021">The Mobile Performance Inequality Gap, 2021</a> (<a href="https://infrequently.org/2021/03/the-performance-inequality-gap/" title="Accès à l’article original distant : The Mobile Performance Inequality Gap, 2021">original</a>)</li>
<li><a href="/david/cache/2021/78f2e167938eb4bfa6747503aefe45c1/" title="Accès à l’article dans le cache local : We Quit Our Jobs to Build a Cabin-Everything Went Wrong">We Quit Our Jobs to Build a Cabin-Everything Went Wrong</a> (<a href="https://www.outsideonline.com/2415766/friends-diy-cabin-build-washington" title="Accès à l’article original distant : We Quit Our Jobs to Build a Cabin-Everything Went Wrong">original</a>)</li>
<li><a href="/david/cache/2021/28242a5ba209770efabfdbe5a6718719/" title="Accès à l’article dans le cache local : Des chasseurs massacrent sadiquement des sangliers à l’arme blanche">Des chasseurs massacrent sadiquement des sangliers à l’arme blanche</a> (<a href="https://reporterre.net/Des-chasseurs-massacrent-sadiquement-des-sangliers-a-l-arme-blanche" title="Accès à l’article original distant : Des chasseurs massacrent sadiquement des sangliers à l’arme blanche">original</a>)</li>
@@ -205,6 +207,8 @@
<li><a href="/david/cache/2021/75d7cccf22ce15ad026621e8e753d65b/" title="Accès à l’article dans le cache local : Comment fonctionne une centrale nucléaire ?">Comment fonctionne une centrale nucléaire ?</a> (<a href="https://couleur-science.eu/?d=268bbb--comment-fonctionne-une-centrale-nucleaire" title="Accès à l’article original distant : Comment fonctionne une centrale nucléaire ?">original</a>)</li>
<li><a href="/david/cache/2021/45af171610f986077420b27c2da46ec1/" title="Accès à l’article dans le cache local : I bought 300 emoji domain names from Kazakhstan and built an email service">I bought 300 emoji domain names from Kazakhstan and built an email service</a> (<a href="https://tinyprojects.dev/projects/mailoji" title="Accès à l’article original distant : I bought 300 emoji domain names from Kazakhstan and built an email service">original</a>)</li>
<li><a href="/david/cache/2021/0c6966a8e9543b52c361ac6de68f08e4/" title="Accès à l’article dans le cache local : Understanding ProRAW">Understanding ProRAW</a> (<a href="https://blog.halide.cam/understanding-proraw-4eed556d4c54" title="Accès à l’article original distant : Understanding ProRAW">original</a>)</li>
<li><a href="/david/cache/2021/aeb0a60038b91bf1fbbbd39b358366fb/" title="Accès à l’article dans le cache local : ☕️ Journal : Statu quo">☕️ Journal : Statu quo</a> (<a href="https://oncletom.io/2021/01/05/statu-quo/" title="Accès à l’article original distant : ☕️ Journal : Statu quo">original</a>)</li>

Загрузка…
Отмена
Сохранить