So gestalten Sie den Status in JavaScript visuell

Eine Roadmap für die Entwicklung von Anwendungen mit Zustandsautomaten und Zustandsdiagrammen

Foto von rawpixel auf Unsplash

Warum scheint das Statusmanagement in JavaScript besonders schwierig zu sein? Ist es die inhärente Komplexität moderner Apps oder nur die Tools? Wie entwickeln andere Bereiche des Ingenieurwesens zuverlässige und vorhersehbare Systeme? Ist es möglich, ein System zu zeichnen und in Code umzuwandeln und umgekehrt?

Lassen Sie uns einen Paradigmenwechsel im Zustandsmanagement untersuchen, um Systeme mit Zustandsautomaten und Zustandsdiagrammen visuell zu entwerfen.

Konzepte> Bibliotheken

Das Staatsmanagement ist mir schon eine Weile in den Sinn gekommen. Ich habe mit verschiedenen Bibliotheken für die Statusverwaltung experimentiert: Flux, Reflux, Redux, Dva, Vuex, Mobx und auch mit meinen eigenen.

Es gibt keinen Grund zu streiten, welches die 10-fache Lösung ist. Staatsbibliothek sind verschiedene Aromen mit den gleichen Bestandteilen. Sie sind ein Teil des Puzzles - sie erleichtern das Synchronisieren und Verbinden von Daten.

Die Lösungen, auf die wir uns als nächstes konzentrieren müssen, betreffen das Gesamtbild:

Wir müssen beim Planen und Entwerfen von Systemen besser werden.

Mach alle Dinge kaputt

Stellen Sie sich eine Benutzeroberfläche vor, die Sie für elegant halten würden. Etwas, das einer Flut von zufälligen Benutzerinteraktionen standhält - Sie wissen, dass die Art von Unvorhersehbarkeit, die auftritt, wenn ein Benutzer mehr als erwartet eine Taste drückt, mit Eingaben in einer unerwarteten Reihenfolge interagiert oder Sie auf andere Weise dazu bringt, Ihr Vertrauen in die Menschlichkeit in Frage zu stellen. Das wirkliche Leben ist hart für Systeme.

Ich werde das Projekt vorhersagen, an das Sie denken.

Nun… Sie denken wahrscheinlich nicht an etwas, das für das Web entwickelt wurde, wo die Philosophie zu sein scheint, „sich schnell zu bewegen und Dinge zu zerbrechen“.

Anhand der Häufigkeit von Updates denken Sie wahrscheinlich auch nicht an Mobilgeräte.

Sie denken wahrscheinlich nicht einmal an etwas, das kürzlich gebaut wurde. Wir scheinen nicht unbedingt besser darin zu sein, zuverlässige Produkte zu bauen.

Ich glaube, ich weiß, woran Sie denken.

Habe ich recht? ….Nein?

Sie erkennen dies möglicherweise nicht einmal als Sony Walkman der 1980er Jahre.

Als Kind erhielt ich einen Kassettenrekorder wie diesen von einem Freund, der auf einen tragbaren CD-Player umgerüstet hatte. Ich verstehe, dass einige jüngere Leser die Erwähnung dieser beiden Geräte als ungewohnt empfinden - stellen Sie sich den Walkman als iPhone vor, aber mit größeren Tasten und größerem zerstörerischen Potenzial. Meine Hauptaufgabe: Brechen Sie es.

Ich würde alle Tastenkombinationen ausprobieren, um zu sehen, was passieren könnte:

  • Versuchen Sie, das Band während des Schnellvorlaufs auszuwerfen
  • Halten Sie den Schnellvorlauf gedrückt und spulen Sie gleichzeitig zurück

Wie auch immer, der Sony Walkman hat sich besser behauptet als die meisten heutigen Websites.

Engineering-Schnittstellen

Elektronik wie der Walkman hielt den harten Benutzertests stand, ohne dass Elemente der Benutzeroberfläche ausgeblendet oder deaktiviert werden konnten. Jeder Knopf kann jederzeit gedrückt werden, alles kann passieren. Und doch schien es unzerbrechlich.

Ich habe mich gefragt:

Vielleicht bietet die Elektronik ein besseres Paradigma dafür, wie wir Schnittstellen im Web erstellen können.

Was können wir aus dem alten Designprozess der Elektronik lernen? Wie können wir Anwendungen besser konstruieren? Marty, wir müssen zurück in die Zukunft!

Elektronik & das Web

Kann uns die Elektronik eine bessere Möglichkeit bieten, Anwendungen im Browser zu erstellen?

Bedenken Sie, dass Komponenten in den letzten fünf Jahren zu einer der bedeutendsten Veränderungen in der Webentwicklung geführt haben. Vielleicht gibt es noch andere Konzepte, die wir uns aus der Elektrotechnik ausleihen können?

Als Webentwickler hatten wir es gut. Mögen. Wirklich gut. Einen Fehler gefunden? Stellen Sie innerhalb einer Stunde ein Update auf Ihrem Server bereit.

Andere Bereiche des Ingenieurwesens sind nicht so nachsichtig. Ein Hardwareproblem führt häufig dazu, dass ein Gerät in den Papierkorb verschoben wird. Embedded-Entwickler müssen darauf achten, dass durch ein Firmware-Update nicht der Akku entladen wird oder alle vorhandenen Geräte abstürzen.

Webentwickler haben den Luxus, rücksichtslos zu sein.

Ganz zu schweigen davon, dass App-Entwickler selten mit den gleichen Ressourcenbeschränkungen konfrontiert waren wie die Entwickler elektronischer Geräte. Wann war Ihr Hauptaugenmerk das letzte Mal auf Leistung und Speichernutzung, anstatt nur das verdammte Ding zum Laufen zu bringen? Ein Schwellenwert von 60 Bildern pro Sekunde ist ein niedriger Balken. Die Messlatte steigt jedoch, da wir zunehmend komplexe Apps entwickeln, die auf weniger leistungsstarken Mobil- und IoT-Geräten ausgeführt werden können. Wir grenzen an ein technisches Problem, mit dem Ingenieure auf niedrigem Niveau seit Jahrzehnten konfrontiert sind.

Einschränkungen erzeugen Kreativität. Einschränkungen führen zu besserem Design.

Um zu sehen, wie das Einbeziehen von Einschränkungen zu einem besseren Design führen kann, müssen wir uns wieder den Grundlagen des Zustandsmanagements zuwenden.

Ye Old / New State Management Fundamentals

Die Richtung der Gespräche in der Web-Community tendiert eher zu NPM-Paketen als zu grundlegenden Prinzipien der Informatik.

Ingenieure fragen nicht: „Welche Bibliothek ist besser? So viel wie sie fragen: "Wie entwerfen wir ein besseres System?"

Wir können mit einigen Grundprinzipien guten Designs beginnen:

  • Unterscheiden zwischen unbestimmten Daten und endlichen Zuständen
  • mögliche Übergänge von einem Zustand in einen anderen begrenzen
  • optisch gestalten

Ich werde diese zusammen mit meinem eigenen Weg und den folgenden 8 Erkenntnissen durcharbeiten.

1. Zustand! == Daten

In programmatischen Systemen ist der Unterschied zwischen Status und Daten verschwommen. Beide leben in Erinnerung und werden daher gleich behandelt.

In React haben Status und Daten denselben Namen und dieselben Mechanismen:

  • bekommen: this.state
  • Speichern: this.state = {}
  • Aktualisierung: this.setState (nextState)

In der Elektronik ist die Unterscheidung zwischen Zustand und Daten weniger verwirrend.

Der Zustand stellt eine endliche Anzahl von Modi dar, in denen das System sein kann - häufig durch die Schaltung selbst definiert. Denken Sie für unseren Walkman an "Spielen", "Anhalten", "Auswerfen". Wie bei einem „Modus“ oder einer „Konfiguration“ ist der Status zählbar.

Daten hingegen werden mit nahezu unbegrenzten Einstellungsmöglichkeiten gespeichert. Denken Sie für unseren Walkman an den Titel „Song 2“, der gerade abgespielt wird. Daten können wie Musik unendlich viele Möglichkeiten haben.

Was auch immer diese DataLoader-Komponente unten tut, der Status kann nur einen begrenzten Satz von Ansichten generieren: "Laden", "Laden" oder "Fehler".

Das Trennen von Status und Daten kann zu weniger Verwirrung führen und ermöglicht es uns, Anwendungen auf der Basis von Zustandsautomaten zu erstellen.

2. Der Zustand ist endlich

Elektronikentwickler wissen seit langem, dass eine vorhersagbare Schnittstelle eine begrenzte und kontrollierte Anzahl von Zuständen aufweist. Ohne eine kontrollierte Anzahl von Zuständen werden Systeme schwierig zu debuggen und können nicht gründlich getestet werden.

In einer Zustandsmaschine werden Zustände explizit definiert. Übergänge sind die möglichen Ereignisse, die Sie auslösen können, um zwischen Zuständen zu wechseln.

Wenn Sie beispielsweise einen Übergang mit dem Ereignis "STOP" auslösen, wird der Status auf "Gestoppt" verschoben.

In React könnten wir einen einfachen Walkman mit mindestens zwei Zuständen definieren: "Gestoppt" oder "Spielen".

Schauen Sie sich diese CodeSandbox an.

In einer Zustandsmaschine befindet sich das System immer in einer der möglichen Konfigurationen. Die Ansicht hat keine Möglichkeit, etwas anderes als "Spielen" oder "Gestoppt" zu sein. Wenn Sie beide Tests durchführen, können Sie sicher sein, dass das System ordnungsgemäß funktioniert.

3. Komplexität in Zustandsautomaten verwalten

Schauen wir uns an, was passiert, wenn wir dem Zustandsmaschinen-Beispiel zwei neue Zustände hinzufügen: "Zurückspulen" und "Schnellvorlauf".

Wenn Zustände gleichwertig sind, können sie täuschend leicht hinzugefügt werden. Jeder Zustand ist wie sein Modul, das isoliert entwickelt und getestet werden kann. Aber Vorsicht, Zustandsübergänge sollten nicht immer möglich sein.

Wir sollten uns um unkontrollierte Übergänge zwischen Staaten sorgen.

Vielleicht hast du es gefangen. Wir haben oben einen Bug eingeführt. Nehmen Sie sich eine Minute Zeit und versuchen Sie herauszufinden, was schief gelaufen ist.

4. Guard-Übergänge

Es scheint, dass die Kassette völlig durcheinander ist, da die Benutzer zwischen Zurückspulen und Schnellvorlauf wechseln können, ohne die Kassette dazwischen anzuhalten.

Als Lösung können wir unseren Zustandsübergängen Wachen hinzufügen. Wachen sind Bedingungen, die erfüllt sein müssen, damit ein Übergang stattfinden kann. Als Beispiel können wir sicherstellen, dass die Ereignisse FASTFORWARD, REWIND und PLAY nur ausgelöst werden können, wenn der Status "Stopped" ist.

Unerwartete Zustandsübergänge sind nur dann zu erwarten, wenn wir die Art und Weise, wie wir unser Zustandsmanagement planen und gestalten, überdenken.

Wenn wir zusätzliche Zustände wie ausgeworfen hinzufügen, müssen wir überlegen, welche Zustandsübergänge unter welchen Bedingungen zulässig sind. Mit einem Walkman können Sie das Band auswerfen, indem Sie auf Stopp drücken, während sich das Band im Stoppmodus befindet. Um diese Funktionalität hinzuzufügen, müssen wir noch mehr Schutzvorrichtungen hinzufügen und bestimmen, welche Übergänge möglich sind.

Die Wahrscheinlichkeit nicht behandelter Zustandskombinationen multipliziert sich, wenn zusätzliche Zustände hinzugefügt werden. Dies ist keine skalierbare Lösung. Jeder zusätzliche Zustand führt zu einer Überprüfung aller Übergangswächter.

Es fängt an, sich eher so zu fühlen, als würde der Staat Sie verwalten.

Das Problem beim Verwalten von Wachen ergibt sich aus der Art und Weise, in der der Status dargestellt wird: "Angehalten", "Spielen", "Zurückspulen".

Die ideale Datenstruktur für state ist weder eine Zeichenfolge noch ein Objekt.

Aber was ist es dann?

5. Zustand ist ein Graph

Die ideale Datenstruktur zur Darstellung des Zustands ist häufig eine Grafik. Zustandsgraphen, die allgemein als Zustandsdiagramme bezeichnet werden, bieten eine intuitive Möglichkeit, Zustandsübergänge an jedem Knoten zu entwerfen, zu visualisieren und zu steuern.

Dies ist keine neue Nachricht - Elektronikingenieure verwenden seit Jahrzehnten Zustandsdiagramme, um komplexe Systeme zu beschreiben.

Schauen wir uns ein Beispiel im Web an. AWS Step Functions bieten eine visuelle Oberfläche zur grafischen Darstellung des Workflows einer Anwendung. Jeder Knoten steuert ein Lambda - eine entfernte Funktion, die in der Cloud aufgerufen wird -, wobei der Ausgang jeder Funktion den Eingang der nächsten auslöst.

AWS Step-Funktionen

Im obigen Beispiel wird deutlich, wie sich die Aktionen eines Benutzers in den einzelnen Schritten bewegen, einschließlich möglicher Fehler, und wie damit umgegangen wird. Das Hinzufügen zusätzlicher Schritte führt nicht zu einem exponentiellen Anstieg der Komplexität.

Ein Ingenieur kann bemerken, wie viel Schrittfunktionen mit SPS-Blockdiagrammen (Speicherprogrammierbare Steuerung) gemeinsam haben. Ein Designer kann feststellen, wie viel er mit Workflow-Diagrammen gemeinsam hat. Sollte die Art und Weise, wie wir einen Staat entwerfen, nicht mehr mit der Art und Weise gemein haben, wie wir Anwendungen planen?

6. Gerüst auf Zustandsgraphen

Zustandsgraphen werden zum Gerüst für Ihre Anwendung.

Beispielsweise könnte ein Zustandsdiagramm unseres Walkmans eine visuell verständlichere und zugänglichere Darstellung ergeben.

Walkman-Zustandsdiagramm

Ohne in den Code für Wachen zu vertiefen, können wir feststellen, dass es keine Möglichkeit geben sollte, von „Zurückspulen“ zu einem anderen Status als „Angehalten“ zu springen. Anstatt alle Übergänge zu skizzieren, die Ihre Benutzeroberfläche nicht ausführen sollte, legen Sie fest, was sie tun kann. Die Entwicklung verlagert sich von einem defensiven Bottom-Up-Codierungsansatz zu einem Top-Down-Designansatz. Diese Verschiebung ist allein 10x.

Zustandsdiagramme sind intuitiver, leichter zu debuggen und können Änderungen in den Anforderungen besser aufnehmen. Neben Zustandsautomaten können Änderungen in jedem Zustand von ihren Nachbarzuständen isoliert werden. Ganz zu schweigen davon, dass ein Großteil der komplexen Übergangslogik in einem visuell nachvollziehbaren Format enthalten sein kann.

Leider können Zustandsgraphen eine tickende Zeitbombe sein.

Dicht verbundene Grafiken werden nicht skaliert. Überlegen Sie, was passieren würde, wenn wir dem obigen Diagramm weitere 4 Zustände hinzufügen würden. Die Lesbarkeit nimmt ab und die Wiederholungen nehmen zu, wobei verschlungene Pfeile in alle Richtungen zeigen und um den Platz konkurrieren. Diese Spaghettifizierung eines Zustandsgraphen wird als Zustandsexplosion bezeichnet.

Glücklicherweise gibt es eine Möglichkeit, die visuelle Komplexität beim Entwerfen komplexer Zustandsgraphen mithilfe einer formalisierten Methode zur Beschreibung von Systemen zu verringern: Sehen wir uns die Zustandsdiagramme an.

7. Master Statecharts

Die Zustandsdiagramme habe ich zum ersten Mal in der Präsentation von Luca Matteis zum Modellieren des Verhaltens von Redux-Apps mithilfe von Zustandsdiagrammen beim Vancouver React Meetup kennengelernt. Am nächsten Arbeitstag sprach ich dieses „neue“ Paradigma für das Staatsmanagement an, nur dass viele meiner Ingenieurskollegen bereits mit dem Konzept vertraut waren. Ich arbeite bei einem IOT-Unternehmen neben vielen Hardware- und Embedded-Entwicklern. Wir stellen ein ;)

Das Konzept eines Zustandsdiagramms stammt aus dem Jahr 1987, als der Mathematiker David Harel einen Artikel über die visuelle Beschreibung komplexer Systeme veröffentlichte, beispielsweise das folgende Beispiel einer Quarzuhr.

Zustandsdiagramme sind sowohl intuitiv als auch einfach zu beherrschen, sobald Sie die Sprache verstanden haben.

Statecharts führen eine Vielzahl neuer State-Typen ein:

  • Ausgangszustand - Der durch einen Punkt mit einem Pfeil markierte Ausgangszustand.
  • verschachtelte Zustände - Zustände, die Zugriff auf die Übergänge ihres übergeordneten Elements haben.
  • Parallele Zustände - zwei sich nicht berührende Zustände, die durch gepunktete Linien dargestellt werden.
  • Verlaufsstatus - Ein Status, der sich an den vorherigen Wert erinnert und diesen wiederherstellen kann.

Außerdem können Zustandsdiagramme enthalten, wie und wann Übergänge und Aktionen ausgelöst werden:

  • Transition - Eine Funktion, die eine Statusänderung basierend auf einem benannten Ereignis auslöst. "Gestoppt" → Übergang ("Abspielen") → "Abspielen"
  • guard - eine Bedingung, die erfüllt sein muss, damit ein Übergang stattfindet. Beispielsweise kann die Wiedergabe nicht ausgelöst werden, wenn kein Band vorhanden ist oder wenn das Bandende erreicht ist. "Angehalten" → Übergang ("Abspielen") [hasTape] → "Abspielen". Bei einer Bestellung können mehrere Übergänge möglich sein.
  • action - Trigger, die aufgrund einer Statusänderung auftreten. Zum Beispiel das Auslösen eines Bandes, um die Wiedergabe zu starten, wenn der Zustand "Wiedergabe" eingeht. Aktionen können "onEntry" und / oder "onExit" auftreten.

Das Umschreiben des Walkman-Beispiels als Zustandsdiagramm beseitigt die im Zustandsdiagramm festgestellte Redundanz. Beachten Sie, dass bei STOP-Ereignissen keine Wiederholung mehr erforderlich ist. Zustandsdiagramme sind skalierbar - es ist nicht schwer, zusätzliche parallele Zustände wie "Aufnahme" und "Lautstärke" hinzuzufügen.

Zustandsdiagramme sind mehr als nur ein Konzept zur visuellen Beschreibung von Anwendungen.

Zustandsdiagramme können die Zustandsautomaten generieren, die einer Anwendung zugrunde liegen.

Sie können Grafiken in Code konvertieren und umgekehrt. Zeigen Sie Ihre Anwendungslogik als Diagramm an oder zeichnen Sie sie.

8. Statechart Tools

Statecharts bieten eine vielversprechende Zukunft für das echte Entwerfen von Systemen - und das nicht nur auf dem Papier. Während es Tools für andere Programmiersprachen gab, zeigt JavaScript gerade erst einen Boom bei Statechart-Tools.

C & Java-Entwickler verfügen über Tools zum Codieren mit und neben Zustandsdiagrammen. Yakindu Statechart Tools vereint beispielsweise die Welten des visuellen Designs und des Codes. Ich habe kürzlich erfahren, dass Yakindu auch einen Typescript-Codegenerator enthält.

Dasselbe Tool wird nun auch für JavaScript verfügbar.

Sketch Systems bietet eine Möglichkeit, Systeme in Markdown zu entwerfen, die dann zum Prototypen in JavaScript verwendet werden können. Sketch Systems unterstützt zwar noch keine Aktionen oder Wachen, ich fand es jedoch sehr nützlich, um Prototypen zu erstellen und Statusdiagramme zu testen.

https://bit.ly/2lZhqOB

Mit Sketch Systems können Sie Ihre Diagramme in XState exportieren, eine auf Statecharts basierende JavaScript-Bibliothek mit Visualisierung und anklickbarem State-Prototyping-Tool.

https://bit.ly/2uJydt9

Stellen Sie sich erweiterte Werkzeuge in Ihrem Editor vor. Stellen Sie sich Ihren Workflow vor, während Sie zwischen visuellem Entwerfen und manuellem Codieren Ihrer Anwendungslogik wechseln. Es ist die Arbeit wert, die wir als Community investieren müssen, um die Tools, Bibliotheken und Editor-Plug-ins zu verbessern, die wir mithilfe von Zustandsdiagrammen besser unterstützen möchten.

Fazit

In der JavaScript-Community hat sich die Komplexität eingeschlichen. Ich glaube nicht, dass wir dafür bereit waren. Ich gebe zu, ich habe lange gebraucht, um Bewerbungen gut zu planen. Ich würde einen Komponentenbaum und eine Zustandsform skizzieren. Beobachten Sie, wie Prototypen in die Produktion einfließen. Aber wie könnte ich Anwendungen ohne eine formalisierte visuelle Sprache zum Entwerfen von Zustandsdiagrammen gut planen?

Lange Zeit werde ich gestehen, dass ich mich dem Staatsmanagement eher wie einer mystifizierenden Kunst zugewandt habe. Mir war nicht bewusst, dass es in anderen Bereichen der Informatik mit einer langen Geschichte des Aufbaus und der Verwaltung komplexer Systeme viel zu lernen gab. Mir wurde klar, dass es wichtig ist, in die Vergangenheit zu schauen und die Bereiche der Technik, die uns umgeben, von der Seite zu betrachten.

Wir können von Ingenieuren lernen, die jahrzehntelange Lösungen für die Erstellung komplexer und doch vorhersehbarer Systeme entwickelt haben. Wir können auf Tools und Bibliotheken als Ökosystem aufbauen, um die visuelle Gestaltung der Anwendungslogik zu unterstützen. Und wir werden es tun, weil JavaScript all dies benötigt.

Die Zukunft des Entwurfs von Anwendungen in JavaScript sieht besser aus als je zuvor. Dieser Artikel war allesamt auf sehr hohem Niveau und hat wahrscheinlich mehr Fragen als Antworten hinterlassen. In Teil 2 möchte ich mich eingehender mit Mustern für die Verwendung von Zustandsdiagrammen mit Komponenten befassen.