Your State Management Design Fails the Moment Two Screens Disagree
You walk into the round feeling good. The interviewer says, design a dashboard with filters, a table, and a chart. You draw three boxes, name a store, and say "single source of truth" with great confidence. Then the interviewer asks one quiet question, and the whole drawing falls over.
"What happens when the table says paid and the header still says unpaid?"
That is the real question. It was never about which library you picked. It was about who owns each piece of state, and what happens when two parts of the screen disagree.
Most candidates answer a storage question when asked an ownership question. Redux, Zustand, Context, a signals library, it does not matter. A library tells you where state lives. It does not tell you who is allowed to change it, who has to hear about the change, or what wins when two writers collide. A global store can still ship a UI that lies, when three components each keep their own copy of the same fact.
Senior engineers start with the argument, not the library. Every piece of state has an owner, and only the owner writes it. Everyone else reads it or asks for a change. That one rule kills a whole class of bugs.
Take the dashboard. The filter is not "component state" just because a dropdown renders it. If the URL holds the filter, a refresh, a shared link, and the back button all agree. The table rows are server state, cached locally, never edited as if the cache were the truth. The chart keeps no copy. It derives from the same rows, so it cannot drift.
This is the angle interviewers listen for. They do not care whether you can recite the difference between client state and server state. They care whether you can spot the state that should not exist at all. A count derived from a list is not state. A total derived from a cart is not state. A flag in three places is one piece of state with three liars claiming to own it. Delete the copies, keep the derivation, and half your sync bugs disappear.
Here is the artifact to take into your next round. For every piece of state on the whiteboard, fill in this five line card before you move on:
Owner: who is the single writer.
Writers: who may ask for a change, and through what action.
Readers: who renders from it, and do they read the owner or a copy.
Invalidation: what event makes it stale, and who notices first.
Conflict rule: when two writes arrive, what wins, and what does the loser see.
Run the dashboard through it. Filter state: owner is the URL, readers are the table and the chart, conflict rule is last URL wins and everything re-derives. Table rows: owner is the server, invalidation is a refetch or a mutation response, conflict rule is server wins and the cache shows loading, not old data dressed up as new. For an optimistic update, the owner is still the server. The UI shows a predicted value, marked pending, with a rollback when the server says no. If you cannot fill in the conflict rule, you have a demo, not a design.
Notice what this does to the interview. You stop defending a library and start narrating decisions. "I am putting this in the URL because sharing and refresh have to agree." "I am not storing this total, I am deriving it, because a stored total goes stale." "If the mutation fails, this row rolls back and the user sees why." Each sentence is a trade-off with a reason, and that is what gets scored.
I turned the full 60-question drill set into The Frontend System Design Interview Playbook ($19): https://bittalk.gumroad.com/l/frontend-interview-playbook. It has a drill for exactly this move, naming the owner before you name the tool, plus fifty nine other traps like it.
Next time you practice, do not start by picking a store. Start by finding the two screens that could disagree, and decide, out loud, who wins. That is the answer the interviewer was waiting for.
Top comments (0)