Apache Buildr

Apache Buildr – Die Maven-Alternative?

Tammo van Lessen

Die Automatisierung der Build-Prozesse ist eine feine und wichtige Sache. In der Regel freut man sich, wenn ein Projekt Apache Maven verwendet und man dank der Konvention das Projekt sofort bauen kann. Doch mit der Zeit stellt sich in der Regel Ernüchterung ein: Der Build schlägt plötzlich fehl, weil ein Artefakt nicht mehr in den bekannten Repositories gefunden werden kann, die Ergebnisse sind nicht exakt reproduzierbar oder für eine kleine Erweiterung des Prozesses müssen erst aufwändig Plug-ins entwickelt und verteilt werden. Muss das so sein? Apache Buildr hat sich zu einer mächtigen Alternative entwickelt, indem es den deklarativen Ansatz von Maven mit dem imperativen einer Skriptsprache kombiniert.

Die Ursprünge von Buildr [1] liegen in der BPEL-Engine Apache ODE [2]. ODE ist ein komplexes Middleware-Projekt, das sehr hohe Anforderungen an das Build-System stellt. So besteht es aus über fünfunddreißig Modulen, unterstützt neun Datenbanken, wird in drei verschiedenen Editionen paketiert und hängt von über hundertzwanzig Bibliotheken ab. Die Datenbankanbindung erfolgt wahlweise über OpenJPA oder Hibernate – beide müssen im Build-Prozess berücksichtigt werden. Die Datenbankskripte sollen nicht nur für eine Datenbank, sondern gleichzeitig für alle neun erzeugt werden. Zusätzlich werden XML-Parser und -Serializer mittels XMLBeans generiert und eigene Annotations-Prozessoren für die Codegenerierung verwendet. Dazu kommen weitere „Kleinigkeiten“, wie die Anforderung, dass alle ausgelieferten Textdateien, auch die generierten, die Apache-Lizenz im Kopf führen müssen.

„Maven Uncertainty Principle“

Nach den guten Erfahrungen, die das ODE-Projektteam mit Maven 1 gemacht hatte, war man optimistisch, auch diese Anforderungen mit Maven – diesmal in Version 2 – umsetzen zu können. Das war auch tatsächlich möglich, allerdings mit deutlich höherem Aufwand als erwartet. Für eine so einfache Aufgabe wie das Zusammenführen von zwei SQL-Dateien benötigt man beispielsweise 34 Zeilen XML. Die SQL-Skripte für alle Datenbanken zu erzeugen, war mit Maven und Plug-ins gar nicht möglich, sodass man an dieser Stelle auf Ant-Skripte ausweichen musste. Im Ergebnis war die Build-Logik von Apache ODE um insgesamt 6 739 Zeilen XML-Code gewachsen, verteilt auf 53 Dateien. Die Verteilung auf mehrere voneinander abhängige pom.xml-Dateien muss man in Kauf nehmen, wenn man sein Projekt auf mehrere Module verteilen möchte. Man kann sich vorstellen, dass das auf Kosten der Wartbarkeit geht. Zudem sind die Konfigurationsoptionen verschiedener Plug-ins nicht immer selbsterklärend und ändern sich mitunter zwischen Plug-in-Versionen. In der Praxis führt dies zu schwer aufzuspürenden Problemen und zu nicht reproduzierbaren Builds. Scherzhaft sprach man sogar vom „Maven Uncertainty Principle“, in Anlehnung an Heisenbergs Unschärferelation.

Notausgänge

Dass dies besser gehen muss, steht außer Frage – aber wo genau liegt eigentlich das Problem? Maven verfolgt einen rein deklarativen Ansatz mithilfe einer XML-basierten DSL. Diese DSL ist allerdings ausschließlich in der Lage, das „Was“ zu beschreiben, nicht jedoch das „Wie“. Für die tatsächliche Implementierung der gewünschten Funktionalität sind die Plug-ins verantwortlich. Sie allein bestimmen also das „Wie“. Die einzige Möglichkeit, Einfluss darauf zu nehmen, ist die Konfiguration der Plug-ins (im Rahmen der angebotenen Funktionalität) oder ein Notausgang. Ein solcher könnten z. B. ein selbst geschriebenes Maven-Plug-in, der Aufruf eines Ant-Scripts oder, wie in Maven 1, ein Jelly-Script sein. Die Lösung kann also nur die bessere Verbindung der deklarativen und imperativen Ansätze sein, die eine nahtlose Integration von Notausgängen erlaubt [3].

Buildr hat sich genau das zum Ziel gesetzt und setzt dabei auf bewährte Mittel. So sollen die guten Eigenschaften von Maven, wie z. B. die Abhängigkeitsverwaltung, beibehalten werden. Als Basis für die DSL wird aber auf XML verzichtet und stattdessen Ruby eingesetzt. Dadurch hat man jederzeit die Möglichkeit, die Mächtigkeit der Scriptsprache als Notausgang zu verwenden, wenn die deklarativen Elemente nicht mehr ausreichen. Der Buildr-basierte Build von Apache ODE besteht nun nur noch aus 912 Zeilen Ruby-Code, der Übersichtlichkeit halber auf drei Dateien verteilt. Ein wichtiger Nebeneffekt: Der Buildprozess ist sogar doppelt so schnell.

Abb. 1: Auf der Basis von Ruby setzt Buildr auf Rake auf

Auf der Basis von Ruby setzt Buildr auf Rake auf (Abb. 1). Rake ist ein populäres Build-Werkzeug in der Ruby-Welt. Es operiert auf einem gerichteten azyklischen Graphen, um Abhängigkeiten zwischen Tasks zu definieren. Dafür stellt es eine einfache DSL zur Verfügung. Die Tasks selbst werden in Ruby implementiert und können dementsprechend komplexe Aufgaben bearbeiten. Zusätzlich können so genannte FileTasks kausale Abhängigkeiten zwischen Dateien definieren. Wird eine solche Abhängigkeit zwischen einer .java- und .class-Datei definiert, so weiß Rake, dass es die .class-Datei nur dann neu erzeugen muss, wenn die .java-Datei ein neueres Änderungsdatum als die .class-Datei hat.

Dennoch wurde Rake für die Build-Prozesse von Ruby-Projekten entwickelt. Um effizient Java-Projekte bauen zu können, liefert Buildr die nötigen Erweiterungen der DSL, um die wichtigsten Elemente eines Builds, nämlich Kompilieren, Testen, Paketieren und Releasen, deklarativ in der Skriptsprache verwenden zu können.

Geschrieben von
Tammo van Lessen
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.