Gradle 1.0 nach den ersten Wochen: Abschied von Maven?

Keine Zeit? Hier die Kurzversion in 30 Sekunden.
- Gradle 1.0 ist am 12. Juni 2012 erschienen; ich habe es seitdem an kleinen Java-Projekten ausprobiert.
- Eine
build.gradleist deutlich kürzer als die entsprechendepom.xml, nutzt dasselbe Verzeichnislayout und holt Abhängigkeiten aus Maven Central.- Eigene Tasks sind einfacher Groovy-Code statt Plugin, und der Wrapper (
gradlew) macht Builds reproduzierbar.- Nachteile aktuell: Startzeit, IDE-Unterstützung noch nicht so rund, weniger Doku und Erfahrungsberichte.
- Meine Einschätzung: Neue Projekte gern mit Gradle, bestehende Maven-Projekte nicht zwingend umziehen.
Am 12. Juni ist Gradle 1.0 erschienen. Das Werkzeug gibt es schon länger, aber die 1.0 ist für viele das Signal, dass man es ernsthaft ansehen darf, ohne dass sich alle zwei Wochen die Syntax ändert. Ich habe seitdem ein paar kleine Java-Projekte probeweise von Maven darauf umgestellt und neue Projekte damit angelegt. Nach den ersten Wochen sind meine Eindrücke gemischt, aber überwiegend positiv.
Weniger Text, gleiche Konvention
Der auffälligste Unterschied ist die Größe. Eine minimale pom.xml für ein Java-Projekt mit zwei Abhängigkeiten sieht ungefähr so aus:
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>de.beispiel</groupId>
<artifactId>demo</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>Dieselbe Beschreibung in Gradle:
apply plugin: 'java'
group = 'de.beispiel'
version = '1.0-SNAPSHOT'
sourceCompatibility = 1.6
repositories {
mavenCentral()
}
dependencies {
compile 'org.apache.commons:commons-lang3:3.1'
testCompile 'junit:junit:4.10'
}Die Datei ist Groovy-Code, kein XML, und compile sowie testCompile entsprechen den Maven-Scopes compile und test. Das Plugin java erwartet dasselbe Verzeichnislayout wie Maven (src/main/java, src/test/java, src/main/resources), man kann also ein bestehendes Projekt ohne Verschieben von Dateien umstellen. Ergebnisse landen allerdings in build/ statt in target/. Mit gradle build wird kompiliert, getestet und das Jar gebaut, gradle test führt nur die Tests aus. Gradle holt Abhängigkeiten aus denselben Repositories wie Maven, der Umstieg bedeutet also keine neue Infrastruktur.
Eigene Tasks statt Plugin-Suche
Dort, wo Maven eine starre Abfolge von Phasen hat, ist Gradle ein Graph aus Tasks, und eigene Tasks sind in wenigen Zeilen geschrieben:
task zeigeVersion << {
println "Projekt ${project.name}, Version ${version}"
}
task kopiereDoku(type: Copy) {
from 'doku'
into "$buildDir/doku"
}Aufgerufen wird das mit gradle zeigeVersion. Bei Maven hätte ich für das Kopieren ein Plugin gesucht, konfiguriert und die richtige Phase eingetragen. In Gradle ist es normaler Code, den man auch bedingt oder in Schleifen verwenden kann. Das ist angenehm, aber es hat eine Kehrseite: Ein Build, der aus viel Groovy-Logik besteht, wird schnell so unübersichtlich wie ein Shellskript. Die Freiheit verlangt Disziplin, wo Maven einen Rahmen vorgibt.
Der Wrapper
Gut gefällt mir der Wrapper. Man definiert einen Task, der ihn erzeugt:
task wrapper(type: Wrapper) {
gradleVersion = '1.0'
}Nach gradle wrapper liegen im Projekt die Skripte gradlew und gradlew.bat sowie ein kleines Verzeichnis gradle/wrapper. Wer das Projekt auscheckt, ruft ./gradlew build auf, und Gradle in der passenden Version wird beim ersten Mal heruntergeladen. Damit muss auf einem Build-Server oder auf einem frisch eingerichteten Rechner nichts vorinstalliert sein, und alle bauen mit derselben Version. Maven hat dafür keine direkte Entsprechung, dort verlässt man sich meist darauf, dass die richtige Version installiert ist.
Abhängigkeiten und Konfigurationen
Ein weiterer Punkt, der mir bei der Arbeit aufgefallen ist: Gradle kennt neben compile und testCompile auch runtime und testRuntime, und man kann eigene Konfigurationen anlegen. Für typische Anwendungen reicht das Standardset völlig aus, aber bei Projekten mit mehreren Modulen (Multi-Project-Builds) merkt man, wie flexibel das System ist. Eine Datei settings.gradle listet die Teilprojekte auf, und in der Haupt-build.gradle lassen sich gemeinsame Einstellungen für alle Module an einer Stelle festlegen, ohne dass man ein Eltern-POM pflegen muss. Auch transitive Abhängigkeiten werden aufgelöst wie bei Maven, und wenn eine Bibliothek unerwünschte Pakete mitbringt, kann man sie direkt an der Abhängigkeit ausschließen. Wer schon einmal ein exclusions-Konstrukt in XML geschrieben hat, wird die kürzere Variante zu schätzen wissen.
Trotzdem bin ich bei einer Sache vorsichtig: Die Auflösung von Versionskonflikten funktioniert nach eigenen Regeln, bei Konflikten gewinnt standardmäßig die neueste Version. Das weicht vom Verhalten von Maven ab (dort zählt die Nähe in der Abhängigkeitskette) und kann bei einer Umstellung zu anderen Jars im Klassenpfad führen. Nach einem Umzug sollte man deshalb die tatsächlich verwendeten Bibliotheken vergleichen, bevor man etwas ausliefert.
Die Nachteile
Im Alltag fällt zuerst die Startzeit auf. Jeder Aufruf startet eine JVM, lädt Groovy und wertet das Skript aus, das dauert spürbar und bei kleinen Projekten mehr, als man erwartet. Maven ist da nicht schneller, aber bei Gradle erwartet man es eher anders. Die IDE-Unterstützung ist ebenfalls noch nicht so rund wie bei Maven. Über die Plugins eclipse und idea lassen sich Projektdateien erzeugen (gradle eclipse), und es gibt Plugins für die Entwicklungsumgebungen, aber ich hatte öfter das Gefühl, dass Änderungen an der build.gradle nicht sauber ankommen, und Maven-Projekte importieren die IDEs deutlich zuverlässiger.
Dazu kommt, dass es weniger Dokumentation und Erfahrungsberichte gibt. Bei einem Maven-Problem liefert eine Suche meist sofort eine Antwort. Bei Gradle muss man häufiger in die Doku des Projekts oder in den Quellcode schauen, und für exotischere Plugin-Konstellationen gibt es oft noch kein fertiges Beispiel. Das wird sich vermutlich ändern, jetzt ist es aber so.
Meine Meinung
Für neue Projekte nehme ich inzwischen gern Gradle: kürzere Buildskripte, einfachere Sonderfälle und der Wrapper wiegen die Nachteile auf, besonders wenn man ohnehin Groovy-Syntax nicht scheut. Bestehende Maven-Projekte würde ich dagegen nicht allein wegen der Technik umziehen. Der Build läuft, das Team kennt ihn, und die IDE-Anbindung funktioniert. Ein Umstieg bringt dann vor allem Aufwand. Anders sieht es aus, wenn der Maven-Build bereits mit vielen Workarounds und eigenen Plugins arbeitet. Dort kann Gradle echte Vereinfachung bringen, und die Konvention ist ja dieselbe, sodass man schrittweise und mit wenig Risiko testen kann.
Ob Gradle Maven ablöst, wird sich zeigen. Im Moment sehe ich es als ernsthafte Alternative, nicht als Pflicht.
Beitragsbild: eigene Collage mit Logos von Wikimedia Commons (Gradle-Logo: Hans Dockter, gemeinfrei; Apache-Maven-Logo: Apache Software Foundation, gemeinfrei); die Marken gehören ihren Inhabern.
Christian Ackermann
Softwareentwickler (C++, C, Java, C#) aus der Oberpfalz, bloggt seit 2001 über Linux, Technik und Kochen.