Snapshot Management für Angular Prototyping

Jede Web-Applikation, die mit veränderlichen Daten arbeitet, muss diese Daten in irgendeiner Weise abspeichern, damit die Änderungen nicht verloren gehen. Typischerweise wird hierfür eine Schnittstelle von der serverseitigen Software (Backend) bereitgestellt, die zum einen das Abrufen der Daten erlaubt und zum anderen das Abspeichern von Änderungen oder das Hinzufügen neuer Daten ermöglicht. Der Server dient hierbei als zentrales Element, mit dem jeder Client (Browser oder App) kommuniziert, um an die Daten zu gelangen. Das Backend kommuniziert seinerseits mit einer Datenbank, die die eigentliche Datenhaltung übernimmt. Für die Entwicklung eines Frontend-Prototyps für einen unserer Kunden haben wir uns allerdings dazu entschlossen auf eine Datenhaltung direkt im Browser zu setzen. Wie es funktioniert und welche Vor- und Nachteile es mit sich bringt, wird im Folgenden beschrieben.

Anforderung an den Prototyp

Zunächst muss geklärt werden, welche Anforderungen unser Prototyp erfüllen soll. Vorweg sei gesagt: Es ging nicht darum, eine voll funktionsfähige, produktionsfertige Software auszuliefern. Der Fokus lag vielmehr auf dem Erscheinungsbild, der Funktionalität und der Haptik des Frontends. Unser Kunde möchte eine browser-basierte App auf den Markt bringen, vor deren Entwicklung er bei seinen Kunden mit einem Prototyp Akzeptanztests durchführen möchte. Für die Entwicklung des Prototyps bedeutet das, dass viele kleine Änderungen sowohl am Code als auch an den Daten an der Tagesordnung sind, wodurch unser Prototyp hier maximale Flexibilität braucht. Zusätzlich benötigt unser Kunde für die Akzeptanztests die Möglichkeit, viele verschiedene Testszenarien zu erstellen, um diese dann an die Testpersonen auszugeben.

Keine Datenbank ist auch eine Lösung

Bei unserem Prototyp handelt es sich um eine digitale B2B Plattform, auf der gewerbliche Anbieter ihre Handelswaren an gewerbliche Händler oder Großabnehmer veräußern können. Das heißt, wir hantieren hier unter anderem mit Entitäten wie „Benutzer“, „Unternehmen“, „Sortiment“, „Artikel“, „Angebot“ und „Bestellung“. Natürlich lassen sich diese Daten hervorragend in einer relationalen Datenbank ablegen. Eine Datenhaltung im Browser hat aber für unseren Anwendungsfall entscheidende Vorteile:

  • Es ist nicht erforderlich, eine passende Backend-API zum Synchronisieren der Daten zu implementieren.
  • Eine Datenbankanbindung muss ebenso wenig implementiert werden.
  • Bei Änderungen an den Daten muss dementsprechend auch keine Anpassung der Backend-API oder am Datenbank-Schema erfolgen. Eine ggf. erforderliche Migration der Daten entfällt ebenfalls.
  • Durch den geringeren Implementierungsaufwand ergeben sich außerdem Kostenersparnisse, eine reduzierte Entwicklungszeit und dadurch eine schnellere Time-to-Market.

Wenn wir zusätzlich noch die Möglichkeit schaffen, einen Abzug der Daten im Browser an eine Testperson zu schicken, können wir sogar die verschiedenen Testszenarien vorbereiten und verteilen.

Solltest Du bei Deinem Projekt ähnliche Bedingungen vorfinden oder ein einfaches Proof-of-Concept für das nächste Projekt bauen willst, ist die im Nachfolgenden beschriebene Vorgehensweise eventuell ein valider Lösungsansatz.

Prototyp-Setup

Für die Implementierung des Prototyps wurde das Web-Framework Angular verwendet. Unsere Daten können durch diverse View-Komponenten dargestellt und editiert werden. Als globale Datenablage im Browser („Store“) haben wir uns für den NGXS State Manager entschieden. Bei Bedarf liefert dieser unsere Daten an jede beliebige Komponente aus (über sog. „Selectors“). Auch bei Datenänderungen werden die aktualisierten Daten an den Store weitergeleitet (über sog. „Actions“), welche dann bei der nächsten Anfrage an den Store wieder ausgeliefert werden.

Initial werden auch bei unserem Prototyp alle erforderlichen Daten von einem Webserver ausgespielt. Hierzu gehört insbesondere die kompilierte Angular-App mit ihren HTML, CSS und JavaScript Dateien. Aber auch Schriften, Bilder und JSON-Dateien werden benötigt, um dem Browser eine lauffähige App auszuliefern. Die eigentlichen Nutzdaten werden, sobald die App gestartet wurde, einmalig vom Server bereitgestellt und in den Store importiert. Hierbei handelt es sich um sinnvolle Initialisierungsdaten, wie z. B. ein Set an Benutzern, Unternehmen und Artikeln, die einen guten Startpunkt für die Vorbereitung eines Testszenarios bieten. Alle nachfolgenden Änderungen an diesen Daten verbleiben aber ausschließlich im Browser. Doch wie bekommen wir die Daten nun aus unserem lokalen Browser an die Browser der Testpersonen verteilt? Hierbei können uns Snapshots helfen!

Was ist eigentlich ein Snapshot?

Ein Snapshot ist eine Momentaufnahme aller Daten die aktuell im Store gespeichert sind. Um einen Snapshot zu erhalten, bietet NGXS die Methode store.snapshot() an. Das hierüber erhaltene Objekt kann nun an einem geeigneten Ort abgelegt werden. Wir haben hierfür eine simple Backend-API implementiert, die das Hinzufügen, Abrufen und Löschen von Snapshots ermöglicht. Beim Hochladen eines Snapshots werden zusätzlich auch Meta-Informationen, wie Ersteller, Titel, Beschreibung, Datum und ID gespeichert. Der Snapshot selbst wird hierbei schemalos im JSON-Format in einer Datei abgelegt. Von dort aus kann er jederzeit wieder ausgelesen und an beliebige andere Browser ausgespielt werden, die diesen Snapshot nun wiederum nutzen können, um den Store mit Daten zu initialisieren. Hierfür bietet NGXS die Methode store.reset() an. Um unerwünschte Seiteneffekte zu verhindern, haben wir das Importieren eines Snapshots mit einer Weiterleitung auf die Login-Seite inklusive Reload gekoppelt. Somit können wir sicherstellen, dass alle View-Komponenten neu initialisiert werden und die App vom Einstiegspunkt aus aufgerufen wird.

Beim erstmaligen Aufrufen der URL wird ein bestimmter, als „Default“ markierter Snapshot vom Backend ausgespielt und in den Store importiert (Abb. a). Der Browser hat nun alle Daten, um mit der Vorbereitung eines Testszenarios zu beginnen. Sobald das Testszenario fertig erstellt ist, kann der aktuelle Stand der Daten unter einem eigenen Namen (hier „snapshot_a“) exportiert und an das Backend geschickt werden (Abb. b). Um diesen Snapshot im Browser des Testers zu laden, kann beim Aufrufen der URL eine Snapshot-ID als Queryparameter mitgegeben werden. Beim Laden der Seite wird der Parameter ausgewertet und, sofern vorhanden, der entsprechende Snapshot vom Backend geladen und in den Store importiert (Abb. c). Testpersonen können den Prototyp nun mit den für sie vorbereiteten Daten ausprobieren.

Um zu verhindern, dass bei jedem Reload der Seite oder beim Schließen des Browser-Tabs alle Daten im Store verworfen werden, kann NGXS seinen gesamten Inhalt, oder auch nur einen Teil dessen, mit Hilfe des Storage Plugins im Local Storage ablegen. Die Daten bleiben somit auch sessionübergreifend erhalten und beim nächsten Öffnen der App wird der letzte Stand rekonstruiert. Durch das Aufrufen der URL mit Snapshot-ID als Queryparameter kann aber auch jederzeit der ursprüngliche Snapshot wiederhergestellt werden.

Um das Abspeichern und Verwalten von Snapshots etwas angenehmer zu gestalten, haben wir noch eine Übersichtsseite gebaut, die alle Snapshots tabellarisch auflistet. Hier können Snapshots gelöscht oder direkt importiert werden und einer der Snapshots kann hier als der Default markiert werden. Außerdem kann der aktuelle Zustand des Stores per Knopfdruck an den Server geschickt werden. An dieser Stelle macht es ggf. Sinn geeignete Sicherheitsmaßnahmen wie bspw. eine zusätzliche Autorisierung zu implementieren, um zu verhindern, dass jeder Benutzer der App die Snapshots anzeigen und manipulieren kann.

Was muss bei der Verwendung von Snapshots beachtet werden?

Abschließend möchte ich auf Punkte hinweisen, die bei der hier beschriebenen browser-basierten Datenhaltung zu beachten sind:

  • Über die Developer Tools kann jeder leicht Zugriff auf alle Daten bekommen. In einem Snapshot dürfen dementsprechend niemals sensible oder personenbezogene Daten abgelegt werden, die nicht dazu bestimmt sind, auch von der Testperson gesehen zu werden.
  • Alle Änderungen an den Daten verbleiben erstmal nur im Browser und können nur via Snapshots zwischen zwei Browsern ausgetauscht werden. Das heißt, es ist nicht möglich, Datenänderungen in einem Browser vorzunehmen und diese direkt in einem anderen Browser zu sehen. Hierfür muss ein Snapshot erst exportiert und im anderen Browser wieder importiert werden.
  • Sind mehrere Browser-Tabs mit der App geöffnet, greifen alle auf dieselben Daten im Local Storage zu. Hier muss im Einzelfall geprüft werden, welche Teile des Stores über das NGXS Storage Plugin tatsächlich persistiert werden sollen.

Fazit

Das Fazit der hier beschriebene Methode fällt gemischt aus. Auf der einen Seite haben wir sehr viel Flexibilität gewonnen und einen geringen Aufwand bei der Instandhaltung/Weiterentwicklung der Datenhaltung. Die dadurch gewonnene Zeit konnten wir anderweitig in coole Frontend-Features investieren. Die Kehrseite der Medaille ist allerdings ein etwas anderes Verhalten der App, welches - wie wir selber feststellen mussten - nicht immer für alle offensichtlich ist. Hier muss zusätzliche Zeit aufgebracht werden, um die Funktionalität allen Beteiligten verständlich zu machen. Auch die Fehlersuche ist erschwert, da sich in jedem Browser potenziell unterschiedliche Daten befinden. Außerdem kann nicht gewährleistet werden, dass das im Snapshot verwendete Datenmodell auf dem aktuellen Stand ist.

Unsere Empfehlung ist, insbesondere bei größeren Prototypen oder wenn viele verschiedene Personen involviert sind, die eigenen Voraussetzung genau zu prüfen und abzuwägen ob eine browser-basierte Datenhaltung für den eigenen Anwendungsfall sinnvoll ist. Für kleine Prototypen oder einen Proof-of-Concept kann ein Snapshot-Management aber durchaus eine sinnvolle und kostengünstige Ergänzung sein.

Seite teilen