Three flags disagree

A request fails, yet its success badge remains visible. Adding another flag will not resolve the ambiguity. Three independent flags for loading, success and failure permit eight combinations, including combinations your interface should never show.

布尔组合与合法状态字段对照 / One explicit state avoids contradictory combinations of boolean flags.布尔组合与合法状态字段对照 / One explicit state avoids contradictory combinations of boolean flags.
One explicit state avoids contradictory combinations of boolean flags.

Every caller inherits the job of interpreting those combinations. Future edits become guesswork for people and agents alike. Define the valid situations before choosing a library.

Start with a request table

Our example has four states. Predict what should happen if a success event arrives before any request starts. Here, the policy is to ignore that event and retain the current state.

Current stateAccepted eventNext state
idlesubmitloading
loadingresolve / rejectsuccess / error
errorretryloading
successresetidle

Events absent from the table leave state unchanged. A discriminated union can attach results only to success and an error only to error. A reducer centralises event handling; a state machine becomes useful when transitions need more structure.

Request states and transitionsA lifecycle diagram generated by Archify.Request states and transitionsidleloadingsuccesserrorsubmitresolveRepresentationUse a discriminated union, reducer or statemachine.Keep simple cases simple.Original exampleOur original request table; events absent fromit leave state unchanged.Only success carries results; only error carriesan error.loading → errorrejecterror → loadingretrysuccess → idleresetidle → success× resolve: illegal transitionIgnore the event; retain idle. Tests must catchearly success.
Model allowed transitions and test that forbidden transitions are rejected.

A simple request may need no dedicated library. You should still be able to name the current state and the events it accepts. A tool name cannot answer those questions for you.

I think I'm addicted to getting agents to build state machines

— Matt Pocock

What does the interface protect?

A request module should explain its results, failures and dependencies. Tests constrain its implementation. Callers should not need to understand cache keys or retry counters to use it correctly.

简单接口包住有价值的复杂度 / A deep module exposes a simple interface and hides useful complexity.简单接口包住有价值的复杂度 / A deep module exposes a simple interface and hides useful complexity.
A deep module exposes a simple interface and hides useful complexity.

John Ousterhout's deep-module concept concerns a simple interface that hides useful complexity. Neither splitting something into ten files nor squeezing it into ten lines establishes that quality.

Enforce dependency boundaries

Tools can reject imports that cross an architectural boundary. Types can describe domain failures explicitly. Effect is one of Matt's public preferences and a possible further study topic. This lesson does not cover it or recommend a universal migration.

Exercise: reject early success

TRY IT

Produce two kinds of evidence

  • Task: specify and enforce what idle does when it receives resolve.
  • Invalid path: it must not enter success or invent a result.
  • Normal path: submit shows loading; reject shows an error; retry can lead to success.
Suggested approach

The invalid event preserves idle. The normal sequence is idle, loading, error, loading, success. Check both the state and the visible interface.

Done means a test catches early success and a repeatable interaction demonstrates the normal path. Continue with implementation and feedback. The archived xstate-catalogue is a historical reference, with no promise of current API compatibility.

Quick reference

01

State

One tag names the phase; data belongs to that phase.

02

Transitions

List accepted events and a policy for every other event.

03

Interface

Callers depend on behaviour; tests constrain internals.

Sources

Unofficial, non-commercial study notes. No affiliation with or endorsement by Matt Pocock. Quoted works remain their authors’ copyright; MIT reuse retains its copyright and licence notices.