Caching Strategies (APCu, Redis, Memcached)
debt(d7/e5/b5/t7)
Closest to 'only careful code review or runtime testing' (d7). The detection_hints list laravel-debugbar, clockwork, and blackfire — these are profiling/observability tools that require deliberate instrumentation and manual inspection rather than automated lint or compiler feedback. Missing cache usage or stale cache bugs do not surface until runtime under realistic load, and even then the symptom (slow response or wrong data) may not be immediately attributed to caching.
Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix describes a cache-aside pattern with Redis or APCu, but common_mistakes reveal that fixing caching problems properly requires: reconsidering TTLs per data type, identifying the right caching layer, adding graceful cache-miss fallbacks, and addressing invalidation logic. This is not a single-line swap — it typically touches service classes, repositories, and configuration files across one or more components.
Closest to 'persistent productivity tax' (b5). The term applies_to web, cli, and queue-worker contexts, meaning caching decisions ripple across multiple execution contexts. Cache invalidation strategy, TTL choices, and cache-aside patterns must be understood and respected by every developer touching data-fetching code. However, it does not fully define the system's shape — it is a recurring tax rather than an architectural constraint.
Closest to 'serious trap' (t7). The misconception field states explicitly: 'Caching always makes things faster' — but stale cache, cache stampedes, and over-caching can make things slower or silently incorrect. This contradicts the intuitive expectation that adding a cache is a safe, purely additive optimisation. Developers familiar with basic caching may not anticipate invalidation failures or stampede conditions, making this a serious cognitive trap.
Also Known As
TL;DR
Explanation
Caching strategies include: in-process caching (APCu, OPcache for bytecode), distributed caching (Redis, Memcached for shared state across servers), HTTP caching (ETags, Cache-Control headers for browser/CDN caching), and database query result caching. Key cache design decisions are TTL (time-to-live), invalidation strategy (TTL expiry vs. explicit eviction), cache stampede prevention (probabilistic early expiry, locking), and what to cache (expensive queries, rendered fragments, API responses). Cache invalidation is famously one of the two hard problems in computer science.
Diagram
flowchart LR
REQ[Request] --> CHECK{Cache hit?}
CHECK -->|HIT| RETURN[Return cached<br/>response O 1]
CHECK -->|MISS| DB[(Database<br/>or API)]
DB --> STORE[Store in cache<br/>with TTL]
STORE --> RETURN2[Return response]
subgraph Cache Layers
L1[Browser cache]
L2[CDN edge cache]
L3[App cache Redis]
L4[DB query cache]
end
style RETURN fill:#238636,color:#fff
style L1 fill:#238636,color:#fff
style L4 fill:#1f6feb,color:#fff
Common Misconception
Why It Matters
Common Mistakes
- Caching everything without considering cache invalidation — stale data is often worse than no cache.
- Using the same TTL for all data regardless of how often it changes — user sessions and product catalogues have very different staleness tolerances.
- Not caching at the right layer — caching a slow SQL result but not the rendered HTML misses bigger gains.
- Forgetting to handle cache misses gracefully — if the cache server is down, the app should still work.
Code Examples
// No caching — expensive DB query on every request:
function getDashboardStats(): array {
return $db->query('SELECT COUNT(*), SUM(total) FROM orders WHERE ...')->fetch();
// Called 1000 times/min — same result every minute
}
// With caching:
function getDashboardStats(): array {
return apcu_fetch('dashboard_stats', $ok)
?: tap(expensiveQuery(), fn($r) => apcu_store('dashboard_stats', $r, 60));
}
// Cache-aside pattern with PSR-6
$item = $cache->getItem('user:' . $id);
if (!$item->isHit()) {
$user = $this->db->fetchUser($id); // expensive
$item->set($user);
$item->expiresAfter(300); // 5 min TTL
$cache->save($item);
}
return $item->get();
// Cache invalidation on write
public function updateUser(User $user): void {
$this->db->save($user);
$this->cache->deleteItem('user:' . $user->id); // invalidate
}