Hype-resistente Web-Frontends für langlebige Anwendungen
Wie baut man heute Web-Frontends? Folgt man dem Mainstream, dann folgt man einem einfachen Rezept. Man wähle ein Web-Framework, mit dem man im Browser Oberflächen entwickelt. Die Auswahl des Frameworks wird oft auf die Frage reduziert, ob man nun Angular, React oder Vue nimmt – jeder weiß aber, dass es noch eine Menge von Alternativen gibt [1].
Das Web-Framework bietet in der Regel ein Komponentenmodell an, über das man Controls aus Control-Bibliotheken zu Dialogen zusammenbaut und über das man die Control-Verarbeitung an die logische Verarbeitung im Client anbindet. Die Programmiersprache ist entweder JavaScript selbst oder eine höhere Sprache wie z. B. TypeScript, die letztlich in JavaScript transpiliert wird. Von dem Client-Programm werden nun i. d. R. per REST-Protokoll Services der Server-Seite angesprochen. Je nach Architektur können das natürlich auch mehrere Server sein (z. B. bei Verteilung der Logik auf Microservices).
Aufbau von Abhängigkeiten
Je mehr im Browser codiert wird, desto mehr begibt man sich in Abhängigkeit sowohl von den Browser-Technologien selbst (HTML, CSS, JavaScript) als auch vom dem verwendeten Web-Framework. Ein Wechsel des Web-Frameworks kommt i. d. R. einer kompletten Re-Implementierung des Clients nahe. Je umfangreicher der Client-Teil der Anwendung ist, desto teurer wird also ein potenzieller Umstieg.
Mismatch beim Lebenszyklus
Warum und wann sollte man überhaupt über potenzielle Umstiegsszenarien nachdenken? Ein wichtiger Grund – und um diesen geht's in diesem Artikel – ist der lange Lebenszyklus umfangreicher Anwendungen. Hier geht es zum Beispiel um Unternehmens- und Industrieanwendungen, die gerne einen Lebenszyklus von 15-20 Jahren haben. Das klingt utopisch?
Die Entwicklung eines solchen Anwendungssystems dauert durchaus Jahre. Grund: Sie haben einen immensen funktionalen Umfang. Ein ERP-System, eine Buchhaltung mit Controlling, eine Personalwirtschaft, ein CRM-System, eine Lagersteuerung, eine Behördensoftware – alle diese Systeme bestehen aus hunderten von Dialogen mit unterschiedlichster Nutzungsbandbreite: von der "stumpfen" Erfassung von Stammdaten, über die "kreative" Steuerung der Abläufe mit Hilfe von Leitständen bis hin zum flexiblen Reporting mit Drill-Down in die Echtdaten – alles ist dabei! Solche Systeme stehen oft in Konkurrenz zu bereits existierenden Lösungen "aus den 90ern", die zwar architekturmäßig am Ende ihres Lebenszyklus, aber funktional tief ausgeprägt sind.
Werden diese Anwendungssysteme durch ein Softwarehaus erstellt, so plant dieses, diese für eine ganze Weile zu verkaufen – ob nun "on premise" oder "as a service". Und dann kommt ja erst die eigentliche Nutzung durch den Kunden. Und die ist mit z. B. 10 Jahren noch kurz umschrieben! Summa summarum ergibt das zusammen locker 15-20 Jahre.
Vergleichen wir nun den Lebenszyklus solcher Anwendungssysteme mit dem Lebenszyklus von Web-Frameworks: Die Welt der Web-UI-Entwicklung ist immer noch eine sehr volatile. Frameworks und mit ihnen verbundene Hypes kommen und gehen in regelmäßigen Abständen. Schaut man alleine auf die Liste der von Google stammenden Frameworks im Bereich der Web-Entwicklung, so kann man aufreihen: GWT (Google Web Toolkit), Dart, Angular JS, Angular, Polymer und gerade aktuell Flutter als Cross-Client-Framework – und diese Liste ist bestimmt nicht vollständig!
Sprich: Wenn Sie heute auf das Web-Framework X setzen, weil es gerade dem Mainstream entspricht, so können Sie davon ausgehen, dass spätestens im Jahre 2030, wenn Ihr Anwendungssystem in der Blüte seines Lebenszyklus' stehen sollte, dieses Web-Framework zu den nicht mehr aktuellen gehört und "out of hype" ist. Sie sind dann mit Ihrem Anwendungssystem nicht mehr im dann aktuellen Mainstream, sondern gehören technologisch bereits zu den "etwas Überholten". Was tun?
Alternative 1: "Es betrifft mich gar nicht!"
Zunächst mal dürfen Sie sich die Frage stellen: Betrifft mich dieses Problem wirklich?
Viele Produkte und Projekte heute – insbesondere wenn es sich um Lösungen für den Endkonsumenten handeln – haben zum einen nicht den funktionalen Umfang, der im vorigen Kapitel skizziert wurde. Ein Wechsel des Web-Frameworks tut hier zwar weh, ist aber durchführbar. Zum anderen spielt in diesen Systemen oft die Aktualität der Benutzeroberfläche eine große Rolle – sie ist das zentrale Aushängeschild der Anwendung. Hier will man direkt auf Web-Technologien durchgreifen und sich diese nicht durch zwischengelagerte Abstraktions-Stacks verbauen. Der erhobene Zeigefinger des vorigen Kapitels gilt hier also nicht!
Alternative 2: "Dann wechseln wir halt nicht!"
Bleiben wir aber bei den umfangreichen Anwendungen: Alle Web-Frameworks haben ja eines gemeinsam: sie setzen auf den Grundtechnologien des Browsers auf: HTML, CSS, JavaScript. Browser sind im vergangenen Jahrzehnt zunehmend kompatibler geworden. Eine Anwendung, die heute mit Framework X erstellt wird, wird auch mit hoher Wahrscheinlichkeit noch im Jahre 2030 im Browser laufen.
Für den Macher eines Anwendungssystems stellt sich aber nicht die Frage einer prinzipiellen Lauffähigkeit! Sondern: Das System soll auch im Jahre 2030 ein technologisch modernes, effizientes System sein, das sich den Strömungen und Trends flexibel anpassen kann – und das genug Attraktivität hat, um nach außen hin Kunden zu gewinnen und nach innen hin die Entwickler "bei der Stange zu halten". Kurz: Das System soll in 2030 nicht am Ende seines technischen Lebenszyklus stehen – sondern mittendrin!
Insofern ist die Alternative des "Dann wechseln wir halt nicht!" eine Wette auf die Zukunft – mit teuren Risiken.
Alternative 3: "Architektur!"
Wie immer gilt: Wer sich von einer Technologie unabhängig machen will, der muss eine Abstraktionsschicht definieren. Auf der einen Seite der Abstraktionsschicht steht derjenige, der auf einer semantischen Ebene definiert, was er will. Auf der anderen Seite – hinter der Abstraktionsschicht – gibt es einen anderen, der diesen Willen mit einer dazu geeigneten Technologie umsetzt.
Konkret: Aus Sicht eines Anwendungsentwicklers ist und bleibt ein Dialog nichts anderes als eine dynamische Ansammlung hierarchisch strukturierter Controls, die attributiert werden und die Events über z. B. Benutzeraktionen aussenden. Diese Struktur kann auf einer semantischen Objektebene einfach definiert werden – ohne irgendein Wissen darüber zu haben, wie nun ein konkretes Control mit Hilfe welchen Frameworks auch immer im Browser auf den Bildschirm kommt.
Umgekehrt kann auf diese Struktur ein technisch begabter UI-Spezialist zugreifen und daraus mit einem gängigen Web-Framework die Oberfläche im Web hervorbringen, die dieser Struktur entspricht.
Und schon begeht man den konkreten und wichtigen Schritt der Entkopplung des Anwendungssystems vom Web-Framework! Der Anwendungsentwickler programmiert ein "logisches Control-Modell", das über eine entsprechende Interpretationsschicht in "echte" Controls umgesetzt wird, letztendlich im Browser also in DOM-Elemente. Ein Änderung der Web-Technologien spielt sich somit nicht mehr in der Anwendung ab, sondern dahinter – auf der technischen "Renderer-Ebene".
In diesem Szenario wird nun also das eigentliche Rendering im Client abgekoppelt, so dass die Abhängigkeiten von einem konkreten Web-Framework sich auf diesen Teil beschränken. Doch immer noch sind wesentliche Teile der Dialogverarbeitung der Anwendung selbst in der Technologie des Browsers gebunden. Konkret: Unmengen von z. B. JavaScript-Code entstehen "links des logischen Control-Modells".
Eine noch wesentlich stärkere Abkopplung der Client-Verarbeitung erhält man, wenn man einen Schritt weiter geht und den Client als eigenständigen, "technischen" Service definiert, dessen Aufgabe es ist, einen Dialog aufzubereiten, dessen Aufbau über eine explizite Netzwerkschnittstelle übermittelt wird.
Konkret: Im Client läuft ein Programm "Dialogaufbereitung", das über ein z. B. XML- oder JSON-basiertes Protokoll den Aufbau eines Dialoges übersendet bekommt. Das Client-Programm rendert diese Dialogbeschreibung in eine entsprechend aufgebaute Benutzeroberfläche. Eingaben und Aktionen des Benutzers werden durch das Programm empfangen und zu gegebenen Zeitpunkten, wiederum über eine explizite Schnittstelle, an die "Dialogverarbeitung" weitergegeben.
Das Ergebnis der Dialogverarbeitung wird nun in Form von Dialogänderungen an den Client zurückgegeben. Wichtig ist hierbei, dass auf Performance- und Laufzeitgründungen nur geänderte Inhalte der Dialogbeschreibung zum Client gesendet werden: Der Dialog im Client soll ja nicht jedes Mal neu gerendert werden, sondern stabil stehenbleiben, sodass die Änderungen in den bereits gerenderten Dialog eingearbeitet werden.
Die Implementierung des Clients im Browser erfolgt als Single-Page-Application (SPA) – also als eigenständiges JavaScript-Programm. Die Wahl des konkreten Web-Frameworks für dieses JavaScript-Programm ist natürlich wichtig – schlägt aber nicht auf die eigentliche Dialogverarbeitung der Anwendung durch! Das Client-Programm ist architektonisch abgekoppelt und kann technologisch umgestaltet werden, ohne Folgen für die Anwendung.
Sie sehen: Die eigentliche Dialogverarbeitung wird nun nicht mehr im Client ausgeführt, sondern auf der Serverseite der Anwendung – und ist damit komplett unabhängig von der Technologie des Clients. Und dies erlaubt wiederum aus Sicht der langfristigen Unabhängigkeit enorme Freiheitsräume – bis hin zum kompletten Wechsel der Client-Architektur. Wer weiß denn, was in den nächsten 15-20 Jahren so alles passieren wird?!
Ein Blick zurück – Terminals...
Die beschriebene Architektur der Abkopplung der Client-Verarbeitung ist prinzipiell nichts Neues.
Wer die grün-schwarzen Terminals aus den Achtziger- und Neunziger-Jahren kennt, der weiß, dass diese Architektur – in vereinfachter Form! – bereits damals Grundlage der UI-Verarbeitung war. Zum "Terminal-Client" wurde über ein Character-Protokoll (25 Zeilen mit 80 Buchstaben...) eine Bildschirmbeschreibung gesendet. Benutzereingaben wurden zum Server gesendet und dort z. B. in ein Cobol-Programm eingearbeitet. Zurück zum Terminal ging eine erneute Dialogbeschreibung (wieder 25 Zeilen mit 80 Buchstaben...).
Man mag über die heutige Benutzungs-Qualität dieser Terminal-Clients lächeln. Aber man muss zugeben: Es gibt sie heute noch! Der Grund ist: Auf Basis des expliziten Protokolls des unabhängigen Terminal-Clients konnte dieser in allen UI-Architekturen seit den Achtzigern einfach re-implementiert werden – bis hin zur Implementierung des Terminal-Clients innerhalb des Browsers. Die Unternehmensanwendungen aus den Achtzigern und Neunzigern laufen also heute noch – ...ein ziemlich langer Lebenszyklus, oder?
Man sieht aber genauso auch sofort das zentrale Problem des Protokolls zwischen Terminal-Client und Server: Das Protokoll war stark an die Control-Welt der Achtziger-Jahre angepasst und erlaubte es nicht, neue Controls einfach zu integrieren. Und in den Achtzigern gab es eben nur Labels, Eingabefelder und Funktionstasten.
Die Lehre daraus: Das Protokoll zwischen einer Dialogverarbeitung und einem Dialog-Client muss offen sein für die Einbindung neuer graphischer Komponenten und darf nicht an ein vorgegebenes Layouting-Prinzip ("Character!") gebunden sein.
Ein Blick zurück – Plain HTML
Auch der ursprüngliche Browser zum Ende der Neunziger war ein explizit abgekoppelter Client – das Protokoll zum Server hin hieß und heißt "http": HTML-Inhalte gehen zum Client, Eingaben und Änderungen werden in Form von http-get/post zum Server übermittelt. Erst dieses Protokoll machte den Erfolg des Browsers möglich: Er war als eine generische Rendering-Engine konzipiert – der semantische Inhalt einer dargestellten Seite war ihm komplett egal, das war die Sache der auf dem Server befindlichen Anwendung. Somit konnten sich auf Basis dieses Protokolls beliebige inhaltliche Anwendungsszenarien entwickeln.
Nun aber das Problem: Da das primäre Ziel des Browsers die Darstellung von Texten war, kannte er keine Änderungsverarbeitung: HTML-Inhalte wurden immer bei Dialogänderungen komplett neu gerendert – mit entsprechend schlechter Performance und Usability. Das Sich-Ändern von HTML-Seiten wurde nicht in das http-Protokoll selbst aufgenommen, sondern es wurde durch javascript-basierte Verfahren (AJAX) in den Browser hineingestülpt – am eigentlichen http-Protokoll vorbei.
Die Lehre daraus: Das Protokoll und die Verarbeitung eines Dialog-Clients müssen Änderungen beherrschen!
Ein Blick in die Gegenwart
Auch in der heutigen Zeit gibt es Repräsentanten des abgekoppelten Dialog-Clients: Explizit dem Gedanken des über eine langfristig stabile Schnittstelle abgekoppelten Clients folgt das Web-Framework "CaptainCasa Enterprise Client".
Die Entwicklung dieses Frameworks startete bereits im Jahre 2007 – damals war der abgekoppelte Client eine Java-Swing-basierte Implementierung – hatte also mit dem Browser technologisch selbst wenig zu tun! Im Jahre 2012 wurde dieser Implementierung eine parallele Java-FX-basierte Implementierung hinzugefügt. Im Jahre 2017 kam dann die Umsetzung des Clients in Form einer Javascript-basierten Single-Page-Application. Das Protokoll zwischen dem CaptainCasa-Client und der Java-basierten Server-Verarbeitung ist "XML over http" – in dem XML können beliebige neue Komponenten eingebunden werden.
Auch hier gilt: Für nutzende Anwendungen war der Übergang vom Java-Swing-Client aus dem Jahre 2007 zum HTML-basierten Client von heute ein "Turnkey" – also ein Austausch des Client-Renderers. Dieselbe Unternehmensanwendung, die vorher unter einem Swing-Client bedient wurde, konnte 2012 unter einem Java-FX-Client verwendet werden – und ab 2016 unter einem Browser-Client.
Auch andere Frameworks kann man in der Ecke des abgekoppelten Clients finden – wobei hier der Fokus nicht so stark auf der langfristig stabilen Schnittstellenbeziehung zwischen Client und Server gelegt ist. Zu diesen Frameworks gehören Vaadin und Eclipse RAP. Daneben wird das Prinzip des abgekoppelten Clients in vielen Anwendungsprojekten eigenständig entwickelt, in der Regel mit dem Hintergrund, die Entwicklung im Browser-Umfeld effizienter zu gestalten – und eine Trennung zwischen Anwendungs-Dialog-Entwicklung und Browser-Umsetzung durchzuführen.
Fazit
Entwickeln Sie eine umfangreiche Anwendung mit langer Laufzeit? Dann kommen Sie um die Frage nicht herum, wie Sie eine entsprechend langfristig ausgelegte Browser-Frontend-Strategie definieren. Und diese Frage ist mit der Wahl eines Web-Frameworks nicht beantwortet! Es kommt darauf an, wie Sie dieses nutzen – direkt oder mit einer Abstraktion dazwischen!
Eines ist sicher: Wenn das gesamte User-Interface Ihrer Anwendung in sieben Jahren neu codiert werden muss, weil Ihr Web-Framework nicht mehr aktuell ist, dann wird es teuer! Wenn sich eine Änderung des Web-Frameworks aber nur auf das zentrale Reimplementieren eines Rendering-Clients beschränkt, dann werden Sie den Wert der Abkopplung zu schätzen wissen!
Und noch eines ist sicher: Die UI-Welt ist noch nicht "mature", sie wird sich konstant weiter- und um-entwickeln. Neue Frameworks, neue Begriffe, neue Hypes werden weiterhin kommen und gehen – es bleibt aufregend!