2013 schrieb ich Full-Stack-Java bei BluLogix, kompilierte zu JavaScript mit dem Google Web Toolkit, verdrahtete Spring Security für Auth und shippte eine Cloud-Billing-Plattform für Telecom-Anbieter. TypeScript würde weitere zwölf Monate brauchen, bis es 1.0 erreichte. React war ein Facebook-internes Ding. Node.js war das, über das Leute Blog-Posts schrieben, nicht das, worauf sie Billing-Systeme shippten.
Ich machte, ohne es zu wissen, typsicheres Full-Stack-Development ein Jahrzehnt bevor es zum Standard wurde.
Was GWT wirklich war
Google Web Toolkit (GWT) war eine kühne Idee: schreib dein Frontend in Java, lass den GWT-Compiler laufen, und bekomme optimiertes JavaScript auf der anderen Seite raus. Kein dünner Wrapper. Kein JSX-Analogon. Java — Klassen, Generics, Interfaces, das vollständige Typsystem — durch Cross-Compilation zu JavaScript kompiliert, das im Browser lief.
Das funktionierte, weil Google es zum Funktionieren brauchte. Gmail war auf GWT gebaut. Google Docs war auf GWT gebaut. Google steckte ernsthaftes Engineering in den Compiler — Dead-Code-Elimination, Code-Splitting, Permutation-basierte Optimierung über Browser-Targets — und produzierte überraschend effizienten Output. Das resultierende JavaScript war minimiert und pro Browser permutiert, sodass IE ein Artefakt bekam, Firefox ein anderes, Chrome ein weiteres. Man musste sich darum nicht kümmern. Der Compiler erledigte es.
Der Value Proposition für ein Team wie meins war sofort klar: dasselbe Typsystem,
das dein Backend schützte, schützte auch dein Frontend. Wenn das API ein
BillingCycle-Objekt zurückgab, erhielt der UI-Code ein BillingCycle-Objekt,
mit allen getypten Feldern, und der Compiler fing jeden Mismatch zur Build-Zeit
ab. Keine JSON-Shape-Mismatches. Kein “ich dachte, das Feld sei ein String.” Keine
Runtime-Überraschungen, weil jemand eine Property im Backend-DTO umbenannte und
vergaß, den Frontend-Fetch-Call zu updaten.
2013 war das wirklich ungewöhnlich. Alle anderen schrieben jQuery-Callbacks und beteten.
Der Preis, den du für statische Typen zahltest
GWT war nicht kostenlos. Der Compiler war langsam. Nicht “ein paar Extra-Sekunden” langsam — Compile-Zyklen bei einer mittelgroßen GWT-App liefen zwei bis fünf Minuten. Der inkrementelle Dev-Modus (wo man die App in einem gehosteten Browser laufen ließ und Java-Bytecode hot-swappte) half, war aber fragil: Dev-Modus und Produktionskompilierung divergierten manchmal auf subtile Weisen, und man shippte etwas, das in Dev perfekt funktionierte und in einer Permutation kaputt war, die der Dev-Browser nie ausgeführt hatte.
Das Widget-Modell waren Java-style Objekthierarchien: GwtWidgets, die von
abstrakten Basisklassen erbten, Event-Handler-Interfaces, UiBinder-XML-
Templates, die auf Java-Klassen gemappt wurden. Das war 2013 Java-Enterprise-
Kultur auf die UI angewendet. Es fühlte sich natürlich an, wenn man von Swing
oder JSF kam. Es fühlte sich fremd an, wenn man von irgendwas anderem kam.
CSS war ein echter Kampf. GWTs CssResource-System gab einem typsichere
CSS-Klassennamen — Java-Code würde myStyle.myClassName() statt eines rohen
Strings referenzieren, sodass das Umbenennen einer CSS-Klasse einen Compiler-
Fehler produzierte statt eines stillen Bruchs. Das ist eigentlich großartig in
der Theorie. In der Praxis war das Tooling rund drum rau genug, dass ich sinnvolle
Stunden damit verbrachte, zu debuggen, warum ein Style nicht angewendet wurde,
nur um festzustellen, dass ich den falschen CssResource-Typ referenziert hatte.
Spring Boot tauchte auf und fühlte sich wie ein Geschenk an
Ich fing um 2012 an, Spring Framework zu verwenden — Spring MVC für REST-Endpunkte,
Spring Security für Auth, Spring WS für SOAP-Services (ja, SOAP, das war
Enterprise-Java für Telecom). Das war die Ära des XML-konfigurierten Spring:
applicationContext.xml-Dateien mit 500 Zeilen Bean-Definitionen, Namespace-
Deklarationen und Property-Platzhaltern. Man hatte eine intime Beziehung zum
Application-Context. Man kannte jeden Bean beim Namen.
Spring Boot 1.0 erschien im April 2014. Ich war da schon bei AFAQ, und wir adoptierten es früh — früh genug, dass es noch keine 400 Stack-Overflow-Antworten für jedes Konfigurationsproblem gab, das man traf.
Der Shift, den Boot machte, war nicht das Hinzufügen von Features. Es war das
Eliminieren von Zeremonie. Auto-Configuration bedeutete, dass das Framework
vernünftige Defaults aus dem Classpath erriet und verdrahtete, was man wirklich
brauchte. @SpringBootApplication ersetzte das XML-Labyrinth. Embedded Tomcat
bedeutete, man lief java -jar statt einen Container-Deployment zu verwalten.
application.properties ersetzte ein Drittel des XML.
Das erste Mal, als ich eine Spring-Boot-App von Grund auf laufen ließ und in unter 10 Minuten einen funktionierenden REST-Endpunkt hatte — ohne die Zeit zu rechnen, die ich mit Docs-Lesen verbracht hatte — verstand ich, dass sich etwas verändert hatte. Nicht technisch revolutionär. Philosophisch anders.
Das AFAQ-EHR auf GWT + Spring Boot bauen
Bei AFAQ (2014–2017) baute ich eine EHR/EMR-Suite — webbasiert, vollständig integriert mit ERP-Modulen, deployed auf Komponenten von VA VistA. Der Tech-Stack: GWT auf dem Frontend, Spring Boot + Java EE auf dem Backend, mit den VistA-MUMPS- Komponenten hinter einer Service-Schicht (dazu gibt es einen eigenen Post).
Die spezifische Kombination von GWT und Spring Boot war für Healthcare eigentlich
recht gut. Der Grund: Healthcare-UIs sind komplex, stateful und hochriskant.
Eine Patientenakte-Ansicht hat verschachtelte Tabbed Panels, Echtzeit-Labor-
ergebnisfeeds, Medikamentenlisten, die sich während der Sitzung aktualisieren,
Encounter-Notizen mit Rich Text und Alert-Badges, die feuern müssen, wenn sich
etwas ändert. GWTs Java-UI-Modell handhabte das besser als jQuery-Spaghetti.
Die Typsicherheit zählte, wenn die Daten AllergyRecord- und MedicationOrder-
Objekte statt beliebigem JSON waren.
Spring Boots opinionated Defaults halfen bei AFAQ auch, weil das Team nicht groß war und wir schnell vorankommen mussten. Convention over Configuration ließ uns die Business-Logik schreiben statt über Bean-Lifecycles zu debattieren.
Der Schmerzpunkt war der Build. Eine vollständige GWT-Kompilierung auf dem Frontend plus Spring Boots Maven-Build auf dem Backend, auf Hardware von 2014, war ein 15-Minuten-Prozess von einem sauberen Checkout bis zu einem deployable Artefakt. Wir mussten diszipliniert sein, den Build nicht zu brechen, weil die Feedback-Loop von “ich habe etwas Falsches gemergt” zu “ich weiß, dass es kaputt ist” mindestens eine Viertelstunde war.
Warum GWT weg ist und was es ersetzte
GWT peakte um 2012–2013 und dann verbesserte sich JavaScript schnell. TypeScript kam und gab der JavaScript-Welt die statische Typisierung, die GWT immer verkauft hatte. React gab ihr das Component-Modell. Webpack gab ihr das Code-Splitting. Das Build-Tooling verbesserte sich dramatisch. Und entscheidend: Jeder Web-Engineer kannte bereits JavaScript. Der Pool der Leute, die GWT-Java-Frontend- Code schreiben konnten, war die Schnittmenge von “Java-Engineers” und “Leute, die bereit sind, Frontend zu schreiben” — ein berühmt kleines Venn-Diagramm.
Google reduzierte schrittweise seine Investitionen in GWT. Die Community übernahm es. Neue Entwicklung in GWT ist jetzt Nischen-in-Nischen: Es gibt medizinische Abrechnungssysteme, die es noch laufen, Enterprise-Java-Shops, die nie migriert haben, und eine Handvoll Open-Source-Projekte, die es verwenden.
Spring Boot hingegen ging in die andere Richtung. Es fraß die Java-Backend-Welt. Wenn du heute einen neuen Java-Service schreibst, benutzt du mit an Sicherheit grenzender Wahrscheinlichkeit Spring Boot. Es wurde zum Standard in einer Art, wie es wenige Frameworks schaffen.
Die Ironie ist, dass der Teil des Stacks, der weniger neuartig war (Java-Backends gibt es seit 1997), sich als der dauerhafte herausstellte. Der Teil, der seiner Zeit wirklich voraus war — typsicheres kompiliertes Frontend-Java — verlor gegen das Ökosystem, gegen das es antrat, sobald dieses Ökosystem reifte.
Was ich jemandem sagen würde, der gegen die GWT-Nostalgie-Wand läuft
Wenn du in GWT gearbeitet hast und dich wehmütig fühlst: Was du wirklich vermisst, ist das Gefühl eines konsistenten Typsystems über den gesamten Stack. Dieses Gefühl ist jetzt in TypeScript + tRPC verfügbar, oder in einem vollständigen Java-Backend mit einem generierten TypeScript-Client, oder in Kotlin + Compose Multiplatform, wenn du dich mutig fühlst. Das Tooling ist dramatisch besser.
Aber du liegst nicht falsch, dass GWT ein reales Problem als erstes gelöst hat. Es löste es mit viel Java, einem sehr langsamen Compiler und einem Widget-Modell, das wie Swing aussah. 2013 war das der richtige Trade. 2024 hast du bessere Optionen — und die meisten dieser besseren Optionen existieren, weil GWT zuerst da war, den Wert demonstrierte und die experimentelle Steuer zahlte, damit alle anderen etwas Saubereres bauen konnten.
Ich denke gelegentlich noch an die GWT-UiBinder-XML-Templates. Nicht mit
Wärme. Aber mit einer spezifischen Art von Respekt, der für Dinge reserviert ist,
die wirklich schwer waren und die ich trotzdem in Produktion geshippt habe.
Spring Boot denke ich jeden Tag daran. Es ist gerade in meinem Stack.