Tech
Tech · ◉ Evergreen

Everything you cache is a bet that the world will hold still

by Shreyansh Ojha·5 min·Working Theory

There’s a famous line, usually credited to the engineer Phil Karlton: there are only two hard things in computer science — cache invalidation and naming things. It gets quoted as a joke. It’s actually a warning, and most of us learn why the hard way: we add a cache to make something fast, it works beautifully, and three weeks later a user is staring at a number that’s wrong and swearing the app is broken. The app isn’t broken. The cache is doing precisely what you asked. You just asked for something with a hidden cost you hadn’t priced in.

A cache is a copy you keep closer to hand than the real thing. The “real thing” — the database, the upstream service, the source of truth — is authoritative but slow or expensive to ask. So you keep a copy somewhere quick: in memory, at the edge, in the browser. The next time someone needs the value, you hand them the copy instead of making the round trip. That’s the whole trick, and it’s a spectacular trick: caching is one of the highest-leverage speed moves there is.

But look at what you actually did. The moment you made that copy, you created two versions of the truth — the authoritative one and the convenient one — and you took on a debt: keeping them in agreement. Every cache is, underneath, a bet that the source won’t change before you next look, or that you’ll notice when it does. The instant reality moves and your copy doesn’t, you’re serving stale data. The window between “the truth changed” and “the copy caught up” is the staleness window, and every design decision about a cache is really a decision about how long that window is allowed to be and who’s hurt if it opens.

source of truth value A value B truth changes what the user sees value A value B copy catches up the stale window
A cache splits the truth in two. The shaded gap — from "truth changed" to "copy caught up" — is the staleness you're choosing to allow. Original diagram · Working Theory

Once you see caching as managing a staleness window rather than making things fast, the standard tools stop being arbitrary jargon and become answers to one question: how do we close that window, and what does closing it cost?

The bluntest answer is a time-to-live — a TTL. You stamp the copy with an expiry: trust it for sixty seconds, then throw it away and re-fetch. TTLs are popular because they’re simple and they self-heal; even if you never explicitly tell the cache the truth changed, it forgets on a timer and re-asks. The cost is that a TTL doesn’t track reality, it tracks the clock. Set it long and you serve more stale data; set it short and you make more expensive round trips, which is the speed you were trying to buy back in the first place. The TTL is just you putting a price on freshness, in seconds.

The sharper answer is active invalidation: the moment the truth changes, you go and evict or update the copy on purpose. When it works, it’s the best of both — fast reads and fresh data, because the copy is corrected exactly when it’s wrong and not a moment later. The reason it’s on Karlton’s list of hard things is that knowing the truth changed is only half of it. You also have to know every place you stashed a copy — the server memory, the CDN edge, the other region, the user’s browser — and reach all of them, reliably, including the messy case where the value changes again while you’re still busy invalidating the last change. Miss one copy and you’ve got a stale value with no timer to save you, which is worse than a TTL because it may never self-correct. Active invalidation trades the TTL’s guaranteed-but-slow honesty for speed that’s only as good as your bookkeeping.

Which is the real lesson, and it’s a design lesson more than a technical one: the right amount of staleness is a per-value product decision, not a global default. A user’s account balance, a permission that was just revoked, the price at checkout — these tolerate almost no stale window, and they’re worth the cost of tight invalidation or no cache at all. An avatar, a follower count, a trending list, yesterday’s analytics — these can be minutes or hours stale and nobody is harmed, so a generous TTL is free money. The failure isn’t caching the balance or caching the avatar; it’s caching them the same way because “the cache” felt like one setting. Decide, value by value, how wrong you’re willing to be and for how long — and then the fast copy is a gift instead of a trap.

To look up: the 'two hard things' quip attributed to Phil Karlton; cache invalidation strategies (TTL/expiry, write-through, write-around, cache-aside / lazy loading); cache coherence and the freshness-vs-cost tradeoff. Standard engineering ground — the framing here (a cache as a managed staleness window, and a per-value product decision) is the editorial angle, not a novel claim.

Liked this? Get the next one in Working Theory.

Going weekly in August (it's in beta now). One genuinely interesting read on building, the brain, and the science most people missed.

Got a reaction, a counter-example, or something I missed? Reply by email — I read everything.
◉ join in

Where have you hit this — in a product you use, or one you're building?

Threads open here soon. For now, the conversation lives two clicks away — discuss on GitHub, or just reply by email. I read and answer everything.