Every lesson in this domain so far has assumed caching is the right call and gone deep on doing it well. This one is the other half: the specific, recurring ways teams reach for a cache where it actively makes things worse, not just unnecessary.
3 min read
cache.set(f"live_stock_price:{ticker}", price, ttl=300) # price changes every secondCaching something that's written (or meaningfully changes) as often as it's read provides no real benefit — the cache is almost never actually serving a "hit" that saved real work, because the underlying value has usually already moved on by the time anything reads the cached copy. System Design's own caching lesson named this directly: caching pays off specifically for data read far more often than it changes, and a live stock price, a real-time inventory counter during a flash sale, or a constantly-updating counter are the cases that principle rules out, not edge cases it overlooks.
A cached "user's total order count" that has to be invalidated on every place an order can be created, cancelled, or refunded is a real liability: miss invalidating it from even one of those code paths (a new feature added later, a background job nobody remembered updates this too), and that one cached value silently drifts from the truth indefinitely, with nothing anywhere flagging that it's wrong. The more independent write paths can affect a cached value, the higher the real risk that one of them eventually gets missed — this is the cache-invalidation half of "there are only two hard problems," made concrete.
A cache can make a badly-indexed, slow database query look fast on every cache hit — and completely hide the fact that the underlying query is a real performance problem, until the exact moment the cache misses (a deploy, a flush, a cold key) and that slow query hits production traffic directly, unmitigated. Reaching for caching as the first fix for slowness, before checking whether a proper index (Databases & SQL's own indexing lesson) or a query rewrite would fix the actual root cause, trades a real, fixable problem for a hidden one that resurfaces unpredictably later.
Caching a per-user result under a key that doesn't actually include enough to distinguish users (forgetting to include a locale, a permission level, or the user ID itself in the cache key) can serve one user's personalized or permissioned data to a completely different user — this is the same cache-key-as-a-naming-problem System Design's caching lesson raised, but surfacing here as a genuine data-leak risk, not just a "wrong content" bug.
The right question before adding any cache, for any piece of data, is concrete: is this read far more often than it's written, is its invalidation story actually simple and complete, and would a stale or wrong cached value here be a minor inconvenience or a real incident? Data that fails any of these isn't automatically off-limits for caching — but it needs a deliberately chosen, narrower TTL, explicit invalidation, or outright exclusion, rather than being wrapped in the same default cache-aside helper used for everything else in the codebase without a second thought.
Check your understanding
A quick comprehension check — not tracked, not graded, just for you.
1. Why does caching a live, constantly-changing value (like a real-time stock price) provide little benefit?
2. What's the real risk of caching a value with many independent write paths that must each remember to invalidate it?
3. Why is using a cache to make a badly-indexed slow query "feel fast" a real anti-pattern?
Caching Strategies