Caching is hard.
-
Caching is hard. It's so hard. But also, we are so fucking bad at it. Every time I have to use a public wifi setup I have a joker moment.
Does absolutely nobody test shit on anything less than wired symmetric gigabit anymore?
Web SPA apps are some of the worst for this. Motherfucker, you have the same fucking iconography for three years, why does it load correctly and then ALL OF THE ICONS FAIL ONCE I DROP TO A SHIT INTERNET CONNECTION?!
I didn't even reload the page?! The fuck are you doing?
-
But seriously, caching is hard, it's really hard, but you can make life WAY easier for yourselves when building an SPA if you do this super simple thing.
Break down all your content into two axis:
1. push vs pull
2. owned vs userWhenever possible, turn your pull assets into push assets and all of your user assets into owned assets.
What do I mean by that? Let's break it down further
-
There's four categories:
1. Push + Owned
2. Push + User
3. Pull + Owned
4. Pull + UserI'm making up terminology but fuck it, I'm drinking coffee and eating my donut and doing this live at a coffee donut shop, fuk it.
Push means that the asset is pushed to a central server and then distributed.
Pull means the asset is referenced and the central server has to "pull" the content.
Owned means it's owned by the central server, user means it's user-submitted content.
Got it? Kewl
-
Every content caching strategy on the web fucks this up because the web isn't designed to handle this notion of push vs pull or user vs owned.
However, the web *is* designed extraordinarily well to handle the concept of pull + owned, and with service workers, it's also extremely equipped to handle push + owned.
So, make everything owned, and make it all push if possible, *especially* if it's an SPA.
-
Push + Owned:
Content is pushed to a central server and then distributed. And it's owned by the central server. This is ideal, because it means that your expiration time can be infinite. You only expire content on the client when explicitly told to.
Got that? You. Only. Expire. Content. On. The. Client. When. Told. To.
Make everything push + owned if you can. That means not returning a 304, it means not even trying the web request. Put that shit in STORAGE.
UI icons are the classic example.
-
It turns out, however, that you can make a shit ton of other stuff push + owned if you try a little harder.
User profile picture? If the user doesn't change their profile picture, it's guaranteed to be the same. Guess what fukers, expire the it on new upload but otherwise OWN IT. IT DOESN'T NEED TO BE RE-FETCHED.
Custom emojis n shit? Own them. Expire them only when they're changed.
"but Hazel how does the client check if they're expired?"
Use "stale while re-validate". You're welcome.
-
@hazelweakly
There was a joke, many years ago, that lisp programmers knew the value of everything and the cost of nothing.We took that joke and scaled it up to the size of the planet.
-
A very concise summary follows:
1. Push + Owned: store asset, stale while revalidate
2. Push + User: infinite TTL + hashed URL
3. Pull + Owned: infinite TTL + hashed URL
4. Pull + User: sensible semi-short TTL + stable URL -
Let's talk about Pull + User since that's the other weird pattern not covered by "standard caching how-to" guides on the internet.
That's where it's user generated content, but not owned by the server. Posting gifs into the chat is a prime example; linking a blog post and generating a media upload for that is another.
Guess what: this pattern fits for highly dynamic user-generated content, which means it's the content *users link to each other*
Stable URL, short TTL. YES, SHORT TTL
-
You would be absolutely fucking shocked how much traffic the pull + user generates. It's atrocious, but it's also extraordinarily cache hostile, and has a half life of minutes to hours.
You would also be shocked how much caching it will break assumptions on the behalf of users.
It breaks all of their assumptions. They're gonna change something and refresh the page and get mad when it doesn't update. All of your bug reports lie here.
Debounce + throttle? Sure. Micro-TTL? Yes.
Cache? Never
-
anyways long story short don't just give up because "lol caching is hard"
Understand your users and what the fuck you're doing, make a strategy that builds a mental model for your developers, and then make doing the right thing easy.
An amazing fetching interface would be
1. Push + Owned: storeAsset(URI)
2. Push + User: storeContent(URI)
3. Pull + Owned: loadAsset(URI)
4. Pull + User: loadContent(URI)Never seen anyone build that, never seen tests for this, but fuk me it would fix so much
-
Ok I made this into a blog post, you're welcome :ablobfoxbongo:
Cache Me Not, Cache Me, Cache Me Not | Hazel Weakly
Caching is hard. So hard. But also, we are so fucking bad at it. Every time I have to use a public wifi setup I have a joker moment. Does absolutely nobody test...
Hazel Weakly (hazelweakly.me)
-
Oliphantom Menacereplied to Hazel Weakly last edited by
@hazelweakly “Cache Me If You Can”