Gradle statt Maven: Warum wir umgestiegen sind
Zurück zum Blog

Gradle statt Maven: Warum wir umgestiegen sind

5 Min. Lesezeit
Lesen auf English

Gradle statt Maven: Warum wir umgestiegen sind

Wer im Java-Umfeld arbeitet, kommt an Maven kaum vorbei. Seit Jahren ist es das Standard-Build-Tool in der Enterprise-Welt -- bewährt, weit verbreitet und von praktisch jeder IDE unterstützt. Trotzdem haben wir uns bei encircle360 entschieden, unsere Projekte auf Gradle zu migrieren. In diesem Artikel erklären wir, was uns zu diesem Schritt bewogen hat und welche Erfahrungen wir dabei gesammelt haben.

Was uns an Maven gestört hat

Maven funktioniert. Das steht ausser Frage. Für einfache Projekte mit Standardstruktur liefert es zuverlässig Ergebnisse. Aber sobald ein Projekt wächst oder die Build-Logik komplexer wird, stösst man mit Maven an Grenzen, die sich nur umständlich überwinden lassen.

XML als Build-Sprache ist der offensichtlichste Kritikpunkt. Eine pom.xml mit mehreren hundert Zeilen ist keine Seltenheit, und das Hinzufügen eigener Build-Logik erfordert entweder das Schreiben eines eigenen Maven-Plugins oder den Einsatz des maven-antrun-plugin -- beides wenig elegant. Hinzu kommt, dass Multi-Module-Projekte in Maven schnell zu einer Menge an redundanter Konfiguration führen, selbst mit vererbten Parent-POMs.

Build-Performance war für uns aber der ausschlaggebende Punkt. In einem Projekt mit mehreren Modulen dauerte ein vollständiger Maven-Build regelmässig über zwei Minuten. Jede kleine Änderung an einem einzigen Modul löste einen kompletten Rebuild aller abhängigen Module aus. Das summiert sich über den Tag.

Warum Gradle

Gradle adressiert genau diese Schwachstellen. Es kombiniert die Konventionen von Maven mit der Flexibilität einer echten Programmiersprache -- Groovy -- als Build-DSL. Das Ergebnis ist ein Build-System, das sowohl für einfache als auch für komplexe Szenarien gut funktioniert.

Die Groovy-DSL

Statt XML schreibt man Build-Skripte in Groovy. Das klingt zunächst nach einer unnötigen Hürde, ist aber in der Praxis ein grosser Gewinn. Eine typische build.gradle für ein Spring-Boot-Projekt sieht so aus:

plugins {
    id 'java'
    id 'org.springframework.boot' version '2.0.0.RELEASE'
    id 'io.spring.dependency-management' version '1.0.4.RELEASE'
}

group = 'com.encircle360'
version = '1.0.0-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    runtimeOnly 'org.postgresql:postgresql'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

test {
    useJUnitPlatform()
}

// Eigene Build-Logik: einfach als Task definieren
task printVersion {
    doLast {
        println "Aktuelle Version: ${version}"
    }
}

Was hier sofort auffällt: Die Datei ist kompakt, lesbar und -- vor allem -- erweiterbar. Eigene Build-Logik lässt sich direkt als Task definieren, ohne ein separates Plugin schreiben zu müssen. Für Java-Entwickler ist Groovy schnell zu lesen, auch ohne tiefe Vorkenntnisse.

Es gibt übrigens auch ein Kotlin-DSL für Gradle, das sich gerade in Entwicklung befindet. Für den produktiven Einsatz würden wir Stand heute aber noch zum bewährten Groovy-DSL raten.

Inkrementelle Builds

Das Feature, das den grössten Unterschied im Alltag macht, sind inkrementelle Builds. Gradle verfolgt für jeden Task, welche Dateien als Input dienen und welche Outputs erzeugt werden. Wenn sich seit dem letzten Build nichts am Input geändert hat, wird der Task übersprungen -- markiert als UP-TO-DATE.

In der Praxis bedeutet das: Wenn man eine einzelne Java-Klasse ändert, kompiliert Gradle nur das betroffene Modul und überspringt alles andere. Bei unseren Multi-Module-Projekten hat das die durchschnittliche Build-Zeit von über zwei Minuten auf unter 20 Sekunden reduziert. Das ist kein marginaler Unterschied -- das verändert den Entwicklungsalltag spürbar.

Build Cache

Seit Gradle 4.x ist der Build Cache standardmässig verfügbar. Er geht noch einen Schritt weiter als inkrementelle Builds: Selbst wenn man zwischen Branches wechselt oder einen clean ausführt, kann Gradle bereits erzeugte Outputs aus dem Cache wiederverwenden, sofern die Inputs identisch sind.

Der Build Cache lässt sich mit einer einzigen Zeile in der gradle.properties aktivieren:

org.gradle.caching=true

Besonders in CI/CD-Pipelines macht sich das bemerkbar. Wenn mehrere Entwickler ähnliche Änderungen bauen, können Build-Ergebnisse teamweit geteilt werden -- über einen Remote Build Cache.

Der Gradle Wrapper

Ein Detail, das wir von Anfang an schätzen gelernt haben, ist der Gradle Wrapper (gradlew). Er stellt sicher, dass jeder Entwickler und jede CI-Umgebung exakt dieselbe Gradle-Version verwendet -- ohne manuelle Installation. Das gradlew-Skript und die zugehörigen Dateien werden ins Repository eingecheckt:

gradlew
gradlew.bat
gradle/
  wrapper/
    gradle-wrapper.jar
    gradle-wrapper.properties

Ein neuer Entwickler klont das Repository und kann sofort ./gradlew build ausführen. Keine Installationsanleitung, keine Versionskonflikte. Maven hat mit dem Maven Wrapper inzwischen nachgezogen, aber Gradle hat dieses Konzept schon früh etabliert.

Spring Boot und Gradle

Da wir bei encircle360 viel mit Spring Boot arbeiten, war die Integration ein wichtiges Kriterium. Spring Boot unterstützt beide Build-Tools gleichwertig. Der Spring Initializr (start.spring.io) bietet sowohl Maven- als auch Gradle-Projekte an.

Das spring-boot-gradle-plugin kümmert sich um alles Nötige: Es erstellt ausführbare JARs, verwaltet die Dependency-Versionen über das io.spring.dependency-management-Plugin und bietet Tasks wie bootRun für den schnellen Start während der Entwicklung.

Gerade das dependency-management-Plugin ist hervorzuheben: Es übernimmt die BOM-Verwaltung (Bill of Materials) von Spring Boot, sodass man in den meisten Fällen keine expliziten Versionsnummern für Spring-Abhängigkeiten angeben muss.

Wo Maven weiterhin seine Berechtigung hat

Fairerweise muss man sagen: Maven ist nicht schlecht. Für viele Projekte ist es nach wie vor eine gute Wahl. Die Stärken von Maven liegen in seiner Einfachheit und Vorhersehbarkeit. Das "Convention over Configuration"-Prinzip funktioniert hervorragend, solange man sich innerhalb der Konventionen bewegt.

Maven hat ausserdem ein reiferes Plugin-Ökosystem und ist im Enterprise-Umfeld tiefer verankert. Wer ein einfaches Projekt ohne besondere Build-Anforderungen aufsetzt, wird mit Maven wahrscheinlich schneller zum Ziel kommen. Es gibt schlicht weniger zu konfigurieren und weniger Freiheitsgrade, die man falsch nutzen könnte.

Auch die IDE-Unterstützung für Maven ist nach wie vor hervorragend. IntelliJ IDEA und Eclipse verstehen Maven-Projekte nativ und tadellos. Die Gradle-Integration hat in den letzten Jahren stark aufgeholt, ist aber gelegentlich noch etwas hakelig bei der Synchronisation.

Unser Fazit

Für uns hat sich der Wechsel zu Gradle gelohnt. Die schnelleren Builds, die Flexibilität der Groovy-DSL und Features wie der Build Cache machen den Entwicklungsalltag produktiver. Die Migration bestehender Projekte war überschaubar -- die Abhängigkeiten aus der pom.xml lassen sich fast 1:1 in die build.gradle übertragen.

Wer vor der Entscheidung steht: Probiert es aus. Gradle hat eine gewisse Lernkurve, gerade wenn man von Maven kommt. Aber der Invest zahlt sich aus, besonders bei Projekten, die über ein einzelnes Modul hinausgehen.

Teilen

Patrick Hütter

Geschrieben von

Patrick Hütter

Gründer & Software-Architekt

Softwarearchitekt, Ingenieur und Unternehmer. Patrick baut seit über einem Jahrzehnt Produkte und Plattformen — von Enterprise-Backends über Cloud-Native-Infrastruktur bis hin zu KI-gestützten Anwendungen. Als Gründer von encircle360 verbindet er technische Tiefe mit unternehmerischem Denken und treibt Open-Source-Projekte voran, die echten Impact haben.