Optimistic UI Is Not the Side Effect
Optimistic UI is not the side effect
Optimistic state is a promise that the system accepted the user's intent. It is
not the thing the user asked to happen.
That distinction matters most when the effect is physical or externally
observable: sound stopping, money moving, a file deleting, a door unlocking, a
device changing state. The screen can update instantly and still feel broken if
the real-world effect waits behind a slow remote service.
The rule
If the side effect can happen locally, do it on the hot path. Reconcile with the
remote authority after.
Optimism should make the interface honest about intent while the authoritative
state catches up. It should not become a substitute for the side effect itself.
If the user pressed pause, the audio needs to stop. A paused icon is not enough.
Spotuify example
In Spotuify, the daemon already emitted optimistic playback events. That
fixed part of the interface: the TUI could show paused immediately when Space
was pressed.
The bug was that audio could keep playing for seconds while the real transport
command waited behind Spotify Web API work and player-actor queueing. The UI
was optimistic, but the audible side effect was not.
The shipped fix made the side effect hot too:
- freeze the effective playback command before applying optimistic state
- emit the daemon-owned optimistic playback event
- send play/pause/next/previous/seek/volume through the embedded player's fast
local transport lane - let the background Spotify mutation persist and reconcile the result without
replaying commands that already went local
That is the important shape. The UI can be optimistic, but the local side effect
still needs its own priority path.
The next playback bug added a guardrail: a fast local side effect still has to
be based on valid state. Space should not send a local resume when the daemon
snapshot has no item, or when the track has already reached its duration. In
that case, the truthful action is to start the selected context and publish the
new queue state. See Context Playback Must Publish Queue Truth.
Design check
Ask two questions for every optimistic mutation:
- What visible state should change immediately?
- What actual side effect must happen immediately for the action to feel true?
If those answers point to different systems, both systems need a hot path. A
central optimistic funnel is useful, but it cannot make a slow downstream actor
fast by itself. That is Priority Lanes Need Downstream Isolation in user
experience form.