Hans Dockter über das Build-System Gradle

Interaktiver Build-Vergleich: Teil 2 – Gradle

Im zweiten Teil unseres interaktiven Build-Vergleichs zwischen Maven, Ant und Gradle nehmen wir das Build-System Gradle genauer unter die Lupe. Das im Vergleich zu seinen Konkurrenten jüngste Projekt geht auf eine Initiative von Hans Dockter zurück und liegt derzeit in Version 0.8 vor. Für die Beschreibung des Builds kommt bei Gradle eine Groovy-basierte domänenspezifische Sprache zum Einsatz, die sich erweitern und an die eigenen Bedürfnisse anpassen lassen soll. „Build-by-convention Support für Java-, Groovy-, OSGi-, Web- und Scala-Projekte“ schreibt sich Gradle auf der Projektseite auf die Fahnen. Projekt-Leiter Hans Dockter erklärt, was es mit dem neuen Gradle-Ansatz auf sich hat.

JAXenter: Hallo Herr Dockter! Worauf wurde (und wird) bei der Entwicklung des Gradle-Build-Systems besonderen Wert gelegt?

Hans Dockter: Wir glauben, dass Projektautomatisierung ein essentielle

r Bestandteil erfolgreicher Softwareentwicklung ist. Die Anforderungen an Projektautomatisierung sind in den letzten Jahren erheblich gestiegen und gehen weit über den klassischen Build hinaus. Wir wollen ein Tool anbieten, mit dem es so einfach wie möglich ist, diese Anforderungen umzusetzen.

Wir sind davon überzeugt, dass der deklarative Ansatz der Schlüssel zu gut wart- und erweiterbaren Enterprise Builds ist. Mit Deklarativ meinen wir, dass Benutzer nur das “Was” zu bestimmen brauchen und nicht das “Wie”. Ein Beispiel für ein deklaratives Element sind das Maven packaging– und dependency-Element. Hier müssen die Benutzer nur bestimmen, ob das Projekt z. B. ein Java- oder Webprojekt ist (ein “Was”), welche Dependencies es hat (ein “Was”). Das “Wie” (Kompilieren, Kopieren von Resourcen, Laden von Dependencies, etc. …) übernimmt dann Maven. Das ist nicht zu verwechseln mit Build-By-Convention und funktioniert auch für ein Custom Layout. Man muss dann nur ein paar mehr Angaben zum “Was” machen.

Gradle führt den deklarativen Ansatz von Maven noch viel weiter:

  • Es gibt deklarative Elemente auf unterschiedlichem Abstraktions-Level.
  • Es ist möglich, das Verhalten der Standard-Elemente anzupassen oder auch eigene Sprachelemente hinzuzufügen (über Plug-ins oder direkt im Build Skript).
  • All dies ist integriert in den Build-By-Convention-Ansatz.
  • Die deklarativen Elemente bilden eine Sprache. Die Benutzer können damit ihr Projekt auf einer hohen Abstraktionsebene selber modellieren. Oft erstellt der Build-Master das Modell für die ganze Abteilung oder Organisation und stellt dies über ein Plug-in zur Verfügung.
  • Gradle bietet auch ein Plug-in an, das ein Standard Maven Layout modelliert. Ein solches Layout ist aber nicht privilegiert und man kann dieses Plug-in erweitern (z. B. um Integrationstests im selben Projekt zu haben).

Deklarative Element können sehr mächtig sein. Gradle bietet zum Beispiel das Source-Set-Element, welches das “Was” einer logischen Gruppe von Sourcen (z. B. Ort, Klassenpfade, etc …) beschreibt. Der Benutzer muss ein solches Element nur deklarieren und bekommt dann automatisch die entsprechenden Aktionen dafür angeboten (compile, resource handling, …).

Die deklarative Schicht setzt auf einer mächtigen, imperativen Schicht auf, auf die bei Bedarf auch immer direkt zugegriffen werden kann.

Gradle ermöglicht es dem Benutzer, seine Build-Logik angemessen zu strukturieren. Es erzwingt keine Indirektionen, wenn sie unnötig sind, ermöglicht sie aber in hohem Maße, wenn die Komplexität es erfordert. Man hat endlich ein Build-System, mit dem man geläufige Design-Prinzipien der Softwareentwicklung anwenden kann. Wir denken, dass das für nicht triviale Builds sehr wichtig ist. Und einfache Builds sind in Gradle auch einfach umzusetzen. Gradle skaliert sehr gut mit den Anforderungen.

Unserer Erfahrung nach ist die Performance oft ein großes Problem von Builds. Das trifft insbesondere auf die Builds zu, die möglichst viel automatisieren. Gradle skaliert sehr gut, was die Performance anbelangt. Es gibt riesige Enterprise Builds, die Gradle produktiv benutzen (der größte hat fast 700 Sub-Projekte). Gradle Features wie der inkrementelle Build und die parallele Ausführung von Tests können die durchschnittliche Build-Zeit oft dramatisch reduzieren.

Gradle heißt das Unerwartete willkommen. Wir sind immer wieder erstaunt, welch überraschende Anforderungen unsere User haben. Und meistens sind wir erfreut zu sehen, dass Gradle einen Weg bietet, diese umzusetzen. Gradles erweiterbare Build-Sprache ist eine Vorraussetzung dafür. Eine andere sind die Vielzahl von mächtigen Extension-Points, in die man Custom Code reinhängen kann, um Anpassungen vorzunehmen. Das gilt sowohl für die Konfiguration des Builds als auch für dessen Ausführung. Um nur ein Beispiel zu nennen: Es ist sehr einfach, mit Gradle einen CI-Build so zu erweitern, dass er bei Unit-Tests, die nicht im Package com.mycomp.db sind und länger als eine Sekunde dauern, dem Autor eine E-Mail schickt. Man kann auch Gradle mit eigenen Extension Points erweitern (über Plug-ins oder Init-Skripte).

JAXenter: Wo sehen Sie die Stärken von Gradle im Vergleich zu anderen Build-Systemen, insbesondere zu Maven und Ant?

Hans Dockter: Gradle bietet viele Features, die den Build-Alltag leichter machen. Es gibt eine generische Funktion, um Teilaspekte eines Builds zu skippen. Darum muss sich bei Gradle kein Build-Master kümmern. Bei Ant muss er mit Skip Properties hantieren, bei Maven muss er an die Plug-ins ran, sofern das überhaupt möglich ist. Gradle bietet die von uns heiß geliebte Camel Case Execution zum Abkürzen von Task Names beim Ausführen von der Konsole. Es gibt einen sehr dynamischen Output, der z. B. einen Zähler für die ausgeführten Tests hat. Es gibt eine “Stand Alone” GUI, die mit gradle –gui aufgerufen werden kann. Es gibt den Wrapper, der es ermöglicht, Projekte mit Gradle zu builden, ohne dass Gradle installiert ist. Der Wrapper ermöglicht auch Zero-Administration für clientseitige Gradle-Installationen im Enterprise. Man könnte an dieser Stelle noch einiges mehr aufzählen.

Das ursprüngliche Motto von Gradle lautete: “Make the impossible possible, make the possible easy and make the easy elegant”. Dieses Motto eignet sich sehr gut, um die Eigenschaften von Gradle gegen Ant und Maven zu kontrastieren.

Ant

Ant ist ein rein imperatives Build-System. Das gibt Ant die Flexibilität, das Unmögliche möglich zu machen. Aber Ant macht es selten leicht und elegant, was oft zu schwer wart- und erweiterbaren Builds führt. Es fehlen das Deklarative und die Konventionen. Ant modelliert nicht den Problemraum. Das Ant-Modell besteht aus Task, Target, Project, Resources und Properties. Es weiß nicht, was Source Directories, Projektabhängigkeiten, etc… sind. Dies alles muss die Benutzerin selber modellieren – und das mit den limitierten Sprachelementen, die Ant bietet. Gradle bietet ein reiches, erweiterbares Modell, um Softwareprojekte zu modellieren – und dies, ohne die Flexibilität von Ant aufzugeben. Die Flexibilität ist da, wenn man sie braucht, und ansonsten im Hintergrund der deklarativen Build-Beschreibung.

Ant betrachten wir nicht in erster Linie als konkurrierendes Build-System, sondern als alternden Freund und Helfer. Das gilt vor allem für den Schatz von bestehenden Ant Tasks. Diese sind First Class Citizens in Gradle. Man kann sie auch leicht in ein Gradle-Plug-in wrappen, und schon hat man Convention over Configuration. Zur Gradle-Laufzeit kann man auch einen Ant-Build laden und mit Gradle integrieren. Man kann Abhängigkeiten von Gradle Tasks zu Ant Targets definieren und umgekehrt. Man kann auch Ant Targets von Gradle aus erweitern. Auf diese Art kann man sehr sanft – ganz oder teilweise – von Ant zu Gradle migrieren.

Maven

Selbst wenn eine Reihe von Anforderungen mit Maven einfach umzusetzen sind, passiert es trotzdem viel zu oft, dass relativ einfache Dinge sehr schwierig zu lösen sind. Projektautomatisierung ist ein wichtiger und kritischer Bestandteil erfolgreicher Softwareentwicklung, und wir erleben immer wieder, dass Dinge nicht automatisiert sind, weil sich das mit den verwendeten Build-Systemen zu schwierig gestaltet. Das gilt insbesondere für die Anforderungen, die von einem Build-System nicht antizipiert werden können. Das Umsetzen solcher Anforderungen erfordert oft Workarounds, die hohe Wartungskosten mit sich bringen. Ich möchte hier auch gerne Erich Gamma zitieren:

Frameworkitis is the disease that a framework wants to do too much for you or it does it in a way that you don’t want but you can’t change it. It’s fun to get all this functionality for free, but it hurts when the free functionality gets in the way. But you are now tied into the framework. To get the desired behavior you start to fight against the framework. And at this point you often start to lose, because it’s difficult to bend the framework in a direction it didn’t anticipate. Toolkits do not attempt to take control for you and they therefore do not suffer from frameworkitis. Erich Gamma, Quelle

Das entspricht unserer intensiven Erfahrung mit Maven und wir sehen nicht, dass sich mit Maven 3 hier etwas grundsätzlich ändern wird. Das ist auch kein Problem von XML. Gradle geht den von Erich Gamma empfohlenen Weg und bietet basierend auf Toolkits kleine, optionale Frameworks.

Interaktiver Build-Vergleich: Spielregeln

1. Runde: Wir stellen die drei selben kurzen Fragen an je einen Vertreter von Maven, Ant und Gradle.

2. Runde: Geben Sie über die JAXenter-Kommentarfunktion Ihr Feedback zurück an die Build-Experten!

3. Runde: Die Build-Experten reagieren auf Ihr Feedback und beantworten Ihre Fragen!

Darüberhinaus können Sie uns Ihre Erfahrungen mit den Buildtools auch anhand der folgenden Fragen mitteilen:

  1. Mit welchen Build-Systemen haben Sie in Ihrer Praxis bereits Erfahrungen gesammelt?
  2. Wo sehen Sie die Stärken Ihres bevorzugten Build-Systems?
  3. Wo sehen Sie Schwachpunkte der anderen Build-Systeme?
  4. Welche Fragen haben Sie an Matthew McCullough (zu Maven), Hans Dockter (zu Gradle) und Jan Matèrne (zu ANT)?

Beantworten Sie die Fragen als Kommentar zu diesem Artikel oder senden Sie Ihren Erfahrungsbericht direkt an die JAXenter-Redaktion!

Wir sind gespannt auf Ihr Feedback!

Hans Dockter: Gradle führt auch den deklarativen Ansatz von Maven weiter und öffnet ihn für die komplette Palette von unternehmensspezifischen Anforderungen (siehe oben).

Gradle bietet eine sehr leistungsstarke Unterstützung für Multi-Project Builds. Projektabhänigkeiten sind First-Class Citizens, im Gegensatz zu Maven, wo diese als ganz normale externe Abhängigkeiten modelliert sind. Dies ermöglicht viele Optimierungen (z.B. partial Builds). Und den Benutzern steht diese Information natürlich auch zur Verfügung. Gradle verwendet auch keine Vererbung, um die Gemeinsamkeiten von Subprojekten zu definieren. Anstelle dessen gibt es “Configuration Injection”. Man kann gemeinsame Konfiguration in beliebige Gruppen von Subprojekten injizieren. Die auf Maven 3.1 verschobene Mix-In Funktionalität für Poms geht in die gleiche Richtung hat aber nicht dieselbe Mächtigkeit.

Noch ein letzter Aspekt, der oft zu heftigen Diskussionen führt. Viele Maven User mögen die sehr restriktiven, unveränderbaren Vorgaben von Maven. Ihrer Meinung nach führen sie zu gut zu verstehenden und wartbaren Builds. Wir behaupten, dass oft das Gegenteil der Fall ist. Was passiert, wenn man komplexe Anforderungen in ein vereinfachendes Modell quetschen muss? Zum einen ist es aufwendig. Oft so aufwendig, dass man es nicht tut. So bleibt der Build einfach. Herzlichen Glückwunsch ;). Was passiert aber, wenn man quetscht? Dann fängt es unserer Meinung nach oft an, im Sinne von Kent Beck, “anrüchig” zu werden. Beispielsweise muss man auseinander reißen, was zusammen gehört (Shotgun Surgery). Oder man hat überflüssige Indirektionen (wie z. B. Lazy Project). Am schlimmsten ist wohl, dass man gezwungen ist, ein Grundprinzip des Domain-Driven-Designs zu verletzen: Man muss das Explizite implizit machen. Ein solcher Build mag bei oberflächlicher Betrachtung einfach aussehen. Er ist aber in Wirklichkeit oft ein Wartbarkeits-Monster.

Wir halten einen klar strukturierten Prozess für den Build einer Organisation sehr wichtig. Gradle unterstützt dies stärker als jedes andere Build Tool, das wir kennen. Aber die Organisation muss diesen Prozess selber gestalten können. Gradle bietet eine Reihe von Standardprozessen. Diese sind aber nicht privilegiert, und sie sind erweiterbar. Man kann aber auch komplett eigene entwerfen oder einen Mix verwenden.

JAXenter: Was kann Gradle von anderen Build-Systemen lernen?

Hans Dockter: Wir haben natürlich von Ant und Maven gelernt, und viel davon ist in Gradle eingeflossen. Dieser Prozess ist aber mehr oder weniger abgeschlossen. Für die Zukunft kann Gradle vor allem noch von Build-Systemen anderer Plattformen und Sprachen lernen. Diese bieten oft schon lange sehr mächtige Features, die wir in der Java-Welt bisher nicht hatten, deren Fehlens sich viele aber auch nicht bewusst sind. Ein Beispiel für so ein Feature ist ein leistungsfähiger, generischer inkrementeller Build. Den haben wir in Gradle 0.9 implementiert. Ein anderes interessantes Feature sind regelbasierte Ansätze, angewandt auf Input/Output Patterns. Mit diesen kann man z. B. für Files, die einem bestimmten Muster entsprechen, einfach Transformationen definieren. Rake und Scons sind Build-Systeme, die wir uns näher anschauen. Grundsätzlich denken wir, dass ein “Rich Model” für den Input und Output sehr wichtig ist, um leistungsfähige Lösungen für z. B. parallele und verteilte Builds zu implementieren.

Es gibt noch andere nette Sachen, die wir auch bald bieten wollen, wie z. B. inkrementelles Testen.

JAXenter: Vielen Dank für Ihre Ausführungen!

Geschrieben von
Kommentare

Schreibe einen Kommentar

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