skip to content

In a UML state machine, what is the difference between a shallow and a deep history pseudo-state?

level: middleimportance: nice to knowfreq 18%

answer

  1. Resuming rather than restarting
  2. A marker that remembers the last substate
  3. One level down, or all the way down
  4. The first entry has nothing remembered
  5. H for one level, H-star for all

basics

~20 s

Shallow history remembers only which substate of its own region was last active. Deep history remembers the active configuration all the way down through every level of nesting. Both restore that memory when the composite state is re-entered.

solid answer

~40 s

A **history pseudo-state** is a marker drawn inside a composite state's region that records which substate was active when the region was last left. An arc that targets it resumes there instead of starting from the region's initial pseudo-state. **Shallow history**, written `H`, remembers one level: the substate of its own region, and if that substate is itself composite, the inner region restarts from its initial pseudo-state. **Deep history**, written `H*`, remembers the whole nested configuration, so every level resumes where it stopped. Neither is a state — the object never rests on the marker. On the very first entry there is nothing remembered, so control follows the history marker's default outgoing arc, or falls back to the region's initial pseudo-state.

code

pseudocode · 11 lines
pseudocode
composite PROCESSING
  region:
    (initial)  -> VALIDATING
    VALIDATING -> PRICING on validated
    composite PRICING
      (initial) -> RATING
      RATING    -> SURCHARGING on rated

PROCESSING -> SUSPENDED       on operatorHold
SUSPENDED  -> PROCESSING.H*   on operatorRelease   // resumes at SURCHARGING
// PROCESSING.H would resume PRICING but restart it at RATING

go deeper

for a junior

Know that a history marker inside a composite state means resume where we left off rather than start again, and that it is a marker the object passes through, not a state.

for a middle

Explain the one-level versus all-levels difference and say what happens on the very first entry, when the region has been exited zero times and nothing is remembered.

for a senior

Be ready to name the cost: behaviour now depends on where the machine has been, so tests must establish the prior path and a persisted object must store the remembered configuration.

for a principal

Weigh hidden state against explicitness. Argue when resuming is genuinely the requirement, and when modelling the suspension as visible substates is easier for a whole team to reason about.

## What a history pseudo-state records When a machine leaves a composite state, the region inside it forgets where it was: re-entering normally runs the region's initial pseudo-state and starts again from the beginning. That is right for a lifecycle and wrong for an interruption. If a long process is suspended and later released, restarting it from the first substate throws away everything it had progressed through. A **history pseudo-state** solves exactly that. It is a small marker drawn inside a composite state's region — `H` for shallow, `H*` for deep — that records the substate active at the moment the region was last exited. An arc targeting the marker means *resume where this region left off*. Two things to hold on to: it is a **pseudo-state**, so the object passes through it and never rests there, and it belongs to **one region**, so a composite with two orthogonal regions needs a marker in each if both are to resume. ## Shallow versus deep The two differ only in how far down the memory reaches. | | Shallow history (`H`) | Deep history (`H*`) | | --- | --- | --- | | Remembers | the last active substate of its own region | the last active configuration at every nesting level below it | | Nested composites | restart from their own initial pseudo-state | resume at their remembered substate | | Use when | only the top-level phase is worth resuming | the whole nested position must be restored | | Cost | cheap to reason about | the reader must trace every level to predict the target | With one level of nesting the two behave identically, and choosing `H*` there is a signal the author copied a pattern rather than made a decision. A worked shape from a freight-booking portal: `Processing` contains `Validating` and a nested composite `Pricing`, which itself contains `Rating` and `Surcharging`. An operator hold moves the booking to `Suspended`; releasing it targets the history marker. With shallow history the booking resumes in `Pricing` but restarts at `Rating`, silently repeating rating work. With deep history it resumes at `Surcharging`, exactly where the hold interrupted it. On that portal, holds landed on roughly one booking in twelve, so the difference was the repeated work of several hundred bookings a quarter — a real distinction, not a notational nicety. ## The first entry problem A history marker has nothing to remember until the region has been exited at least once. The notation handles this with a **default outgoing transition**: an arc drawn from the marker to a substate, taken when no memory exists. If no default is drawn, control falls back to the region's initial pseudo-state. A history marker with neither a default nor an initial pseudo-state in its region is ill-formed, and this is the detail candidates most often miss, because on a diagram the marker looks self-sufficient. ## Where history earns its keep - **Suspend and resume.** A hold, a pause, an operator interruption — anywhere the requirement is genuinely *carry on from where we were*. - **Recoverable interruptions.** A connection drop that returns to the same phase of a long interaction. - **Modal detours.** Entering a settings or override mode and returning to the previous position. ## What it costs History introduces **hidden state**. The target of a transition now depends on where the machine has been, not only on the current state and the arriving event, and that has three consequences: 1. **Testing gets more setup.** Two runs with the same external event sequence can land in different substates, so a test must establish the prior path before asserting the resume. 2. **Reading gets harder.** A reviewer tracing an arc into `H*` cannot say where control lands without knowing the earlier history of the object. 3. **Persistence gets a new obligation.** If the object outlives the process holding it, the remembered configuration has to be stored alongside the current state, or the resume is a fiction. The explicit alternative is worth naming in an interview: model the suspension as substates that carry the phase, so where you resume is written on the diagram rather than remembered by it. That trades diagram size for readability, and on a small machine it is often the better answer. ## Common misreadings - Treating the marker as a state the object waits in. - Expecting history to restore data values as well as the active configuration — it restores position only. - Assuming a marker works on the very first entry. - Believing history records the whole path travelled rather than the last configuration.

  • What happens when a transition enters a history pseudo-state before anything has been remembered?
    Control follows the marker's default outgoing transition if one is drawn, and otherwise falls back to the region's initial pseudo-state. A history marker with neither a default arc nor an initial pseudo-state in its region is ill-formed, because the machine has no defined target on that first entry. It is the detail most often missed, since the marker looks self-sufficient on the diagram.
  • Why can a history pseudo-state make a state machine harder to test and review?
    Because it introduces hidden state: the target of a transition now depends on where the machine has been, not only on the current state and the arriving event. Two runs with identical external events can land in different substates, so tests must set up the prior path, and a reviewer tracing the arc cannot predict the destination from the diagram alone. If the object is persisted, the remembered configuration has to be stored too.

saying these in an interview costs you the question

  • Thinks a history pseudo-state is a state the object rests in
  • Expects history to restore data values as well as position
  • Assumes a history marker works on the very first entry
  • Uses deep history where the composite has only one nesting level
  • Believes the marker records the whole path rather than the last configuration