Als der Kunde uns sagte, er wolle sein JSF-Frontend durch eine „moderne Single-Page-Anwendung” ersetzen, hatten wir gemischte Gefühle. JavaScript im Enterprise-Umfeld? Aber nach einem Jahr mit AngularJS 1.3 muss ich zugeben: Google hat ein Framework gebaut, das Enterprise-Java-Entwickler wirklich annehmen können.
Warum AngularJS (und nicht Backbone oder Ember)¶
2014 stehen drei ernsthafte Kandidaten für Enterprise-SPAs zur Auswahl: Backbone.js, Ember.js und AngularJS. Backbone ist minimalistisch — es gibt einem Freiheit, aber auch die Verantwortung für jede architektonische Entscheidung. Ember ist opinionated und ausgezeichnet, aber die Community in Tschechien ist klein. AngularJS gewann durch eine Kombination von Faktoren: starke Unterstützung durch Google, Two-Way Data Binding, Dependency Injection (Java-Entwickler kennen es aus Spring) und eine riesige Community.
Das Schlüsselargument für unser Team: AngularJS ähnelt konzeptionell dem, was Java-Entwickler bereits kennen. Module, Services, Dependency Injection, Testen mit Jasmine — all das hat Parallelen in der Java-Welt. Die Lernkurve war überraschend sanft.
Anwendungsarchitektur¶
Wir bauten ein internes CRM-System für ein mittelständisches Unternehmen — etwa 200 Benutzer, Dutzende Bildschirme, komplexe Formulare, Echtzeit-Benachrichtigungen. Architektur:
Frontend: AngularJS 1.3 + UI-Router + Bootstrap 3
Backend: Java EE 7, JAX-RS (Jersey), JPA (Hibernate)
API: RESTful JSON, JWT authentication
Build: Grunt + Bower (frontend), Maven (backend)
Tests: Karma + Jasmine (unit), Protractor (E2E)
Wir entschieden uns für eine strikte Trennung von Frontend und Backend. Das Frontend ist eine statische Anwendung, die von Nginx ausgeliefert wird, das Backend ist eine reine REST-API auf WildFly. Kein JSP, kein Server-Side Rendering. Ein sauberer Vertrag über JSON-API.
Was uns AngularJS gelehrt hat¶
Two-Way Data Binding ist großartig — bis es das nicht mehr ist. Für Formulare mit zehn Feldern ist es Magie. Für eine Tabelle mit tausend Zeilen ist es eine Katastrophe. Jeder $digest-Zyklus durchläuft alle Watcher. Bei mehr als 2000 Watchern auf einer Seite beginnt die Anwendung zu ruckeln. Lösungen: Virtual Scrolling, One-Time Binding ({{ ::value }}) und track by in ng-repeat.
Direktiven sind die Stärke des Frameworks. Wir bauten eine Bibliothek wiederverwendbarer Direktiven — Datepicker, Autocomplete, Datentabelle mit Filterung und Sortierung, Formularvalidatoren. Nach drei Monaten Arbeit hatten wir ein Komponentensystem, aus dem neue Bildschirme wie Bausteine zusammengesetzt werden können.
Services und Dependency Injection. Angular Services sind genau das, was ein Java-Entwickler erwartet. Singleton-Instanzen, injiziert über den Konstruktor (bzw. Funktionsparameter). AuthService, ApiService, NotificationService — die Code-Struktur ist auch für einen Kollegen lesbar, der nicht am Projekt beteiligt war.
Integration mit dem Java-Backend¶
REST-API nach pragmatischen Prinzipien gestaltet — kein striktes HATEOAS, aber auch kein Chaos. Konventionen: Substantive in URLs, HTTP-Methoden für Operationen, Paginierung über Query-Parameter, Fehlerantworten in einem Standardformat.
// Angular service for working with contacts
angular.module('crm').factory('ContactService', function($http) {
var api = '/api/v1/contacts';
return {
list: function(params) { return $http.get(api, {params: params}); },
get: function(id) { return $http.get(api + '/' + id); },
create: function(data) { return $http.post(api, data); },
update: function(id, d) { return $http.put(api + '/' + id, d); },
remove: function(id) { return $http.delete(api + '/' + id); }
};
});
JWT-Token für die Authentifizierung — ein Angular Interceptor fügt jedem Request den Authorization-Header hinzu. Ein Refresh-Token-Mechanismus behandelt den Ablauf. CORS korrekt auf dem Backend konfiguriert. Keine Session-Cookies, kein serverseitiger Zustand. Eine zustandslose Architektur, die wunderbar skaliert.
Testing — Überraschend gut¶
Karma Runner + Jasmine für Unit-Tests. Angular ist mit Testbarkeit als Priorität entworfen — $httpBackend zum Mocken der API, $provide zum Ersetzen von Abhängigkeiten. Wir haben 78 % Abdeckung — mehr als unser Java-Backend.
Protractor für End-to-End-Tests. Selenium unter der Haube, aber mit einer Angular-aware API. Es wartet automatisch auf den Abschluss des $digest-Zyklus und ausstehende $http-Requests. E2E-Tests laufen im CI auf Jenkins — Headless Firefox über Xvfb.
Schwachstellen und Lessons Learned¶
- IE-8-Unterstützung — der Kunde verlangte sie. AngularJS 1.3 hat sie offiziell abgeschafft. Kompromiss: IE 9+ mit Polyfills. Es dauerte Wochen, die Stakeholder zu überzeugen.
- SEO — für eine interne Anwendung nicht relevant, aber für zukünftige öffentliche Projekte ist SPA ein Problem. Prerender.io oder Server-Side Rendering müssen wir noch angehen.
- Build-Tooling — Grunt + Bower funktioniert, aber das Ökosystem bewegt sich schnell. Gulp übernimmt, Browserify und Webpack stehen vor der Tür. Investitionen in die Build-Pipeline sind notwendig.
- Angular 2.0 — Google hat Angular 2.0 angekündigt, das nicht abwärtskompatibel sein wird. Das ist für ein Enterprise-Projekt besorgniserregend. Wir beobachten die Situation.
AngularJS funktioniert im Enterprise-Umfeld¶
Nach einem Jahr im Produktivbetrieb haben wir eine stabile, wartbare und gut getestete Anwendung. AngularJS gab dem Java-Team die Struktur und Konventionen, die es kennt. Es ist nicht ohne Probleme — Performance mit großen Datensätzen erfordert Sorgfalt, und die Zukunft des Frameworks ist ungewiss. Aber für 2014 ist es die beste Wahl für Enterprise-SPAs, die wir haben.
Brauchen Sie Hilfe bei der Implementierung?
Unsere Experten helfen Ihnen bei Design, Implementierung und Betrieb. Von der Architektur bis zur Produktion.
Kontaktieren Sie uns