Key Principle
Statechart design produces its benefits only when practitioners internalize a set of interlocking heuristics that span design, coding, debugging, and maintenance. No single rule is sufficient; the heuristics form a web where violating one (e.g., allowing inter-region dependencies) silently undermines the guarantees of others (e.g., change isolation). This reference collects the most consequential practical wisdom from across the book into a single checklist.
Why This Matters
The notation is learnable in hours; the judgment takes much longer. "Learning how to apply the notation to solve design problems is much more difficult" (Ch. 14). These rules of thumb encode the hard-won patterns that separate a statechart that functions as a trustworthy design tool from one that is "massive and yet offer little benefit" over procedural code (Chapter 8). Each rule addresses a specific failure mode observed in real designs.
When to Use Concurrency vs. Depth
- Concurrency solves the cross-product problem of independent controls. N binary controls produce 2^N sequential states; orthogonal regions collapse this to N. But independence is a precondition: the CD player offered "no opportunity to use concurrent parts" (Chapter 8).
- Depth solves the duplication problem. "Having duplicate states in a statechart is something to be avoided at all costs" (Chapter 8) -- one duplicate interacting with two others forces duplication of all three, producing six instead of three. Use a superstate + history.
- Decision rule: Independent features producing combinatorial states -- use concurrency. Shared behavior reachable from multiple contexts -- use depth + history.
Notation Economy
- Multi-event labels reduce clutter: list events separated by "or" on a single arrow. Each still maps to a separate event-action table entry (Chapter 8).
- Never combine multiple conditions on transient-state exits "because it would look like one condition" (Chapter 8) -- ambiguity between alternatives and conjunctions causes design errors.
- One state variable per concurrent region; one per hierarchy level (Chapter 13).
The No-Conditionals Rule
"State procedures always set the same attributes to the same values. In other words there should
be no conditional statements which could cause different attributes to be set" (Chapter 13). If
you find yourself writing an if inside a state procedure, the statechart is missing states --
you have hidden behavioral variation that was never designed. This rule turns coding into a
design-verification step: a conditional in a state procedure is a statechart defect detector.
Event Priority and Determinism
"If the same event with different conditions leaves a state, then only one of those conditions should evaluate to true at any given time. If this cannot be guaranteed, then the events should be prioritized to avoid non-deterministic behaviour" (Chapter 9). Guard conditions on same-event transitions must be mutually exclusive or explicitly ordered.
Debugging Strategies
- Log state variables on every event for a complete context trace. "It is easy to identify exactly which lines of code are executed in response to that event" because context is explicit and loggable (Ch. 14).
- Design-first debugging: Trace bugs in the statechart before touching code. "It is easier to modify the design of a statechart and then modify the code, than it is to modify the code directly" (Ch. 14).
Common Pitfalls
Inter-Region Dependencies
A condition (in state X) on an event arrow negates concurrency's value: "a sharp increase in
the number of test cases is required" (Chapter 9), side-effects propagate, and comprehension
collapses. The fix: merge dependent parts. Merging two 2-state regions produced exactly 4 states
and was "considerably easier to understand" (Chapter 9).
Duplicate State Cascades
"It is easy to think that having an extra state will not cause too many problems. However, a duplicate state can lead to a rapid increase in the number of states" (Chapter 8). Every state the duplicate touches must also be duplicated -- super-linear growth.
Actions on States as Global Variables
"Actions on states are like global variables. They can be very powerful, but they also have the potential to cause many problems" (Chapter 9). New transitions trigger entry actions inappropriately. The rule: "Use states to control the attributes of user interface items rather than executing actions. All actions should be associated with events" (Chapter 9).
Hierarchy-Jumping Transitions
Transitions that jump multiple hierarchy levels break the contract: "It should be possible to understand a statechart without having to understand the details of lower-level states" (Chapter 9). Restrict transitions to adjacent levels; use default start arrows for deep routing.
Maintenance Heuristics
- Change isolation: "If the actions that are executed in response to an event in a particular context are changed, then the actions executed in response to that event in all the other contexts will not be affected" (Ch. 14). This is the maintenance payoff of explicit context.
- Additive modification: "If the same event can occur in two different contexts and the resulting actions are identical, it is still strongly advised that the code for the two events are kept separate" (Chapter 13). Minor duplication is cheap; cross-context coupling is not.
- Formalize completely: "It is bad practice to define only part of the syntax, on the grounds that the rest of it is easy to code directly" (Chapter 8). Partial formalization breaks trust.
- Synchronize via simultaneous events, not dependencies: "When designing simultaneous events, typically only one event should cause actions to occur. The other events should be used to synchronize the concurrent parts with the primary event arrow" (Chapter 9).
- One controller per screen item: "A screen item should be controlled by precisely one part of a statechart" (Chapter 9). Split control across regions forces mental composition that scales badly.
Key Quotes
"Having duplicate states in a statechart is something to be avoided at all costs." -- Chapter 8
"Actions on states are like global variables. They can be very powerful, but they also have the potential to cause many problems." -- Chapter 9
"State procedures always set the same attributes to the same values. In other words there should be no conditional statements which could cause different attributes to be set." -- Chapter 13
"Writing user interface code is easy. Writing user interface code that can repeatedly be enhanced by different people over a long period of time, is very difficult." -- Ch. 14
"It is easier to modify the design of a statechart and then modify the code, than it is to modify the code directly." -- Ch. 14
Rules of Thumb
- Concurrency for independent controls; depth + history for shared behavior from multiple contexts
- If a state appears twice, consolidate immediately -- the cascade cost is super-linear
- If concurrent parts reference each other's internal states, merge them; accept the state count increase as the cost of clarity
- A conditional inside a state procedure signals a missing state in the design
- Keep actions on transitions, not on state entry/exit, unless truly unconditional for every path
- Separate event code by context even when behavior is identical, to prevent maintenance coupling
- Log state variable values on every event for complete debugging traces
- Restrict transitions to adjacent hierarchy levels; use default starts for deep routing
- One concurrent part controls one screen item -- never split control across regions
- Formalize all behavior in the statechart; partial formalization destroys trustworthiness
- Coordinate concurrent parts through simultaneous events, not structural dependencies
- Design changes precede code changes; update the statechart first, then modify the implementation
Related References
design-heuristics.md-- The design tests (completeness, reachability, dead states, determinism) that complement these heuristicsstandard-patterns.md-- The concrete patterns (transient states, parameterized alerts, history-based cancel) that these rules of thumb governcoding-statecharts.md-- Implementation-level rules including the no-conditionals rule and context isolation in codeevaluation-evidence.md-- The lifecycle evidence and 80-90% bug reduction claim that motivates these heuristics