Die Generierung eines Formulars aus einem JSON-Deskriptor ist ein wiederkehrendes Problem in der Frontend-Entwicklung. In verschiedenen Geschäftsbereichen gibt es viele komplexe Einschränkungen in Bezug auf die Attribute, die eine Validierungslogik erfordern, um zu verhindern, dass schlechte Anfragen durchkommen. Wie können wir die Validierungsdeskriptoren zu unserem Vorteil nutzen, um die Erstellung einer Benutzeroberfläche zu beschleunigen? Das wollen wir herausfinden.
Der Ablauf der Richtlinienerstellung ist ein zentraler Bestandteil unserer internen Prozesse. Er wird sowohl von den Geschäftsabläufen als auch von den Entwicklern verwendet, um Verträge in unserer Plattform zu erstellen. Die Erstellung einer Police umfasst 3 API-Anfragen:
Jede Anfrage, die an die Policen-APIs gesendet wird, wird durch eine Reihe von Validierungsregeln überprüft, die wir in unserer eigenen Metasprache geschrieben haben. Der Zweck dieser Validierungsregeln ist es, die Kohärenz (Zusammenhang) der Daten innerhalb jeder Anfrage und zwischen den Anfragen zu gewährleisten. Sie legen Einschränkungen für die Attribute der Nutzdaten fest, wie z. B. einen Grenzbereich für numerische Werte, eine Reihe möglicher String-Werte, die ein Attribut haben kann, oder einen Regexp, dem ein Feld folgen muss (Telefonnummer, Bankkonto IBAN, ...)
Früher haben wir die UI für die Richtlinienerstellung für jede neue Produktlinie manuell implementiert. Wir kopierten und änderten geringfügig die Reaktionskomponenten von bereits implementierten Policen-Erstellungsabläufen, um nahezu identische Bildschirme neu zu implementieren (seufz).
Diese Lösung führte zu unzähligen Duplikaten. Sie erforderte die Erstellung von fest kodierten React-Komponenten auf der Grundlage der Validierungsregeln, die sich im Laufe des Produktlebenszyklus ändern können. Dies bedeutete noch mehr manuelle Eingriffe.
Dieser Prozess wurde aufgrund der steigenden Anzahl von Produkten in unserem Angebot immer kostspieliger. Die Duplizierung von Formularkomponenten wurde ineffizient.
Unsere Codebase-Struktur sah in etwa so aus:
Da wir viele Produkte einbinden, wurde dieser Ansatz nach einer Weile ziemlich mühsam. Da haben wir uns gedacht: Wäre es nicht cool, wenn wir diese Benutzeroberfläche einfach generieren könnten? Immerhin sind die Komponenten fast identisch, und die Informationen sind bereits in unseren Eingabevalidierungsregeln enthalten. Also machten wir uns daran, einen Prototyp für den UI-Generator zu schreiben.
Bei ELEMENT verwenden wir unsere eigene Metasprache zur Validierung der Policen- und Angebotsanfragen. Die Integration eines neuen Produkts wird von der Definition seiner Validierungsregeln begleitet. Das sieht folgendermaßen aus:
Unser Ziel ist es, ausgehend von den Validierungsregeln eine Benutzeroberfläche für die Angebots-, Kunden- und Policenanfragen zu generieren, um unseren Integrationsprozess für neue Produkte zu beschleunigen, da wir uns so die Erstellung/Refrakturierung der UI-Komponenten ersparen. Außerdem wird unsere Codebasis dadurch wartungsfreundlicher, da wir nicht auf einzelne Anwendungsfälle eingehen müssen.
Wir haben uns entschieden, unser UI-Layout als Wizard-Flow zu gestalten, bei dem jeder Schritt eine Anfrage an unsere API sendet. Insgesamt gibt es 3 Schritte: Angebotsberechnung, Kundendetails und Policenerstellung.
Der neue Assistentenablauf ist in einem eigenen Mikro-Frontend gespeichert, auf das über unsere administrative Benutzeroberfläche zugegriffen wird.
Lassen Sie uns die wichtigsten Punkte dieses Architekturdiagramms auflisten:
So sieht die Fehlermeldung der Backend-Validierung aus:
Der Feldgenerator sollte mit einzelnen Feldern, Arrays oder Referenzen auf ein anderes Feld arbeiten. Dieses Feld kann sich auch in einem anderen Schritt des Ablaufs befinden. Zum Beispiel werden Felder im Schritt der Policenerstellung oft mit Informationen aus dem Schritt der Preisgestaltung abgeglichen.
Wir haben folgenden Entwurf für den Feldgenerator entwickelt:
In unserem geplanten Entwurf werden sowohl die Regeln für einzelne Felder als auch für Arrays auf die Wiedergabe von <Field/>-Komponenten reduziert. <Field/> erhält als Requisite eine primitive Komponente, die dem Datentyp der Regel entspricht, z. B. InputNumber für Zahlen, Select für mehrere Optionen mit festem Wert, Switch für boolesche Werte und so weiter. Wir müssen diese Komponenten nicht von Grund auf neu erstellen, wir können die von Ant Design (https://ant.design/) bereitgestellten Komponenten verwenden, der React-Bibliothek, die wir für die Implementierung unserer Benutzeroberfläche gewählt haben.
Wir wollten eine populäre React-Bibliothek wählen, um uns bei Problemen auf die Unterstützung der Community verlassen zu können. Außerdem konnten wir so darauf vertrauen, dass die Bibliothek auf dem neuesten Stand gehalten wird.
Nachdem wir uns verschiedene React-Formularmanagement-Bibliotheken wie Formik, Final Form, react-form, react-hook-form und redux-form angeschaut hatten, entschieden wir uns für react-hook-form, die für uns am besten geeignet war.
Unsere Bewertung wurde durch den aktuellen Stand unserer Backend-Architektur und die Notwendigkeit, unsere Validierungsregeln zu unterstützen, bestimmt.
Die Formik-Bibliothek bietet eine Hook-Funktion, die wir verwenden könnten, aber sie funktioniert nicht mit den <Field/>-, <FieldArray/>- oder <ErrorMessage/>-React-Komponenten. In unserem Fall ist es wichtig, diese Komponenten zu unterstützen, da wir uns entschieden haben, Ant Design form in unseren Backoffice-Mikro-Frontends zu verwenden.
React-form, auch wenn es noch weit verbreitet ist, wird nicht mehr gepflegt. Wir möchten vielleicht eine Bibliothek mit aktiver Community-Unterstützung für etwas frisch Implementiertes verwenden.
Wie Formik bietet auch final-form keine "native" Validierungsmethode. Das würde bedeuten, dass die Last des Schreibens von benutzerdefinierten Validierungen bei uns liegen würde, und davon gibt es eine Menge in unserer Meta-Sprache, die nächste!
React-hook-form hat einige Standard-Validierungsmethoden, um schnell eine Formularvalidierung einzurichten, was sehr hilfreich schien. Es ist auch mit Ant Design form kompatibel, also haben wir uns entschieden, diese Bibliothek zu verwenden.
Schauen wir uns an, wie react-hook-form funktioniert. Ein einfaches Beispiel ist die Verwendung des grundlegenden useForm()-Hooks von react-hook-form (Beispiel verfügbar unter https://react-hook-form.com/):
Wir verwenden die <Field/>-Komponente, passen sie je nach Datentyp der Regel an und injizieren die Validierungsregeln in sie:
In unserem Fall müssen wir auch unsere eigene Validierungslogik und Fehlerbehandlung implementieren. Dafür verwenden wir den useController()-Hook, der in der react-hook-form-Bibliothek enthalten ist.
Hier ist die Implementierung von <Field/>:
Die Implementierung einer Formular-UI mit solider Validierung ist ein immer wiederkehrendes Problem bei der Frontend-Entwicklung. Wir haben uns die bereits vorhandene Metasprache zunutze gemacht, um die Felderzeugung in unseren Formularen zu steuern. Unsere Implementierung musste viele Probleme überwinden, die durch die große Bandbreite an Regeln in unserer Metasprache verursacht wurden. Beispielsweise wirken sich Felder eines Schritts auf einen anderen Schritt aus, Überprüfungsregeln, die nur unter einer bestimmten Bedingung erzwungen werden, und Überprüfungsregeln, die auf Arrays angewendet werden.
Wir sind mit unseren Ergebnissen sehr zufrieden. Der Ablauf der Richtlinienerstellung ist bei Onboardings kein Thema mehr, er funktioniert einfach so. Jetzt ist es an der Zeit, darüber nachzudenken, wo wir diesen Ansatz auch in anderen Lösungen einsetzen könnten.