Web Development & JavaScript - JAX https://jax.de/blog/web-development-javascript/ Java, Architecture & Software Innovation Mon, 19 Nov 2018 15:37:39 +0000 de-DE hourly 1 https://wordpress.org/?v=6.4.2 So entwickeln Sie zukunftssichere Single-Page Applications: Angular, React, Vue.js? https://jax.de/blog/web-development-javascript/single-page-applications-zukunftssicher-entwickeln/ Tue, 27 Mar 2018 15:28:36 +0000 https://jax.de/?p=63923 Single-Page Applications (SPAs) entwickeln sich zu einem festen Bestandteil der Anwendungslandschaft in Unternehmen. Die hohe Dynamik in der Welt der Web-Frontends erweist sich aber immer wieder als ein großer Unsicherheitsfaktor. Stellt sich doch die Frage: Kann man SPAs überhaupt zukunftssicher gestalten?

The post So entwickeln Sie zukunftssichere Single-Page Applications: Angular, React, Vue.js? appeared first on JAX.

]]>

von Sven Koelpin

Eine langfristige technologische Sicherheit ist für viele Unternehmen ein essenzieller Faktor. Anders als zum Beispiel beim Enterprise-Java-Standard, der über einen langen Zeitraum stabile APIs und weitestgehend gleichbleibende Programmierkonzepte garantiert, hat es eine solche Stabilität in der Welt der Web-Frontends zuletzt nicht gegeben. Vielmehr hat es hier den Anschein, als ob alle paar Wochen neue Frameworks, Tools oder Best Practices das Licht der Welt erblicken. Jede dieser Neuerungen scheint dabei das Web zu revolutionieren – die Autoren behaupten das zumindest. Eine Folge davon: Was heute noch als guter Frontend-Stack betitelt wird, ist ein Jahr später oftmals nicht mehr State of the Art.

Single-Page Applications: Angular, React, Vue.js?

Im Blogeintrag [1] „The Brutal Lifecycle of JavaScript Frameworks“ wurde der Lebenszyklus von JavaScript-Frameworks auf Basis von Daten der Stack-Overflow-Trends-Tools [2] analysiert. Die Ergebnisse veranschaulichen zwei Dinge (Abb. 1). Auf der einen Seite ist die Schnelllebigkeit vieler SPA-Frameworks zu erkennen. Diese durchleben zumeist in einer kurzen Zeit einen raschen Anstieg, haben aber nach spätestens zwei bis drei Jahren so gut wie keine Relevanz mehr am Markt. Auf der anderen Seite ist aber auch zu erkennen, dass sich neben den zahlreichen und kurzlebigen „kleineren“ SPA-Frameworks mit Angular und React zwei Big Player herauskristallisiert haben. Diese beiden SPA-Frameworks werden von je einem Technologiegiganten, Angular von Google und React von Facebook, entwickelt. Sowohl Angular als auch React verzeichnen seit über zwei Jahren ein starkes Wachstum, und es ist nicht zu erwarten, dass sich dieser Aufschwung in absehbarer Zeit signifikant abschwächen wird.

Auch Vue.js hat im letzten Jahr deutlich an Aufschwung erfahren, obgleich die Nutzungszahlen die der beiden großen Frameworks noch lange nicht erreichen. Der Anstieg bei Vue.js ist vermutlich nicht zuletzt darauf zurückzuführen, dass für den Einstieg keine unbedingte Notwendigkeit dazu besteht, in die oftmals überwältigende Welt der modernen JavaScript-Entwicklung einzutauchen [3].

Man kann natürlich nicht behaupten, dass die Daten von Stack Overflow die Realität von Nutzungszahlen in ihrer Vollkommenheit widerspiegeln. Sie bieten aber dennoch einen guten Überblick über die aktuelle Welt der SPA-Frameworks und bestätigen, dass das Gesamtinteresse an Single-Page Applications in den letzten Jahren um ein Vielfaches angestiegen ist.

 


Abb. 1: Der brutale Lebenszyklus der JavaScript Frameworks (Erstellt mit Stack Overflow Trends)

 

 

Ist wirklich alles unsicher?

Die Schnelllebigkeit in der Welt der Web-Frontends ist zwar immer ein großer Unsicherheitsfaktor, es lässt sich aber nicht bestreiten, dass die Veränderungen der Frameworks und Tools in den letzten Jahren das Entwicklerleben stark vereinfacht und Single-Page Applications erst richtig Enterprise-fähig gemacht haben. Das beste Beispiel dazu ist der Sprung von AngularJS zu Angular, bei dem das Framework grundlegend verändert und damit ein wichtiger Grundstein für die moderne SPA-Entwicklung gelegt wurde.

Derartige Big-Bang-Versionssprünge werden sich aber in Zukunft, zumindest bei den großen Frameworks Angular und React, wohl kaum wiederholen. Die Community hinter diesen Bibliotheken wird immer stärker – und dass die Nutzergemeinde durchaus Einfluss auf die Entscheidungen der Frameworkhersteller haben kann, hat sich eindrucksvoll bei der Lizenzänderung von React im letzten Jahr gezeigt.

Mittlerweile bieten SPA-Frameworks zudem meistens sinnvolle Vorgehensmodelle und Tools, um mit Breaking Changes umzugehen. So gibt es zum Beispiel bei React die Regel, dass Breaking Changes des API eine Major-Version lang in der alten und neuen Variante unterstützt werden, bevor nur noch das neue API zur Verfügung steht. Zudem gab es bisher immer Tools [4], die eine bestehende Codebasis weitestgehend automatisiert auf neue Patterns oder APIs migrieren konnten. Dieses Vorgehen ist sicherlich auch eine Folge davon, dass Facebook React selbst aktiv im Einsatz hat.

Auch wenn Angular und React mittlerweile einen Großteil der SPA-Gemeinde bedienen, schwächt das die Innovationskraft der JavaScript-Community noch lange nicht ab. Bei der Menge an neuen Tools, Patterns und Best Practices fällt es so oftmals schwer, den Überblick zu behalten (aka „JavaScript Fatigue“). Anstatt sich aber von der Vielzahl der neuen Dinge verunsichern zu lassen, sollte diese Entwicklung eher positiv gesehen werden. Schließlich befeuern die neuen Frameworks und Werkzeuge, die in einigen Aspekten sogar besser und schneller sind als die „Großen“, den Wettbewerb und lassen diese in Zugzwang geraten (z. B. webpack vs. Parcel, React vs. Preact).

 

SPAs vorausschauend entwickeln

Es wäre sicherlich blauäugig, davon auszugehen, dass die aktuelle Welt der Web-Frontends in zwei bis drei Jahren noch die gleiche ist wie heute. Zwar ist nicht zu erwarten, dass die „großen“ SPA-Frameworks dann keine Relevanz mehr haben. Es ist durch die ständige Weiterentwicklung der Plattform „Web“ aber wahrscheinlich, dass sich Single-Page Applications und damit auch die Frameworks stetig neuen technischen Herausforderungen und Anforderungen stellen müssen. Und das ist in gewisser Weise auch gut so, denn das Web ist als Applikationsplattform aktuell noch weit davon entfernt, perfekt zu sein.

Wer heute schon SPAs entwickelt, dem bleibt also nichts anderes übrig, als die hohe Dynamik in diesem Bereich für die eigene Anwendung abzufedern. Das lässt sich beispielsweise mit einer robusten Web-Frontend-Architektur ausprobieren. Glücklicherweise haben sich in den letzten Jahren nicht nur SPA-Frameworks, sondern weitestgehend auch architektonische Prinzipien in Single-Page Applications manifestiert. Die Verwendung dieser kann die Basis für eine robuste SPA-Architektur legen und sie widerstandsfähiger gegen etwaige zukünftige Veränderungen der Außenwelt gestalten.

 

Der Web Development & JavaScript Track auf der W-JAX 2018

 

SPAs komponentenbasiert entwickeln

Die meisten der aktuell relevanten SPA-Frameworks arbeiten komponentenbasiert. Bei dieser Art von Single-Page Applications wird die gesamte Anwendung auf Basis von Komponenten, die in einer Baumstruktur organisiert sind, implementiert. Häufig werden die Komponenten einer Applikation in Smart Components und Dumb Components unterteilt (Abb. 2).

Dumb Components haben ihren Namen aus dem Grund, dass sie im Sinne des Wissens über den aktuellen Gesamtstatus einer Applikation „dumm“ sind. Sie bekommen die Daten, auf denen sie operieren, ausschließlich über ihre Elternkomponenten hereingereicht. Natürlich können Dumb Components trotzdem auch komplexe Logik enthalten, sie sollten aber weitestgehend wiederverwendbar und flexibel an verschiedenen Stellen einer Applikation einsetzbar sein. Klassische Beispiele für Dump Components sind Listen, Tabellen oder Eingabefelder. Sie werden häufig nicht selbst entwickelt, sondern können auch aus Komponentenbibliotheken [5], [6] bezogen werden.

Smart Components haben Zugriff auf den Gesamtstatus der Anwendung. Sie sind deshalb häufig mit den Services (zumeist bei Angular) oder Stores (zumeist bei React) der Applikation verbunden und verteilen die Daten an die unterliegenden Komponenten weiter. Smart Components sind häufig die Einstiegspunkte zu bestimmten Bereichen einer Anwendung. Sie kapseln also ganze Seiten oder Bereiche von Seiten, die bestimmte Use Cases abbilden.

Die Verwendung von Smart und Dumb Components hat sich bisher als gutes Mittel für die Strukturierung einer komponentenbasieren SPA erwiesen. Sie können dabei helfen, die Architektur weniger anfällig für grundlegende technische Veränderungen zu machen.


Abb. 2: Smart vs. Dumb Components

State-Management überdenken

Anders als bei serverseitig gerenderten Webanwendungen, deren Applikationsdaten zumeist nur auf dem Server verwaltet werden, liegen bei Single-Page Applications Teile des Applikationsstatus im Client (Application State). Dieser Status kann vielfältig sein, und die Verwaltung und Manipulation sind häufig alles andere als trivial. Der Application State lässt sich in Domain State (domänenbezogener Status, häufig „Entities“), UI State (UI-bezogener Status, z. B. „Ist ein Modaldialog geöffnet?“) und Component State (z. B. „aktueller Text in einem Textfeld“) unterteilen. Zusätzlich haben die Daten zumeist noch eine unterschiedliche Lebensdauer. Man unterscheidet hier zwischen Short-Term State (flüchtige Daten), Medium-Term State (Daten, die die gesamte Applikationslebensdauer überleben) und Long-Term State (Daten, die auch nach dem Schließen der Anwendung noch existieren).

Die Kombination der verschiedenen States und die unterschiedliche Lebensdauer der Daten kann zu sehr komplexen Datenflüssen führen. Bei komponentenbasierten Single-Page Applications hat sich zur Abschwächung dieser Komplexität das Flux-Pattern (auch Flux-Architektur) durchgesetzt. Es gibt verschiedene Abwandlungen und Implementierungen von Flux, die bekannteste ist Redux [7]. Zugrunde liegt die Idee, dass Teile des Application States zentral verwaltet werden und jegliche Daten stets unidirektional, also nur in eine Richtung, fließen. Dabei werden Änderungen des Application States an Smart Components propagiert, die die jeweiligen Datenänderungen wiederum an die Dumb Components weitergeben können (Abb. 2).

Unidirektionale Datenflüsse eignen sich sehr gut bei hierarchischen Komponentenbäumen, wie wir sie in den meisten SPAs finden. Deshalb gibt es von den bekanntesten Flux Libraries in der Regel auch Implementierungen für alle großen SPA-Frameworks.
Für eine robuste und nachhaltige SPA-Architektur kann es sinnvoll sein, eine State-Management-Library einzuführen und so die Verwaltung des Applikationsstatus vom Single-Page-Application-Framework zu trennen. Allerdings gibt es auch oftmals Fälle, in denen ein externes State-Management mehr Arbeit macht, als dass es Nutzen bringt. Der Einsatz sollte deshalb abhängig von der Komplexität der Applikation und des zu verwaltenden Status, nicht aber unbedingt von der Größe der Anwendung, gemacht werden.

Wie mit ständigen Updates umgehen?

Bei Angular und React standen in den letzten beiden Jahren ungefähr alle sechs Monate neue Major-Releases an – teilweise mit rudimentären Änderungen der APIs. Zwar gibt es, wie bereits erwähnt, zumeist einigermaßen schmerzfreie Migrationspfade. Diese funktionieren aber nur problemlos, wenn vorher bereits regelmäßig aktualisiert wurde. Noch dazu kommen ständige Versionsänderungen in etwaigen anderen Paketen und Tools, die man für die Entwicklung einer SPA benötigt. Um hier nicht abgehängt zu werden, ist es sinnvoll, regelmäßig die Versionen der installierten Pakete zu überprüfen und gegebenenfalls frühzeitig zu aktualisieren. Das Überprüfen der Versionen kann manuell oder mithilfe von Tools erreicht werden. Beispielsweise können Versionschecks automatisiert in den Build-Prozess eingebunden werden (z. B. mit npm-check-updates [8]). Für eine robuste SPA-Architektur ist es zum aktuellen Zeitpunkt unbedingt nötig, Versionsupdatemanagement als regelmäßigen Workflowschritt zu installieren.

 

Free: Mehr als 40 Seiten Java-Wissen


Lesen Sie 12 Artikel zu Java Enterprise, Software-Architektur und Docker und lernen Sie von W-JAX-Speakern wie Uwe Friedrichsen, Manfred Steyer und Roland Huß.

Dossier herunterladen!

 

Fazit

Wer heute auf SPAs setzt, ist schon viel besser dran, als noch vor zwei Jahren – das Umfeld ist spürbar erwachsener geworden. Beispielsweise wurde für AngularJS, dem Vorgänger von Angular, Anfang des Jahres eine dreijährige Long-Term-Support-Version angekündigt, und das obwohl das Framework im Gegensatz zur Neuauflage stetig an Nutzern verliert – ein wichtiges Signal in Richtung der Community [9]. Eine gleiche Sicherheit wie bei Enterprise Java gibt es aber dennoch selbstverständlich nicht. Die hohe Dynamik der SPA-Welt ist aber nicht nur kritisch zu betrachten. Während standardgetriebene Frameworks wie Enterprise Java zwar eine langfristige Sicherheit bieten, glänzten sie bislang nicht gerade mit kurzen Innovationszyklen , wobei sich das natürlich mit EE4J ändern könnte. SPA-Frameworks hingegen bieten die Möglichkeit, technologische Trends schnell umzusetzen und so näher an den Erwartungen der Benutzer zu agieren – selbstverständlich zum Preis der Nichtexistenz von klar definierten Standards und langfristiger Garantien.

Komponentenbasierte Benutzungsoberflächen gibt es schon lange. Dass sich dieses Architekturprinzip nun auch wieder bei allen namenhaften SPA-Frameworks manifestiert hat, ist ein klares Signal für die Zukunft: Es ist aller Wahrscheinlichkeit nach davon auszugehen, dass komponentenbasierte Single-Page Applications auch weiterhin eine Rolle spielen werden. Deshalb kann eine saubere Komponentenarchitektur in Verbindung mit einem durchdachten State-Management und regelmäßigen Versionsupdates dabei helfen, eine robuste und hoffentlich zukunftssicher SPA-Architektur gestalten. In diesem Sinne: Stay tuned!

 

Links & Literatur
[1] Stack Overflow: „The Brutal Lifecycle of JavaScript Frameworks“: https://stackoverflow.blog/2018/01/11/brutal-lifecycle-javascript-frameworks/
[2] Stack Overflow Trends Tools: https://insights.stackoverflow.com/trends
[3] Vue.js: https://vuejs.org/v2/guide/comparison.html#Learning-Curve
[4] react-codemod: https://github.com/reactjs/react-codemod

 

The post So entwickeln Sie zukunftssichere Single-Page Applications: Angular, React, Vue.js? appeared first on JAX.

]]>
„Das Typensystem von Java ist eines der pragmatischsten, das ich kenne“ https://jax.de/blog/web-development-javascript/das-typensystem-von-java/ Tue, 21 Mar 2017 16:49:35 +0000 https://jax.de/?p=46883 Java verfügt über eine statische Typisierung – mit allen Vor- und Nachteilen, die mit einem solchen System verbunden sind. Während statische Typen etwa dabei helfen, potenzielle Fehlerquellen auszuschließen, verhindern sie auch die Flexibilität dynamischer Sprachen. Im Gespräch mit JAX-Speaker Rafael Winterhalter gehen wir den Eigenheiten des Java-Typensystems auf den Grund und klären, wie auch in Java dynamische Effekte durch Codegenerierung zur Laufzeit erzielt werden können.

The post „Das Typensystem von Java ist eines der pragmatischsten, das ich kenne“ appeared first on JAX.

]]>
JAXenter: Hallo Rafael! Auf GitHub bezeichnest du dich als “Software Consultant who likes static types”. Das statische Typensystem in Java scheint es dir also angetan zu haben – so sehr, dass du das Projekt Byteboddy gestartet hast, um Java dynamischer zu machen 😉 Was findest du am Java-Typensystem gut – was stört dich daran?

Rafael Winterhalter: Grundsätzlich empfinde ich Javas Typensystem als eines der pragmatisch besten, das ich kenne. Durch die durchgehend statische Typisierung kann man meistens sehr einfach auch durch unbekannte Java-Anwendungen navigieren, was es sehr einfach macht, sich mit einem Programm bekannt zu machen. Das hilft oft beim Onboarding neuer Entwickler, was meiner Meinung nach Java als Enterprise-Sprache erfolgreich macht.

Gleichzeitig ist Javas Typensystem einfach zu lesen, gerade weil Javacode teils ein bisschen weitschweifiger ist als andere Sprachen. Diese Explizität macht Java-Programme nach meiner Erfahrung oft sehr ausdrucksstark.

Kritik kann man vielleicht an der mangelnden Flexibiliät des Typsystems üben. Gerade generische Typen könnten natürlich in einer erweiterten Form umfangreichere Typensicherheit zulassen. Aber diese zusätzlichen Mittel würden mit einem hohen Preis kommen, gerade für beginnende Javaentwickler, denen viel Code nicht mehr zugänglich wäre.

 

Making Java more dynamic

JAXenter: Auf der JAX hältst du eine Session zum Thema „Making Java more dynamic.“ Darin bringst du die Möglichkeit der Code-Generierung zur Laufzeit ins Spiel. Wie genau funktioniert das?

Rafael Winterhalter: Die Java Virtual Machine führt ja eigentlich keine Java-Programme aus, sondern verarbeitet sogenannten Java Bytecode. Dieser ist ein wenig technischer aufgebaut als die Sprache Java, ist in seiner Struktur aber relativ einfach. Byte Buddy generiert dabei zur Laufzeit Java-Programme mittels einer API statt einen Compiler anzubieten. Diese Java-Klassen werden dann ins laufende Programm geladen, um dessen Verhalten zu verändern.

Dies ist manchmal notwendig, um zum Beispiel Proxies zu generieren. Solche lassen sich mit dem Compiler nur schwer erzeugen, unter anderem wegen Javas Typsystem. Weiterhin ist es möglich, existierenden Code mittels sogenannter Java-Agenten umzuschreiben. Das ermöglicht es, Anwendungen zu erweitern, ohne diese neu zu kompilieren. Dieses Verfahren nutzen beispielsweise APM-Tools, um Metriken zur Laufzeit zu sammeln.

 

Ein “Hello World!” mit dem Byte Buddy

Ein Hello-World-Beispiel in Byte Buddy sieht folgendermaßen aus. Jede erzeugte Java-Klasse beginnt mit einer Instanz der ByteBuddy-Klasse, die eine Konfiguration für die Erstellung neuer Typen repräsentiert:

1. Class&lt<?> dynamicType = new ByteBuddy()
2.     .subclass(Object.class)
3.     .method(ElementMatchers.named("toString"))
4.     .intercept(FixedValue.value("Hello World!"))
5.     .make()
6.     .load(getClass().getClassLoader())
7.     .getLoaded();
8.    
9.   assertThat(dynamicType.newInstance().toString(), is("Hello World!"));

Die Default-ByteBuddy-Konfiguration, die im oberen Beispiel genutzt wird, erzeugt eine Java-Klasse in der neuesten Version des Klassen-File-Formats, das von der ausführenden Java Virtual Machine verstanden wird. Wie im Beispielcode ersichtlich, erweitert der erzeugte Type die Object-Klasse und überschreibt ihre toString-Methode, die nun den neuen Wert Hello Word! zurückgeben sollte. Die zu überschreibende Methode wird durch einen sogenannten ElementMatcher identifiziert.

Im Beispiel kommt ein vordefinierter Element-Matcher named(String) zum Einsatz, der Methoden über ihre genauen Namen identifiziert. Byte Buddy bietet zahlreiche vordefinierten und gut getesteten Matcher, die in der ElementMatchers-Klasse gesammelt vorliegen und einfach miteinander kombiniert werden können. Die Erstellung eigener Matcher ist aber ebenso möglich, indem man einfach das (funktionale) ElementMatcher Interface implementiert.

Zur Implementierung der toString-Methode definiert die FixedValue-Klasse einen konstanten Rückgabe-Wert für die überschriebene Methode. Die Definition eines konstanten Wertes ist indes nur ein Beispiel für die verschiedenen Methoden-Interceptors, die Byte Buddy mitbringt. Durch die Implementierung des Implementation Interface kann eine Methode auch durch eigenen Bytecode definiert werden.

Schließlich wird die beschriebene Java-Klasse erzeugt und danach in die Java Virtual Machine geladen. Zu diesem Zweck ist ein Ziel-Class-Loader nötig, der von der umgebenden Klasse abgeleitet wird. Zu guter Letzt können wir uns das Ergebnis anschauen, indem wir die toString-Methode auf einer Instanz der erzeugten Klasse aufrufen und den Rückgabewert suchen, der den konstanten Wert aufweisen sollte, den wir erwarten.

Byte Buddy ist natürlich zu weitaus komplexeren Klassen-Generierungen fähig. Zudem ist Byte Buddy nicht auf die Erzeugung von Unterklassen begrenzt, sondern kann auch existierenden Code transformieren. Über ein API können sogenannte Java Agents definiert werden, die Code-Transformierungen zur Laufzeit einer beliebigen Java-Anwendung ermöglichen.

 

JAXenter: Kannst du einmal ein Beispiel nennen, wie durch Code-Generierung zur Laufzeit besser modularisierte Anwendungen möglich werden?

Rafael Winterhalter: Beispiele bieten sich in jeder Enterprise-Anwendung, die Code-Generierung nutzt. So implementiert etwa Spring seine AOP-Aspekte mit Hilfe von Klassen, die zur Laufzeit generiert werden. Ist eine Methode beispielsweise als transaktional markiert, so erstellt Spring eine Subklasse, die diese Logik in einer überschriebenen Methode bereitstellt. Ohne eine solche Möglichkeit könnte Spring diese Funktion nur anbieten, wenn ein Nutzer explizit eine Methode in Spring aufruft, was diesen Code stärker an Spring bindet.

 

JAXenter: Wie erwähnt hast du mit dem Byte-Buddy-Projekt selbst eine Code-Generierungs-Library am Start. Wie unterscheidet sich Byte Buddy zu anderen Libraries wie ASM, Javassist oder cglib?

Rafael Winterhalter: Viele Bibliotheken zur Code-Generierung erfordern ein gewisses Verständniss von Java Bytecode und lassen viele Fehler zu, wenn die APIs nicht richtig bedient werden. Das gilt besonders für ASM. Byte Buddy hat das Ziel, erfahrenen Java-Programmiereren das Arbeiten mit Bytecode leicht zu machen, indem es sich an die Syntax von Java-Programmen anlehnt. Als Entwickler soll man nicht über Bytecode nachdenken müssen und Byte Buddy nur beschreiben, welchen Code man generieren möchte.

 

JAXenter: Welche Änderungen am Java-Typensystem bzw. der JVM würdest du dir für zukünftige Java-Versionen wünschen?

Rafael Winterhalter: So wenige wie möglich. Javas Typensystem ist bereits sehr ausdrucksstark, und auch weniger erfahrene Entwickler werden schnell produktiv. Ich hoffe, dass diese Anforderung nicht nach oben verschoben wird. Natürlich machen die neuen funktionalen Züge von Java gewisse Änderungen im Typensystem notwendig, aber insgesamt hoffe ich, dass das VM Team seinen konservativen Kurs beibehält.

 

 

The post „Das Typensystem von Java ist eines der pragmatischsten, das ich kenne“ appeared first on JAX.

]]>