Make-loses Java mit der z2-Environment

Die z2-Environment ist eine Java-Laufzeitumgebung, die sich selbsttätig mit Konfigurationen und Quellcode aus einer Versionsverwaltung oder einem Entwickler-Workspace aktualisiert.

In Pocket speichern vorlesen Druckansicht
Lesezeit: 11 Min.
Von
  • Klaus Wriessnegger
Inhaltsverzeichnis

Die z2-Environment ist eine Java-Laufzeitumgebung, die sich selbsttätig mit Konfigurationen und Quellcode aus einer Versionsverwaltung oder einem Entwickler-Workspace aktualisiert. Mit ihr entwickelte Systeme haben einen hohen Grad an innerer Konsistenz, und Entwicklung sowie Pflege werden dank geringer Anforderungen an die Entwicklungsumgebung stark vereinfacht.

Java ist eine kompilierte Programmiersprache, und gewöhnliche Java-Applikationsserver erwarten, dass Java-Programme zur Ausführung kompiliert vorliegen. Anwendungsentwickler müssen daher vor der Ausführung einen Kompilier- und Transformationsschritt durchführen, den sogenannten Make (und/oder Build). Der Make-Vorgang überführt das, was Programmierer in ihrer Entwicklungsumgebung in einer Verzeichnisstruktur bearbeiten, in eine Form, die der Ausführungsumgebung, etwa einem Java-Applikationsserver, genehm ist: das sogenannte Deployable. Nur in einfachen, isolierten Fällen ist es sinnvoll möglich, mit integrierten Applikationsservern zu arbeiten und automatische Aktualisierungen durch die Entwicklungsumgebung auszunutzen.

Einerseits bedeutet der Ansatz mit externem Make-Vorgang einen nicht geringen zeitlichen Aufwand für den Entwickler. Andererseits zieht dieser nach sich, dass neben der eigentlichen Entwicklungsumgebung und dem Betrieb eines Applikationsservers eine geeignet konfigurierte Build-Umgebung, also die Ausführungsumgebung des Make, konsistent für alle Entwickler bereitzustellen ist. In kleinen Projekten mit vielen Abhängigkeiten übersteigen dabei die Komplexität der Build-Ausführung und deren Konfiguration leicht die des eigentlichen Entwicklungsvorhabens.

Wer solche Erfahrungen hinter sich hat, wünscht sich den Komfort von Skripting-Umgebungen auch für die Java-Anwendungsentwicklung. Dort ist man gewohnt, an beliebigen Teilen der Applikation Änderungen vornehmen zu können, die sogleich effektiv sind.

Die z2-Environment implementiert einen Ansatz mit ähnlichen Qualitäten. Sie ist aus der Erfahrung mit der Verwaltung großer Softwaresysteme bei der SAP entstanden. Sie löst zum Test einer Modifikation in der Entwicklungsumgebung lediglich eine Synchronisation der Laufzeitumgebung aus. Die erkennt die Änderungen im lokalen Entwicklungsvorrat des Entwicklers, dem Workspace, und passt ihren Laufzeitzustand geeignet an. Das kann bedeuten, dass eine Webanwendung entladen und anschließend mit neuen Ressourcen wieder gestartet wird oder dass Java-Klassen schnell zu kompilieren und in neuer Version in der Laufzeit zu laden sind.

z2 mit Komponenten-Repository und Entwickler-Workspace (Abb. 1)

Tatsächlich ist nur ein kleiner, vorkompilierter Kern lokal zu installieren. Sämtliche Konfiguration und Implementierung, inklusive Web-Container und Datenbanktreiber, kann der Entwickler nach Bedarf aus dem Komponenten-Repository laden und falls nötig ebenfalls schnell kompilieren.

Dafür braucht es allerdings ein wenig mehr Umgebungswissen und einen grundsätzlich anderen Deployment-Ansatz. Statt zu erwarten, dass die z2-Environment alle von Änderungen betroffenen oder anderweitig benötigten Laufzeitkomponenten in neuer Form zum Deployment anliefert, "zieht" sie sämtliche Änderungen aus der Versionsverwaltung sowie gegebenenfalls aus einem lokalen Workspace und appliziert sie geeignet auf den Laufzeitzustand. z2 implementiert ein Pull-Deployment im Gegensatz zum üblichen Push-Deployment.

Wesentliches Merkmal des Pull-Deployment-Ansatzes ist, dass das Deployment-Ziel, etwa die Laufzeitumgebung, erkennt, welche Änderungen seit einem vorherigen Pull aufgetreten sind und wie darauf zu reagieren ist, um wieder ein konsistentes Abbild der zugrunde liegenden Quellen zu erstellen. Dadurch ergeben sich signifikante Vorteile: Änderungen anderer Entwickler werden erkannt und konsistent angewendet – auf allen beteiligten Installationen der Laufzeitumgebung, sodass sich Änderungen im Team ständig integrieren lassen.

Hingegen können beim Push-Deployment-Ansatz durch die inkonsistente Integration schnell nicht triviale Probleme entstehen, was dazu führen kann, dass Entwickler die zügige Integration mit der Arbeit anderer durch "Eingraben" auf Zwischenstände vermeiden.

Das Problem liegt in den Projektabhängigkeiten: In der Regel bestehen Applikationen und schon gar komplexere Anwendungsszenarien, hier Lösungen genannt, nicht aus unabhängigen Entwicklungsprojekten: Implementierungen und Datentypen werden über die Grenzen von Entwicklungsprojekten und Deployables hinweg wiederverwendet.

Zum Beispiel kann die Änderung einer einzelnen Klasse den erneuten Make und ein erneutes Deployment mehrerer Deployables erfordern, um wieder eine konsistente, dem aktuellen Stand entsprechende Ausführungsumgebung zu erhalten. Da die Verwendungsbeziehung schnell weitverzweigte Graphen bildet, ist das Erkennen aller notwendigen Aktualisierungen nicht einfach, jedoch vom Entwickler zu gewährleisten.

Nicht nur die Produktion, auch die Entwicklung betreibt Anwendungen hochgradig verteilt. Seltenere Vorgänge wie die Installation eines lokalen Applikationsservers mit einem initialen Entwicklungsstand oder zum produktiven Betrieb können daher zu oft unerwartetem Aufwand führen. Das liegt einerseits daran, dass viele Entwickler oft ähnliche, aber doch nicht identische Konfigurationen benötigen, oder daran, dass Softwarestände unterschiedliche Versionsanforderungen an die Ausführungsumgebung haben. Ein Grund mag zudem sein, dass in einem Skalierungsszenario auch kleinere Aktualisierungen manuelle Schritte auf jedem eingebundenen Rechner erfordern.

Da die z2-Environment einen relativ kleinen und selten anzupassenden Kern hat, ist es praktikabel, ihn neben den Entwicklungsprojekten in die Quellverwaltung einzuchecken. Das reduziert die Installation und die Ausskalierung eines gegebenen Lösungssystems auf das Check-out oder Update einer Versionsverwaltung. Zusammen mit dem Pull-Deployment-Ansatz sind Aktualisierungen damit weitgehend unabhängig von der Komplexität der eigentlichen Modifikation und erfordern stattdessen stets nur die Auslösung einer Synchronisation (oder eine Aktualisierung des Kerns).

Verteilung von z2 per Check-out und Update (Abb. 2)

Den mit z2 verfolgten Entwicklungs- und Lifecycle-Management-Ansatz bezeichnet man auch als systemzentrisch. Und tatsächlich: Statt scheinbar unabhängige Module zu entwickeln, die zu Anwendungen verbaut werden, ist in z2 durch die benutzte Codeline (praktisch eine Subversion-URL) immer der komplette Systemzusammenhang hergestellt.

Um Änderungen von System zu System zu propagieren, gleicht z2 Repository-Inhalte, also auch Quellcode, ab – man spricht hier von einem Transport von Modifikationen. Ein rudimentäres Tool stellt der Hersteller dazu bereit. Die Codeline definiert eine Version der gesamten Lösung – ganz nach dem Motto "The Source is the System". Prinzipiell ist alles in der Codeline dem System bekannt und lässt sich – falls nötig – anfragen und ausführen sowie – wichtig – modifizieren und reparieren.

Hierin unterscheidet sich z2 wesentlich von populären Build-Tools wie Apache Maven und darauf aufbauenden Continuous-Integration-Ansätzen. Ein ausführlicher Vergleich geht über die Vorstellung von z2 hinaus, eine Positionierung zu Ant und Maven lässt sich aber auf den Webseiten der z2-Environment nachlesen.

Außer mit dem Make einzelner Projekte beschäftigt sich Maven mit der Versionierung und Freigabe binärer Build-Ergebnisse solcher Projekte sowie der Verwaltung ihrer Abhängigkeiten. Das ist sinnvoll und wichtig, wenn eine Community viele, eher unabhängig verwaltete Projekte wiederverwendet. Werden aber komplette Systeme erstellt und gewartet, sind eine geschlossen versionierte Klammer um alle beteiligten Module und die Möglichkeit, beliebige Teile des Systems unabhängig als Teil des Systems zu modifizieren, unabdingbar. Hier trifft der systemzentrische Ansatz auf das Product Line Engineering.

Damit die z2-Environment versteht, wie sich Änderungen auswirken, muss sie verstehen, welche "Komponenten" es gibt und wo diese definiert sind. Insbesondere muss sie die Quellverwaltung (bisher wird nur Subversion unterstützt, Git ist in Planung) und für den Entwicklungsfall auch den Entwicklungs-Workspace kennen und analysieren können. In diesen Ablagen erwartet z2 eine Struktur, die die Komponenten des Systems definiert.

Struktur der Komponentenablage (Abb. 3)

Bei den z2-Komponenten handelt es sich um konzeptionelle Elemente, die einen eigenständigen Lebenszyklus haben oder die aus Gründen der Wiederverwendung alleinstehend sind. Beispiele dafür sind, von grob nach klein, Worker-Prozesse, Java-Module, Webanwendungen oder Datenbank-Verbindungskonfigurationen, aber auch Applikationskomponenten wie eine Spring Bean, die einem anderen Modul zur Verfügung gestellt werden soll. Der anfangs beschriebene Synchronisationsmechanismus mit Änderungen von Code oder Konfiguration ist mit der Verwaltung des Komponentenlebenszyklus implementiert.

Das z2-Komponentenmodell ist erweiterbar, und es ist möglich, neue Komponententypen zu definieren. Zur Laufzeit bildet es angefragte Komponenten in sogenannte Ressourcen ab, die die Semantik der Komponente implementieren, also zum Beispiel dem Web-Container eine Webanwendung sowie die impliziten oder expliziten Abhängigkeiten zu anderen Ressourcen dem Laufzeitsystem vorzustellen. Eine Webanwendung ist zum Beispiel abhängig von ihrem Java-Modul, das den Implementierungscode enthält. Als Konsequenz zieht eine Invalidierung des Java-Moduls auch eine Invalidierung, das heißt einen Stopp der Webanwendung nach sich.

Das Komponentenmodell ist auch die Grundlage für die Modularisierung von Applikationen: Mehrfach zu verwendender Java-Code wird in Java-Modulen abgelegt, die ein oder mehrere andere Java-Module referenzieren. Applikationskomponenten lassen sich exponieren und wiederverwenden: Mit der Erweiterung zur Nutzung des Spring Framework können Entwickler zum Beispiel Spring Beans aus dem Spring Application Context eines Moduls in einem Application Context eines anderen Moduls einbinden.

Infrastrukturkomponenten wie der integrierte Jetty-Web-Container sind als Komponenten integriert. Damit fungiert die z2-Environment als Plattform für Infrastrukturkomponenten, die zusammen einen Applikationsserver bilden. Leider scheint es aber daher nicht einfach zu sein, die beschriebenen Qualitäten bei einer losen Integration mit bekannten Applikationsservern wie JBoss oder mit kommerziellen Alternativen zu erhalten.

In Anwendungen mit vielen Projekten ist es wünschenswert, dass der Entwickler nur die Projekte in seinem Entwicklungs-Workspace vorhalten muss, an denen er gerade arbeitet. z2 ermöglicht das, indem sie den Workspace als ein weiteres Komponenten-Repository mit höherer Priorität betrachtet. Praktisch bedeutet das, dass Entwickler wirklich nur die zu modifizierenden Projekte auschecken müssen und dass die lokale z2-Runtime Modifikationen an diesen aufnimmt, ohne die Arbeit anderer Entwickler zu beeinträchtigen. Stellt ein Programmierer die erwünschten Modifikationen schließlich in die Versionsverwaltung zurück, werden sie für alle Entwickler sichtbar und effektiv.

Allerdings gibt es hierbei einen Haken: Entwicklungsumgebungen wie Eclipse leben davon, dass Projekte im Workspace kompilierbar sind. Einzeln ausgecheckte Projekte haben aber in der Regel eine Vielzahl von Abhängigkeiten an weitere Schnittstellen- und Implementierungstypen und sind ohne ihre Sichtbarkeit auf dem Java-Classpath nicht kompilierbar. Hierfür kommt ein kleines, aber wichtiges Tool zum Einsatz: das Eclipse-Plug-in Eclipsoid.

Dieses Plug-in ist Teil der z2-Distribution und lässt sich via localhost vom laufenden System installieren. Es löst das Classpath-Problem und nutzt dabei aus, dass die laufende z2-Umgebung schließlich alle Projektabhängigkeiten kennt und alle Kompilate bereitstellen muss. Dazu lädt Eclipsoid sämtliche benötigten Abhängigkeiten vom laufenden System und stellt sie den Workspace-Projekten zur Verfügung. Damit ist es möglich, ohne zusätzliche Infrastruktur und ohne Verzicht auf Kompilationschecks in der Entwicklungsumgebung auf beliebigen Teilmengen einer Anwendung zu arbeiten und lokal zu testen.

Mit der z2-Environment steht ein innovativer Ansatz zur Entwicklung und zum Betrieb von Java-Entwicklungen bereit. Statt sich auf Optimierung und Komplexitätsbewältigung in der Softwareproduktion per Make, Build und Continuous Integration zu fokussieren, wird das komplette Make-Problem entfernt. Durch den systemzentrischen Ansatz erleichtert z2 die Entwicklung, Wartung und Verteilung komplexer, modularisierter Lösungen.

Der Ansatz kann direkt auf der Website ausprobiert werden. Es stehen grundlegende Distributionen und eine erweiterte zur Entwicklung mit dem Spring Framework als Open Source zur Verfügung. Die ZFabrik Software KG bietet Beratung und Support für z2 an.

Klaus Wriessnegger
war bei der SAP AG an der Entwicklung der hauseigenen Programmiersprache ABAP beteiligt. Er leitete dort auch Java-Projekte, wobei er die Vorteile des eher skriptartigen ABAP-Systems vermisste. In seiner jetzigen Rolle als Entwicklungsleiter bei der Original1 GmbH fand er mit der z2-Environment eine Antwort auf dieses Problem bei der Java-Entwicklung.
(ane)