How do you decide which writes in a product get an optimistic update and which wait for the server?
answer
- two axes, not a preference
- can the client compute the result?
- what does the revert cost the user?
- frequency justifies the maintenance
- measure the rollback rate per write
basics
~20 sWeigh how predictably the client can compute the result against the cost of being wrong. Optimism fits reversible, self-contained, frequent changes; a write the server decides, or whose reversal would confuse or cost, should wait.
solid answer
~40 sI treat it as two axes rather than a preference. First, predictability: can the client compute the post-write state correctly on its own? A toggle or a rename it can; anything involving a generated identifier, a server-side total, an ordering or a permission decision it cannot, and a wrong prediction is a visible rollback. Second, the cost of being wrong: how confusing is the revert, and can the user act on the false state before it is corrected — navigate to an item that does not exist, or send a second change against it? Frequency then decides whether it is worth it at all: optimism earns its keep on changes made constantly, not on a once-a-day action. I also count the per-write patch and rollback code, and watch the rollback rate in production.
go deeper
Learn the question behind the choice: can the screen work out the result by itself, and how bad is it if the value has to change back? That is enough to argue either side.
Give concrete cases on each side and say why — a toggle versus a record whose identifier the server issues — and name the derived data a patch cannot compute.
Bring the failure evidence: reverts the user had already acted on, temporary identifiers escaping into follow-up writes, prediction logic drifting from a server rule.
Own the rule and the measurement. Tier the writes, state the retry boundary against the API contract, instrument the rollback rate, and be willing to spend on write latency instead of on prediction code.
## This is a policy question, not a per-feature one Optimistic updates are usually argued screen by screen, which is how a product ends up with half its writes instant, a quarter of them instant-but-wrong, and a scatter of bespoke rollback code nobody owns. The useful framing is a rule the team can apply without relitigating: **optimism is a prediction with a maintenance cost, and it is justified where the prediction is reliable and the revert is cheap.** ## Axis one: can the client predict the result? - **Yes, confidently** — a boolean flipped, a field replaced with text the user typed, removing an item from a list held in full. The client already knows the answer; the request merely records it. - **Only partly** — a change that also moves a count, a sort position, or a page boundary. The entity is predictable and its consequences are not, so optimism has to be paired with a scoped invalidation of what is derived. - **No** — anything whose outcome the server computes or decides: a generated identifier, a validation or authorisation verdict, pricing, an allocation from limited stock, anything two users contend for. Predicting these renders a value that was never true. ## Axis two: what does being wrong cost? | write | prediction | cost of revert | verdict | | --- | --- | --- | --- | | toggling a flag on a visible row | exact | a value snaps back with a message | optimistic | | reordering a list the client holds in full | exact | positions shuffle back | optimistic | | renaming an item | exact | the old name returns | optimistic | | creating a record the user then opens | identifier unknown | a dead link or a rejected follow-up write | wait, or hold navigation | | a payment, a booking, a destructive action | server-decided | the user believed something irreversible happened | wait | The column that decides most cases is the third. A revert the user can understand in place is a minor cost; a revert *after the user has acted on the predicted state* is a real defect, and the stronger the illusion, the more likely they act. ## The costs nobody budgets - **Code per write.** A predicted patch, a scoped rollback, reconciliation with the response, and the interleaving rules when two of them overlap — each with tests for the arrival orders that matter. - **A second model of the domain.** The client's prediction is a duplicate of a server rule, and it drifts when the server rule changes. - **Support load.** "It changed back" is a hard report to act on, because the screen looks correct by the time anyone sees it. - **Testing surface.** Failure and interleaving paths are exactly the ones that do not get exercised by clicking around. This is why a flat "be optimistic everywhere" is a weak answer: it buys perceived speed with a per-write maintenance obligation that nobody has sized. ## Retry, and the line you do not own A failed write is where the policy meets the API. Whether it may simply be sent again is not something the client can infer from the failure it saw — the request may have been applied before the connection broke. That promise, and how a caller is meant to make a repeated attempt safe, belongs to the endpoint's contract; the front-end decision is only whether to retry silently, offer the user the choice, or surface the failure and stop. Retry silently only where the contract says a repeat is harmless and the user would not want to know. ## Decide once, then measure 1. **Tier the writes.** A short house rule — optimistic for reversible, client-computable changes on data the user is looking at; pending state for everything server-decided or consequential — settles most arguments in review. 2. **Instrument the rollback rate.** Count optimistic patches that reverted, by write. A rate that is not near zero is evidence the prediction was wrong, not evidence that users need a better animation. 3. **Revisit with latency data.** If the median write is already fast, a plain pending state is often indistinguishable from optimism and costs nothing to maintain. ## The alternative investment The honest counterproposal to optimism is to make the write fast: a narrow response, less work on the critical path, a shorter round trip. That pays out for every write in the product, including the ones no one will ever patch locally, and it adds no client-side prediction to maintain. Optimism is the right tool for changes a user makes constantly on data already on their screen; for the rest, a truthful pending state and a fast server age much better.
- What signal tells you an optimistic write was the wrong choice in production?The rollback rate for that write. Patches that revert regularly mean the client was predicting something the server decides. Supporting signals: reports that a value "changed back", users acting on a predicted state — opening an item under a temporary identifier, sending a follow-up change against it — and rising contention between concurrent editors of the same entity.
- When is making the write faster a better investment than making it optimistic?When the round trip is already short, when the revert would be confusing or consequential, or when the prediction duplicates a server rule that keeps changing. Latency work benefits every write, including the ones nobody will hand-patch, and leaves no second copy of the domain logic in the client to maintain.
- How do you keep an optimistic write honest when the user can act on the predicted state?Constrain what the predicted state permits. Hold or re-point actions that depend on server-issued values, keep follow-up changes queued behind the write they depend on, and where neither is practical, show a pending state instead. An illusion the user can build on is no longer a rendering choice; it is a correctness problem.
saying these in an interview costs you the question
- Apply optimism everywhere; users always prefer instant.
- Optimism is free once the data layer supports it.
- A rollback is fine as long as it is animated.
- If a write can fail, never show it optimistically.
- Retrying a failed write from the client is always safe.