Essay

Old Data in a Performance Costume

4 min read
The Diagnosis

Your System Has No Memory

Sometimes a system is not slow because users are asking too many different things. Sometimes it is slow because users are asking the same thing, and the system keeps doing the same work again and again like it has no memory. That is Problem #2: Too Much Repeated Work. It happens when many users ask for the same or mostly same answer, but the system keeps calculating, fetching, formatting, or building that answer repeatedly. Very hardworking. Also very unnecessary.

The general solution is simple: save the answer once, reuse it many times, and decide when that saved answer should no longer be trusted. That is caching in plain English. If the answer is reusable, store it somewhere fast and return the stored answer next time instead of doing the same work again. But before we throw a cache at the problem and call ourselves architects, we need to ask three questions: Can we cache it? Where should we cache it? When should we kill the cache?

Question One

Can We Cache It?

  • Cache It

    Shared, stable, expensive, safe to be slightly old

    A product description is a good example because many users see the same description, and it usually does not change every second.

  • Don't Cache It (or Cache Very Carefully)

    Personal, sensitive, money-related, dangerous if stale

    A bank balance is a good example because showing an old balance is not a 'performance optimization'; it is a support ticket wearing formal clothes.

Question Two

Where Should We Cache It?

Once we decide that an answer can be cached, we need to choose where it should live. The cache can sit at different distances from the user: browser → CDN → memory → disk/storage. The closer it is to the user, the faster it is. But control usually moves in the opposite direction: the closer it is to the user, the harder it is for us to update, expire, or debug.

  1. Browser Cache

    Browser cache is useful for static files like images, CSS, JavaScript, fonts, and logos. It is very fast because the browser can reuse files without asking the server again. The accepted side effect is that once something is cached inside the user's browser, it is harder to force-refresh immediately. The usual fix is versioned file names, like app-v2.js, so the browser fetches a new file when the content changes.

  2. CDN Cache

    CDN cache is useful for public content like images, videos, static files, public pages, and sometimes public API responses. It stores content near the user, so the request does not need to travel halfway across the planet like it is on a spiritual journey. The accepted side effect is that the CDN may serve old content after the source changes. Systems handle this with TTL, cache purging, or versioned URLs.

  3. Memory Cache

    Memory cache is useful when our own system needs very fast access to reusable data. This can be local memory inside one running service, or a shared memory cache used by many replicated services. The accepted side effect is that local memory can become inconsistent across replicas, while shared memory cache adds another system to operate, monitor, and blame during outages.

  4. Disk / Storage Cache

    Disk or storage cache is useful when the saved result is heavier, more durable, or expensive to calculate again. This includes prepared results, precomputed files, search indexes, database tables, or materialized views. The accepted side effect is that this data is usually slower than memory and may not be perfectly live. For dashboards and reports, this is usually fine. For bank transfers, please do not get creative.

Question Three

When Should We Kill the Cache?

In real systems, these options are often used together. We may use TTL as a simple safety net, event-based invalidation for fresher data, and extra patterns like background refresh or stale-while-revalidate to make the user experience smoother.

  • Time-Based Expiry (TTL)

    Keep it for a fixed time, then delete or refresh

    This is simple and works well when data changes slowly or slight staleness is acceptable, like blog pages, product descriptions, images, or rating summaries. The accepted side effect is that users may see old data until the TTL ends.

  • Event-Based Invalidation

    Delete or update the cache when the source changes

    This is useful when freshness matters, such as product price, stock, homepage banners, or profile updates. The accepted side effect is complexity because one data change may affect many cached answers.

A product price may appear on the product page, search results, category pages, wishlist, cart preview, and some random festival widget nobody wants to touch.

Some systems also refresh cache in the background or serve stale data while refreshing it, but these are not separate ways to kill the cache. They are design patterns that make TTL and invalidation easier to use without making users wait. The accepted side effect is that we need extra workers, retries, scheduling, and monitoring. The work did not disappear; it just got a new address.

In The Wild

This Pattern Appears Everywhere

On a news website, the homepage is requested by many users and is mostly public. The top headlines, images, article previews, and category sections can be cached at the CDN and system level, while static files can be cached in the browser. The homepage may use a short TTL, while breaking news may trigger event-based invalidation. This works because the site needs to be fast, but it does not need to rebuild the entire homepage for every visitor.

On an analytics dashboard, the expensive work is usually aggregation. The system may need total sales, orders per hour, revenue by category, top products, and conversion rates. Calculating these from raw data every time is expensive, so the system precomputes the results and stores them as prepared data. The accepted side effect is that the dashboard may be slightly behind real time, so showing "Last updated 2 minutes ago" keeps the delay honest instead of mysterious.

On a food delivery app, many users in the same area may ask for nearby restaurants. Restaurant names, images, cuisine, ratings, and base menu can be cached, while delivery time, distance, surge fee, current availability, and personalized offers may need fresh calculation. CDN can serve images, memory cache can store nearby restaurant lists, and short TTL or event-based invalidation can handle availability changes. This works because thousands of users in the same area should not force the system to calculate the full restaurant list from scratch every time.

On an e-commerce product page, the common parts like title, images, description, specifications, and rating summary can be cached, while personal parts like delivery estimate, cart status, wishlist status, and personalized offers must be calculated separately. This lets the system reuse the common work and compute only what is unique for the user.

The Framework

Three Questions, Every Time

So the full solution is not "use cache." That is too vague, and also how many bad architecture diagrams are born. The real solution is to ask three questions:

  1. Can we cache this answer?

    Is the answer shared, stable enough, expensive to produce, and safe to be slightly old?

  2. Where should we cache it?

    Browser, CDN, memory, or disk — pick the layer that gives the right balance of speed and control.

  3. When should we kill or refresh it?

    TTL, event-based invalidation, or a combination — make freshness a conscious decision.

The Cost

Caching Is Not Free

Caching reduces repeated work, but it is not free. The tradeoff looks like this:

  • It gives you speed, but you pay with stale data.
  • It gives the database breathing room, but you pay with extra debugging.
  • It gives better performance, but you pay with more moving parts.
  • It gives you a saved answer, but you pay with another place where data can disagree.

The final mental model is simple: if too many users ask the same question and the answer is reusable, cache it in the place that gives the right balance of speed and control, then clearly define when that cache should die. Cache the repeated work, accept the cost, and make freshness a conscious decision instead of a lucky accident.

A cache without an expiry plan is not optimization; it is just old data wearing a performance costume.

Pankaj Sarda

Engineering Leader

Building systems in bits, atoms, and books. Bridging high-scale software infrastructure and real-world operations.

Read full profile