After a successful write, when would you patch the cached entry from the response instead of invalidating it and refetching?
answer
- does the response cover everything changed?
- counts, ordering, pages, other entities
- patch what it states, invalidate what it cannot
- scope invalidation by name, not by prefix
- never patch from the request body
basics
~20 sPatch when the response carries the complete updated form of exactly what changed and nothing derived elsewhere depends on it. Invalidate and refetch when the write moves counts, ordering, pages or other entities, or when its response says nothing useful.
solid answer
~50 sPatching from the response is cheaper and steadier: no extra round trip, no flash, and the entry the user is looking at becomes correct immediately. It is only sound when the response is the full updated form of that entry and the write has no effects the client cannot see. Writes usually do have such effects — a total, a sort position, which page an item falls on, a permission, an aggregate on another screen — and then invalidation is the honest answer: mark the affected entries stale and let the ones with live readers refetch. The real skill is scoping it. Invalidating a broad group of keys after every small write turns one activation into a burst of requests. A good default is to patch the entry you wrote and invalidate narrowly for the things you cannot compute.
go deeper
Learn the two options by name: use the response to update the copy you hold, or mark it stale so it is fetched again. Knowing that both exist is most of the answer at this stage.
Explain the deciding question — whether the response describes everything the write changed — and give the usual counter-examples: totals, sort position, pagination, other entities.
Diagnose the request burst. Show how you scope invalidation by naming affected keys, defer entries nobody is reading, and coalesce a run of writes into one revalidation.
Make it a convention rather than a per-feature habit: who decides what a write invalidates, how that is reviewed, and how you keep the fan-out visible before it becomes a load problem.
## Two ways to be consistent after a write A write succeeds. The cached copy the view renders is now, at best, one change behind the server. There are two mechanisms for closing that gap, and mature data layers use both: 1. **Patch from the response.** Take the representation the write returned and write it into the cached entry for that thing. No new request; the screen is consistent as soon as the response lands. 2. **Invalidate and refetch.** Mark the entries the write could have affected as no longer trustworthy, and let the ones with live readers fetch again. Extra requests; consistency comes from the server rather than from your reasoning. The choice is not stylistic. It follows from one question: *does the response contain everything the write changed?* ## What a response can and cannot tell you A write's response typically describes the entity it wrote. It usually does not describe: - **counts and aggregates** — a badge, a total, a group header computed over rows the client never loaded; - **ordering and pagination** — the item may now belong on a different page under the server's sort, and a list cached page by page cannot be repaired by editing one element; - **other entities** — archiving a project may have touched its members, its activity feed, a dashboard summary; - **authorisation effects** — what the caller may now see or do; - **anything the server derived** that the response body happens to omit. So the reliable test is: patch what the response states, invalidate what it cannot state. ## The comparison | approach | cost | correct when | failure mode | | --- | --- | --- | --- | | patch from the response | none beyond the write | the response is the full updated entity and nothing derived depends on it | silent divergence — a total or a position stays wrong until something else refetches | | invalidate and refetch | one or more extra requests | the write has effects the response does not describe | refetch bursts, and a brief flash if the entry is re-read from scratch | | patch, then invalidate narrowly | one extra request, off the critical path | most real writes | none, if the invalidation is actually scoped | The third row is the working default: the entry the user just changed updates instantly from the response, and the handful of derived things you cannot compute are marked stale so they correct themselves. ## Scoping the invalidation Broad invalidation is where post-write behaviour degenerates. A write that invalidates a whole family of keys makes one activation fan out into every list, counter and detail entry in that family — and on a screen where the user edits rows quickly, those bursts overlap. 1. **Name the affected keys deliberately.** Write down what the change actually influences and invalidate that, rather than reaching for the nearest broad prefix. 2. **Let readership decide urgency.** An invalidated entry with no live reader does not need a request now; it needs to be refetched the next time something reads it. 3. **Coalesce.** If the user is firing writes in a row, one revalidation after the last is worth more than one per write, and it is also more likely to be correct. 4. **Prefer computing what you can.** A count the client can adjust with confidence does not need a request; a count derived from data the client never had does. ## The empty response Some writes answer with nothing. There is then no reconciliation material, and two honest options remain: invalidate the affected entries, or keep the optimistic value knowing the server never confirmed the details. Patching from the **request** payload instead is the tempting third option and the wrong one — it re-asserts exactly the client's guess, including whatever the server normalised, defaulted or recomputed, and it hides the divergence behind a value that looks authoritative. ## A default policy worth stating in an interview - Patch the entity you wrote, from the response, whenever the response gives you the whole thing. - Invalidate, narrowly and by name, the derived and cross-entity things you cannot compute. - Never patch from the request body; that is a guess wearing a response's clothes. - Where a write returns nothing and changes something derived, one scoped refetch is a fair price for a consistent screen. That policy also answers the question interviewers usually ask next — why the page fires a dozen requests after one click. It is almost always an invalidation whose scope was chosen by convenience rather than by what the write actually changed.
- How do you keep a post-write invalidation from firing a burst of refetches?Invalidate named keys rather than a broad family, let only entries with live readers refetch immediately and leave the rest to be read on demand, coalesce a run of writes into one revalidation at the end, and compute locally whatever you can compute confidently. Scope is the lever; the burst is almost always an invalidation chosen for convenience.
- What do you do when a write's response returns only part of the entity?Patch exactly the fields it states and treat the rest as unknown rather than cleared — merging a partial body over a full entry is how fields silently become empty. If the omitted fields matter to what is on screen, mark that entry stale so it is refetched whole rather than assembled from a fragment.
- Why is patching the cache from the request payload worse than patching from the response?Because the request is the client's proposal and the response is the server's record of what happened. Servers trim, coerce, default and derive; patching from the request re-asserts the guess and gives it the authority of a confirmed value, so the divergence stays invisible until an unrelated read finally disagrees.
saying these in an interview costs you the question
- Always invalidate everything after a write; correctness first.
- A write's response always contains the full updated entity.
- Patching from the request payload is as good as from the response.
- Invalidation is free because the cache is local.
- A write with an empty response needs no follow-up read.