Statecharts: Hierarchische Zustandsmaschinen
(statecharts.dev)- Ein Format zur visuellen Strukturierung des Verhaltens komplexer Systeme, das die grundlegende state machine erweitert, um das Problem der State Explosion zu bewältigen
- Ermöglicht die Trennung von Verhalten und Komponenten, wodurch sich Verhalten leichter ändern und Code einfacher nachvollziehen lässt; außerdem eignet es sich gut für vom Komponentenmodell unabhängige Tests und die Erkundung von Ausnahmesituationen
- Beim Erstellen eines Statecharts werden alle möglichen Zustände durchlaufen, und es gibt Forschungsergebnisse, nach denen Statechart-basierter Code weniger Bugs aufwies als traditioneller Code
- Mit dem SCXML-Standard und Tools bzw. Bibliotheken für verschiedene Sprachen lassen sich Modelle lesen, schreiben und ausführen; das hilft auch dabei, die Reihenfolge von Abläufen wie entry/exit action korrekt zu behandeln
- Verwendet man ein ausführbares machine format, kann eine einzige Definition als Single Source of Truth dienen, sodass Laufzeitverhalten und Diagramm gemeinsam gepflegt werden und die Synchronisierung von Implementierung und Entwurf wichtig wird
Überblick über Statecharts
- Ein Statechart ist ein visuelles Format zum Umgang mit komplexen Systemen und eine Erweiterung der grundlegenden state machine
- Es wurde erweitert, um das mit wachsender state machine entstehende Problem der State Explosion zu bewältigen
- Zwar lässt sich Verhalten als Diagramm ausdrücken, in der Softwareentwicklung geht es dabei aber weniger um die Visualisierung selbst als um Verhaltensmodellierung und Strukturierung
- Weiterführende Grundlagen finden sich in What is a state machine? und What is a statechart?
Warum Statecharts verwenden?
- Sie bieten eine leicht verständliche Struktur und sind dadurch oft einfacher zu erfassen als viele andere Codeformen
- Sie ermöglichen die Trennung von Verhalten und Komponenten
- Änderungen am Verhalten werden einfacher
- Code lässt sich leichter nachvollziehen
- Verhalten kann unabhängig von Komponenten getestet werden
- Beim Erstellen eines Statecharts werden alle möglichen Zustände vollständig untersucht
- Es gibt Forschungsergebnisse, nach denen Statechart-basierter Code weniger Bugs aufwies als traditioneller Code
- Sie eignen sich gut, um leicht übersehene Ausnahmesituationen zu behandeln
- Mit wachsender Komplexität verbessert sich die Skalierbarkeit
- Auch Nicht-Entwickler können sie leicht verstehen, und QA kann sie als Explorationstool nutzen
- Schon heute enthält viel Code implizit State Machines; Statecharts machen diese explizit sichtbar
Aufwand und Einwände bei Statecharts
- Es ist zusätzlicher Lernaufwand nötig
- Das zugrunde liegende Konzept der state machine selbst dürfte vielen Programmierern allerdings vertraut sein
- Da sich die Arbeitsweise deutlich von bestehender Codierung unterscheidet, kann sie als ungewohntes Paradigma empfunden werden
- Das kann im Team zu Ablehnung führen
- Bei kleinen Statecharts kann die Trennung des Verhaltens dazu führen, dass mehr Codezeilen entstehen
- Gründe für die geringe Verbreitung sind unter anderem mangelnde Bekanntheit und YAGNI
- Häufige Gegenargumente sind, dass man es nicht unbedingt brauche, dass es nicht zu bestimmten Technologietrends passe oder dass die Zahl der Bibliotheken steige
- In Webanwendungen kann sich die Ladezeit erhöhen
- Selbst wenn man diese Vor- und Nachteile zusammen betrachtet, kommt die Einführung insgesamt meist einem Nettogewinn nahe
Einsatzweise und SCXML
- SCXML ist ein Format, das von 2005 bis 2015 beim W3C standardisiert wurde und verschiedene semantische Regeln von Statecharts sowie die Behandlung von Edge Cases definiert
- In mehreren Sprachen gibt es Tools zum Lesen, Schreiben und Ausführen von SCXML
- Es existieren auch abgeleitete Formate mit anderer Syntax, die dasselbe Modell beibehalten
- Es gibt Statechart-Bibliotheken für verschiedene Plattformen, die die semantischen Regeln von SCXML in unterschiedlichem Umfang unterstützen
- Solche Bibliotheken helfen dabei, die Reihenfolge von Abläufen wie entry/exit action korrekt zu behandeln
- Weitere Hinweise zur Nutzung finden sich in how to use statecharts
Ausführbare Statecharts
- Statt Statecharts nur als Dokumentation zu verwenden, kann ein ausführbares machine format sowohl im Entwurf als auch zur Laufzeit eingesetzt werden
- Eine einzige Definition kann als Single Source of Truth dienen, sodass echtes Laufzeitverhalten und visuelle Diagramme gemeinsam betrieben werden können
- Die Übertragung von Diagrammen in Code entfällt
- Bugs, die durch manuelle Übersetzung entstehen, lassen sich reduzieren
- Diagramm und Implementierung bleiben stets synchronisiert
- Diagramme werden dadurch präziser
- Umgekehrt können Diagramme dadurch recht komplex werden
- Die Auswahl an Formaten und Tools für ausführbare Statecharts ist begrenzt
- Eine starke Typsicherheit zwischen Statechart und Komponenten ist nur schwer sicherzustellen
- Wenn sich die Statechart-Definition im Code befindet, kann daraus automatisch ein visuelles Statechart erzeugt werden
- Noch einfacher wird es, wenn die Definition in einer separaten Datei wie JSON oder XML liegt
Community und weitere Materialien
- Community-Gespräche finden auf gitter.im statt; der Chat lässt sich auch ohne Login lesen
- Diskussionen im Frage-und-Antwort-Stil laufen in den statecharts GitHub discussions
- Bücher und Vortragsmaterialien sind auf der Seite resources gesammelt
- Eigene Materialien können in den GitHub Discussions geteilt werden
-
Weiterführende Lektüre
- Use case: Statecharts in User Interfaces
- Concepts — Kernkonzepte von Statecharts und ihre Darstellung in Diagrammen
- Glossary — häufig verwendete Begriffe und Definitionen
- FizzBuzz — behandelt Statechart-Konzepte anhand von FizzBuzz
- Acknowledgements
1 Kommentare
Hacker-News-Kommentare
Es freut mich, dass Statecharts weiterhin Aufmerksamkeit bekommen.
Ich habe XState entwickelt, eine Bibliothek zum Schreiben, Ausführen und Visualisieren von Zustandsmaschinen und Statecharts für JS/TS; zu finden unter https://github.com/statelyai/xstate.
Die wichtigste Erkenntnis aus mehr als 10 Jahren Arbeit daran ist, dass Statecharts am wertvollsten sind, wenn man sie nicht als bloße Dokumentation, sondern als ausführbares Verhalten behandelt.
Man braucht sie nicht überall, aber sie sind besonders stark, wenn „Was passiert als Nächstes?“ sowohl vom aktuellen Zustand als auch vom Ereignis abhängt.
Solche Diagramme lassen sich wie ein Orakel verwenden, das beantwortet: „Wenn in diesem Zustand dieses Ereignis eintritt, was ist dann der nächste Zustand und welche Effekte werden ausgeführt?“
Die nächste Major-Version von XState ist als Alpha fast bereit und fokussiert sich auf Ergonomie, Typsicherheit, Composability und einen neuen Visualizer/Editor.
Ein grundlegendes Open-Source-Visualisierungstool gibt es unter https://sketch.stately.ai.
Für formale Spezifikation ist SCXML lesenswert: https://www.w3.org/TR/scxml
Auch David Harels Originalarbeit ist sehr wertvoll: https://www.weizmann.ac.il/math/harel/sites/math.harel/files/users/user50/Statecharts.pdf
Es gibt auch einen Vortrag von der Laracon, in dem die Gedanken zu State Machines und Statecharts gut zusammengefasst werden.
https://www.youtube.com/watch?v=1A1xFtlDyzU
Das ist eine recht ausgereifte Implementierung, die SCXML ziemlich nahekommt und vor allem bei ausführbaren Inhalten die XML-Anforderung entfernt.
Im Abschnitt zu prior art wird XState ebenfalls als Referenz aufgeführt.
Ich habe es zusammen mit lit.js in einer Drawer-Navigationskomponente eingesetzt, die auf die Seitenbreite reagiert und viele Props sowie internen Zustand hat; ich will mir gar nicht vorstellen, wie schrecklich das ohne XState gewesen wäre.
Ich freue mich auf die nächste Version, und wirklich vielen Dank.
Die automatische TS-Typinferenz ist ziemlich gut, daher lässt es sich bequem einsetzen, wenn man leichte Zustandsmaschinen-Logik braucht.
Früher schien Statecharts im Frontend/UI-Ökosystem langsam an Fahrt zu gewinnen, und ich finde es schade, dass dieser Schwung aus irgendeinem Grund verloren gegangen ist.
Für UI-Interaktionen machen Zustandsmaschinen, besonders Zustandsmaschinen-Kompositionen wie Statecharts, komplexe Abläufe viel leichter nachvollziehbar.
Wenn du neu dabei bist, kann ich Ian Horrucks’ „Constructing the user interface with statecharts“ sehr empfehlen.
Das Buch ist zwar von 1999, aber als Einführung, die erklärt, wie man es tatsächlich anwendet und benutzt, ist es immer noch erstklassig.
https://archive.org/details/isbn_9780201342789/mode/2up
Die wöchentlichen npm-Downloads liegen bei über 4 Millionen, und auch Animationstools wie Rive und LottieFiles stellen Funktionen für Zustandsmaschinen deutlich heraus.
AI-Tools wie LangGraph basieren ebenfalls auf Zustandsmaschinen.
Es wird wohl noch Zeit brauchen, bis diese Apps und Tools das Potenzial von Statecharts vollständig ausschöpfen, aber der Start ist vielversprechend.
https://github.com/derkork/godot-statecharts
Ein Punkt, der in Einführungen oft fehlt, sind History-Pseudo-States.
Wenn man H und H* verwendet, wird das Statechart von außen betrachtet formal nichtdeterministisch.
Oft wird erklärt: „Der aktuelle Zustand ist eine reine Funktion der Eingabe“, aber History durchbricht diese Annahme.
Wenn man über H wieder in einen Elternzustand eintritt, kehrt man in das zuletzt aktive Kind zurück; dadurch kann man bei gleichem Ereignis und gleichem äußeren Zustand in unterschiedliche innere Zustände gelangen.
Dieses verborgene „zuletzt aktive Kind“ ist selbst Zustand, wird im Diagramm aber normalerweise nicht dargestellt.
Schon Harels Originalarbeit erkennt das an, und SCXML sowie XState implementieren es ebenfalls, aber gerade darüber wird kaum gesprochen.
Wenn man also mit Deep History den Teilbaumzustand beim Wiedereintritt bewahrt, verlagert man das Bookkeeping zur Chart-Engine.
Das ist eine vernünftige Entscheidung, aber das Diagramm allein beschreibt damit nicht mehr das gesamte Verhalten, und History-Transitionen brauchen wie jede andere Zustandslogik eigene Tests.
Mit der zweiten Lesart ist die Maschine vollständig deterministisch, und der Deep-History-Zeiger ist einfach Teil des Zustands der Zustandsmaschine.
Man könnte zum Beispiel H und H* in mehrere Knoten auflösen und H' wie ein Write-Ahead-Log vor jeden Knoten setzen.
Ich frage mich, ob sich Durable-Execution-Engines wie Temporal, DBOS, Restate mit Statecharts kombinieren lassen.
In unserer Firma nutzen wir Cloudflare Workflows, um Onboarding- und Payment-Workflows zu verwalten, und dank der automatisch erzeugten Flowchart-Diagramme lässt sich das Workflow-Verhalten schnell verstehen.
Das wirkt letztlich ziemlich ähnlich zu dem Wertversprechen, auf das Statecharts abzielen.
https://zindex.ai/
Diagramme, die von AI erzeugt werden, sind meist einmalig generierte Mermaid/SVG/PNG-Dateien, ohne einen dauerhaften Diagrammzustand, den man aktualisieren, validieren, diffen oder wiederverwenden kann.
Zindex behandelt das Diagramm selbst als strukturierten Zustand.
Wenn ein Agent über das Diagram Scene Protocol (DSP) Knoten, Kanten, Gruppen, Beziehungen, Constraints und Revisionen patcht, übernimmt Zindex Validierung, Layout, Rendering, Versionierung und Speicherung.
Deshalb glaube ich, dass man es neben Temporal/DBOS/Restate/Cloudflare Workflows einsetzen kann: Die Engine bleibt die Quelle der Wahrheit für die Ausführung, während Zindex ein persistentes und prüfbares visuelles Modell verwaltet, das aus Code oder Ausführungsverlauf abgeleitet ist.
Eigentlich können Statecharts mit Durable Execution genauso gut mithalten.
Eine Zeit lang wirkte es so, als würde Cloudflare eher in Richtung des Durable-Object-Actor-Modells gehen, aber ich weiß nicht, ob sie dieses Projekt aufgegeben haben.
Ist das eine eingebaute Funktion von Cloudflare Workers, oder hat euer Team das selbst gebaut?
Ich liebe XState wirklich.
Es hat in mehreren Codebasen unzählige Probleme gelöst und ist in letzter Zeit zum tragenden Gerüst einer Voice-App geworden, die wir für den Bankensektor entwickeln.
Danke, dass du so viel Zeit und Mühe investiert hast, um etwas so Großartiges zu bauen.
Ich habe auch etwas zu meinen Erfahrungen mit Finite State Machines und zur Architektur, die ich mit XState + Mastra aufgebaut hatte, in einem Blogpost festgehalten.
Nach der Veröffentlichung bin ich von Mastra zu Pipecat gewechselt.
https://blog.davemo.com/posts/2026-02-14-deterministic-core-agentic-shell.html
Ich werfe das auch noch in den Ring.
ETL State Chart und Hierarchial FSM:
https://www.etlcpp.com/state_chart.html / https://www.etlcpp.com/hfsm.html
Quantum Leaps:
https://www.state-machine.com
Ich habe das vor allem in sicherheitskritischen Systemen eingesetzt, wo Komplexität, Timing und die Überprüfbarkeit des Verhaltens besonders wichtig sind.
Dabei hilft sehr, dass sich Entscheidungsfindung und Handlung trennen lassen.
Dieser Ansatz, Entscheidungsfindung auf „Wenn in diesem Zustand dieses Ereignis eintritt, was tun wir als Nächstes?“ herunterzubrechen, ist etwas anders als die übliche Programmstruktur, schafft aber eine gute Trennung und macht es leichter, Verhalten unter verschiedenen Bedingungen nachzuvollziehen.
Ich habe mir immer gewünscht, dass Zustandsmaschinen stärker angenommen werden.
In einer Zeit, in der von AI erzeugter Code nicht so tief verstanden wird wie von Menschen geschriebener Code, wird das visuelle Verständnis von Zustand immer wichtiger.
Trotzdem scheinen Frontend-Frameworks weiterhin eher store-basierten reaktiven Zustand zu bevorzugen.
Auch ich nutze das normalerweise als Standard und habe deshalb nicht bewusst gewechselt, außerdem gelten Bibliotheken wie xstate als schwerer zu lernend und wortreicher in der Syntax.
Mit AI fällt diese Hürde jedoch fast weg, daher frage ich mich, ob es andere Gründe gibt, die ich übersehe, oder ob Statecharts ihren Höhepunkt einfach noch nicht erreicht haben.
Die API-Oberfläche wird kleiner, die Lernkurve flacher, und sowohl Entwickler als auch Agenten werden sie leichter schreiben können.
Gleichzeitig schreiben moderne Frontier-Modelle schon jetzt ziemlich guten XState-Code.
Während ich am Projekt https://github.com/xlnfinance/xln arbeitete, wurde mir klar, dass wir eine Möglichkeit brauchten, ein echtes Netzwerk deterministisch zu emulieren.
Dann kam mir der Gedanke: Alle Blockchains sind letztlich replizierte Zustandsmaschinen, also warum nicht jeden Benutzerknoten in eine dreistufige Hierarchie von Zustandsmaschinen aus Runtime -> Entity -> Account einbetten?
Dabei kontrolliert die äußere Maschine die innere vollständig, also eine Art „Blockchain in der Blockchain“ mit unterschiedlichen Konsensmodi.
Später suchte ich nach „hierarchical state machines“, stieß auf Statecharts und hatte das Gefühl, dass sich die beiden Ideen stark ähneln.
Meiner Meinung nach sollte mehr Software Hierarchien von Zustandsmaschinen verwenden, um die schlimmsten Bugs durch Nichtdeterminismus zu reduzieren.
Im Automobilbereich wird so etwas schon seit Langem eingesetzt.
Wenn man sich matlab/simulink anschaut, kann man Algorithmen als Zustandsmaschinen zeichnen und daraus sogar Code generieren lassen.
Kürzlich habe ich ebenfalls eine Zustandsmaschine implementiert, um eine ziemlich komplexe React-Komponente zu verwalten, die über CSS-Transitions zwischen mehreren visuellen Zuständen wechselt.
Die Zustandsmaschine selbst war nicht besonders schwierig, aber die Leute scheinen damit noch nicht vertraut genug zu sein.
In unserer Firma laufen alle Geschäftsprozesse als Statecharts, seit ich einen Interpreter innerhalb von Postgres gebaut habe.
Die Erfahrung war sehr gut, die Prozesse sind extrem robust gegenüber Veränderungen geworden, und auch Jahre später lassen sie sich leicht wieder verstehen.
Ich habe die Bibliothek auch als Open Source veröffentlicht.
https://github.com/kronor-io/statecharts