The screenshot hides most of the work

Calling frontend work button colors and alignment describes a small part of what ships. Those details matter: a control needs to look usable and fit on the screen. But a screenshot cannot show whether a late response replaces the wrong results, whether Back restores a search, or whether a failed save quietly leaves the interface lying to its user.

I think frontend work should be treated as application engineering because that is what these problems require. The browser holds state, talks to services over an unreliable connection, and keeps accepting input while earlier work is unfinished. Decisions about what can happen next determine whether the application is correct.

A successful response can still be wrong

Suppose the request for 'invoice' starts, then the person changes the query to 'invoice overdue'. The second request finishes first. If both responses are allowed to replace the visible list, the older response can overwrite the newer one. Both HTTP requests succeeded. The application still produced an incorrect result.

The rule is straightforward: a response may update the visible results only if it still belongs to the active query. An AbortController can cancel a superseded fetch. A request identifier or an equivalent stale-result guard can prevent obsolete work from being applied. React's effect documentation illustrates this with cleanup that ignores a response after its request is no longer relevant.

Debouncing reduces how often a search starts; it does not establish which result is current. Cancellation also does not undo a server operation that has already happened. These are separate responsibilities, and the implementation needs to account for them separately.

A cache and a Back button need rules

A cache entry called 'issues' is too vague if results depend on the project, status, query, and page. The cache key needs those distinctions, plus the relevant account scope. Otherwise a fast cache hit can show the wrong list. Switching accounts also needs an explicit policy for clearing or separating cached data.

Returning from an issue detail page raises another choice: show the cached list immediately, wait for fresh data, or show the cached list while refreshing it. Each can be reasonable. If background refresh fails, the interface should distinguish previously loaded results from a search that returned no results.

Browser history is part of this design. The History API offers pushState to add an entry and replaceState to update one; popstate lets an application respond to traversal. A router may manage the mechanics, but the product still needs to decide which changes deserve an entry and what state to restore. Pressing Back after reading an issue should not force someone to reconstruct their search.

The difficult part of optimism is failure

Now let the person close an issue from the Open list. Removing the row immediately can make the action feel responsive. Until the server confirms it, though, that disappearance represents a pending operation. The client needs to remember enough to reconcile success or recover from failure.

Restoring a snapshot of the entire list on failure is dangerous if another issue changed in the meantime. It can erase newer successful work. Track the pending mutation by issue and operation, then reconcile it against the current state. If the person closes and reopens the same issue quickly, decide whether to serialize those operations or use a version-aware conflict policy. Arrival order alone is a poor substitute.

A timeout adds ambiguity: the server may have accepted the write even though the response never reached the browser. Blindly retrying an operation that sends a notification or creates a record can repeat the side effect. Safe retries need an agreed API contract, potentially with an idempotency key, and a way to find the accepted result. A spinner cannot solve that contract.

Give the work the engineering attention it needs

These concerns overlap with backend engineering: concurrent operations, cache invalidation, retries, and consistency. The responsibilities differ. The server must enforce authorization on every request and protect the stored data. Hiding a Close button in the browser cannot enforce permission. The client must then explain rejected or conflicting operations without pretending they succeeded.

I would review this issue list by making the first search finish last, failing a write after another succeeds, and navigating Back during a pending request. I would also check that keyboard focus survives a disappearing row and that failure is communicated accessibly. Those tests exercise the behavior someone depends on while doing their work.

Frontend engineering deserves time for these decisions in estimates and code review. A team that reviews only the rendered screen has reviewed only part of the feature. The search is finished when its state remains understandable through the interactions the application actually allows.

Sources & further reading

Technical references checked on 17 September 2026.

  1. MDN: AbortController
  2. MDN: Working with the History API
  3. React: useEffect, fetching data with Effects
  4. OWASP: Authorization Cheat Sheet
← Back to articlesSend me a note ↗