embarc logo
embarc logo

Architektur-Porträt: Das Build-Management-Tool Maven

Stefan Zörner Stefan Zörner
05.12.2023

Lesezeit: 12 Minuten

Der Urvogel aller Werkzeuge, die das Bauen von Software adressieren, ist make (1976). Es ist sehr universell, im Grunde lässt sich mit make alles verwalten und machen, was per Kommandozeile aufrufbar ist – zum Beispiel Java-Programme bauen. Für Programmiersprachen abseits von C / C++ ist es heute allerdings üblicher, spezifische Tools einzusetzen. Im Fall von Java beherrscht Apache Maven seit langem die Szene – das Licht erblickte es vor über 20 Jahren. Maven setzte Impulse für viele Tools, auch über die Java-Welt hinaus. Dieses Porträt beschreibt die Ziele und Lösungsideen des Build-Werkzeugs.

 

Steckbrief: Build-Management-Tool Maven

Name: Apache Maven
Software-Gattung: Build-Management-Werkzeug
Veröffentlicht: 2002, Apache Top Level Projekt seit 2003, Version 1.0 2004
Herkunft/Ursprung: Apache Software Foundation, Open Source
Zielplattform: plattformunabhängig (JVM erforderlich)
Programmiersprache(n): Java
Homepage: maven.apache.org

 

Um Software zu schreiben und zum Laufen zu bringen braucht es nicht viel. Für ein „Hello, World“ reicht eine Programmiersprache inklusive Übersetzer (Compiler, Interpreter) und ein einfacher Editor für den Quelltext aus. Was aber, wenn die Software umfangreicher wird, von externen Bibliotheken und Frameworks abhängt, verschiedene Personen oder Teams an der Entwicklung beteiligt sind, und sich auch Außenstehende dazugesellen, wie bei Open Source-Projekten üblich?

Auch wenn sich die Herausforderungen für verschiedene Entwicklungsteams im Detail unterscheiden, stehen bei Bauen (Build) und Verteilung (Deployment) von Software in solchen Kontexten immer die gleichen Aufgaben an. Das motiviert den Einsatz von Standard-Tools und Best Practices; das Entwicklungsteam konzentriert sich auf seine eigentliche Arbeit.

Build-Management-Tools

Komplexe Softwaresysteme bestehen aus vielen Quelltextdateien. Bei Threema, dem Portrait der letzten Folge dieser Reihe [Zör2023], sind es aktuell über 1600 Einzeldateien (Java, Kotlin, Protocol Buffers) allein für die Android-App – hinzu kommen die iOS-App, das Backend als verteiltes System und einiges mehr. All dies in ausführbare Programme zu verwandeln und zu verteilen beinhaltet eine Reihe von Schritten. Es sind zahlreiche Fremdbibliotheken in der richtigen Version zu organisieren, die Quelltexte in Binärcode zu übersetzen, Tests auszuführen, die Ergebnisse dann zu Einheiten zu bündeln, und noch einiges mehr.

Vor Werkzeugen wie make haben sich Teams mit Shell-Skripten beholfen, um all diese Schritte in der richtigen Reihenfolge festzuhalten, ausführbar und vor allem reproduzierbar zu machen. Solche Skripte sind allerdings betriebssystemabhängig und schnell nur noch schwer zu durchschauen. In make – Bestandteil von Unix, aber mittlerweile auch für andere Plattformen verfügbar – erfolgt die Beschreibung des Builds in einem speziellen, textbasierten Format. Das sogenannte Makefile nennt Eingabedateien, Build-Ziele und erforderliche Schritte dazu, Abhängigkeiten untereinander. Es erlaubt Muster, Macros und Regeln. Insbesondere ist es mit make möglich nur Dinge neu übersetzen (oder allgemeiner: verarbeiten) zu lassen, deren Quellen sich zwischenzeitlich geändert haben. Diese Konzepte finden sich heute in allen gängigen Build-Werkzeugen wieder.

Eine Alternative zu einem Kommandozeilen-Werkzeug wie make stellten vor allem in der Vergangenheit integrierte Entwicklungsumgebungen (IDEs) dar. Die sind ebenfalls oft von Haus aus in der Lage, komplexe Softwarelösungen zu bauen. Was zunächst komfortabel wirkt, behindert aber gerade in größeren Vorhaben oftmals reproduzierbare Builds. Denn Teammitglieder konfigurieren ihre IDE gerne unterschiedlich. Vielleicht benutzen sie sogar unterschiedliche IDEs. Gerade Open Source-Projekte gewähren hier gerne Freiheiten. Ein erfolgreicher Build hängt plötzlich davon ab, wo er läuft. Der berühmte Ausspruch „It builds on my machine …“ stammt aus so einem Umfeld. Heute ist es eher üblich, dass IDEs Build-Werkzeuge integrieren, anstatt ihre Funktionalität nachzubilden.

Bauen in der Java-Welt

Das lange Zeit vorherrschende Werkzeug in der Java-Welt zum Bauen von Anwendungen war Apache Ant [Ant]. Das in Java realisierte Werkzeug erschien 2000 als plattformunabhängige Open Source-Alternative zu make. Als Format zur Beschreibung des Builds benutzt Ant das zeittypische XML. Die Lösung brachte viele vordefinierte Tasks mit und hatte ein Plugin-Konzept zur Erweiterung durch Dritte. Da Apache-Projekte für die Java-Community eine große Rolle spielten, erfreute sich auch Ant schnell großer Beliebtheit. Innerhalb kurzer Zeit nutzte jedes Java-Vorhaben Ant – egal ob in Unternehmen oder Open Source – darunter auch praktisch alle in Java entwickelten Apache-Projekte.

Keimzelle von Maven ist Apache Turbine, ein heute fast in Vergessenheit geratenes Framework für Webapplikationen. Das Projektteam baute Turbine ursprünglich ebenfalls mit Ant, war damit aber unzufrieden. Zwei besonders große Schwächen von Ant waren die unzureichende Unterstützung bei externen Projektabhängigkeiten (Apache Ivy [Ivy] adressierte das Problem erst später für Ant) und fehlende Standards. Flexibilität ist eigentlich etwas Gutes, aber es führte hier dazu, dass Java-Projekte grundlegende Dinge ohne Not unterschiedlich machten und benannten. Das offensichtlichste Beispiel hierzu ist die Organisation der Projektdateien in Verzeichnissen und damit auch der Versionsverwaltung. Liegen die Quelltexte unterhalb von src oder source? Liegen Unit-Tests in einem separaten Teilbaum oder direkt neben dem zugehörigen Produktiv-Code … Dies (und weitere fehlende Konventionen, Ant gibt wenig vor) führten zu vergleichsweise hohen Einarbeitungszeiten in Java-Projekten.

Apache Maven

Ursprünglich als Unterprojekt exklusiv für Turbine im Einsatz löste Jason van Zyl Maven 2002 als Produkt heraus; ein Jahr später wurde es ein eigenständiges Toplevel-Projekt bei der Apache Software Foundation. Tabelle 1 listet die Architekturziele des Build-Management-Tools grob in der Reihenfolge ihrer Wichtigkeit auf – das wichtigste zuerst.

Ziel Beschreibung (und zugehörige(s) Software-Qualitätsmerkmal(e))
Einfach damit zu starten Es ist einfach für ein neues Vorhaben mit Maven zu starten. Neue im Team und Außenstehende, welche die Lösung kennenlernen oder selbst bauen wollen, finden sich schnell in einem bestehenden Build zurecht.(Benutzbarkeit)
Baut Software sicher und zuverlässig Maven baut Projekte störungsfrei und reproduzierbar. Im Fehlerfall unterstützt es bestmöglich bei der Ursachenforschung. (Zuverlässigkeit)
Integration mit typischen Tools Maven integriert nahtlos gängige Werkzeuge des Build- und Deployment-Prozesses wie z.B. Compiler, automatisierte Tests und Release-Management. Umgekehrt lässt es sich selbst leicht in IDEs und Werkzeuge aus dem CI/CD-Bereich integrieren.(Kompatibilität)
Beherrscht auch komplexe Projekte Mit Maven lassen sich auch umfangreiche, mehrteilige Projekte mit vielen Abhängigkeiten und langer Lebensdauer realisieren und angemessen schnell bauen.(Skalierbarkeit)
Erweiterbar, auch durch Dritte Nicht nur das Maven-Projekt selbst, sondern auch Außenstehende können die Lösung um Funktionalität erweitern, und diese Erweiterungen einfach anderen zur Verfügung stellen. (Erweiterbarkeit)
Tabelle 1: Zentrale Architekturziele von Apache Maven

Wie geht Apache Maven diese Ziele an? Abbildung 1 gibt einen Überblick über die wesentlichen Begriffe und Lösungskonzepte und setzt sie durch Pfeile in Beziehung. Vereinfacht ist Maven ein Framework oder eine Ablaufumgebung für Plugins. Sowohl Basisfunktionalität als auch Erweiterungen durch Dritte sind als solche realisiert [MavPlug]. Vom Quelltextumfang ist der Kern von Maven verglichen selbst nur mit den offiziell mitgelieferten Plugins klein (aktuell bezüglich Lines of Code geringer als 25%). Das Übersetzen von Quelltext, das Ausführen von Tests, das Paketieren von Anwendungen, das Schnüren von Releases, das Bauen von Dokumentation … all das ist in Plugins realisiert.

Das Pendent zum Makefile ist die pom.xml-Datei als Dreh- und Angelpunkt für Projektspezifika. POM steht für Project Object Model. Hier finden sich Eigenschaften wie Projektname und Version, aber auch spezielle Plugins, die Standardabläufe abändern oder ergänzen. Es ist der Einstiegspunkt für Außenstehende, quasi ein Beipackzettel unter Versionsverwaltung.

Einfach damit zu starten

Anders als Ant lebt Maven das Prinzip „Convention over Configuration“. So gibt es eine Standardgliederung für die Verzeichnisstruktur, Standardlebenszyklen und vordefinierte Build-Phasen. All das lässt sich zwar umkonfigurieren und erweitern, aber ein einheitlicher Rahmen ist gesetzt. Maven propagiert ihn durch Projektvorlagen, die sogenannten Archetypes. Über diese kann ein Team per Maven-Kommandozeile oder auch über entsprechende Dialoge in einer IDE neue Projekte anlegen. Maven selbst und auch Dritte, wie beispielsweise Framework-Anbieter, stellen solche Vorlagen über öffentliche Repositories zur Verfügung. Neue Vorhaben lassen sich so sehr bequem starten. Und vor allem sehen sie nachher in aller Regel so aus, wie die Best Practices von Maven und oder Frameworks es vorsehen. Im Grunde immer gleich – pom.xml inklusive.

Ein zweiter wichtiger Lösungsansatz in Maven ist das Abhängigkeitsmanagement. Java-Projekte nutzen traditionell zahlreiche Bibliotheken und Frameworks, die über die Standardklassenbibliothek hinausgehen. Bereits für Unit-Tests ist eine Fremdbibliothek erforderlich.

Abhängigkeiten werden in der pom.xml vereinbart, gruppiert nach dem Zeitpunkt, wann sie benötigt werden (nur zum Bauen, auch zur Laufzeit …). Um die Dinge (in der Maven-Sprache: Artefakte) eindeutig ansprechen zu können hat Maven sogenannte Koordinaten eingeführt. Hierbei handelt es sich um eine Angabe in der Form „groupId:artifactId:version“, z.B. „org.junit.jupiter:junit-jupiter-api:5.10.0“ für JUnit 5. Bei der Group-ID ist der umgedrehte Domain-Name des Anbieters üblich (z.B. „org.apache“), was die Eindeutigkeit der Koordinaten sicherstellt. Die Koordinaten für sein eigenes Vorhaben vereinbart das Team in seiner pom.xml (siehe Abbildung 2).

Repositories

Mit den Koordinaten ist Maven in der Lage, die Artefakte aus Repositories herunterzuladen. Eine besondere Rolle spielt dabei Maven Central. Das Repository birgt Millionen von Artefakten; viele Open Source-Projekte stellen ihre Software darüber zentral zur Verfügung. Auch frühere Versionen bleiben abrufbar, unabdingbar für das Bauen älterer Software.

Neben diesem zentralen Repo können Unternehmen auch private Repositories aufsetzen, um eigene Bibliotheken, Frameworks oder Plattform-Bestandteile auf die gleiche Weise zuverlässig zu verteilen. Auch unternehmenseigene Archetypes können so etabliert werden.

Tatsächlich kennt Maven drei Arten von Repositories: zentrale, private und ein lokales auf der Platte des Build-Rechners. Dies kann auch die Entwicklungsmaschine eines Teammitgliedes sein. Maven schaut als erstes dort, ob ein Artefakt bereits lokal vorliegt, es fungiert als Cache. So muss nicht bei jedem Build das halbe Internet heruntergeladen werden.

Zuverlässig und sicher bauen

So archaisch XML heute erscheinen mag – das zugehörige Schema sichert ab, dass die Build-Datei gültig ist. Texteditoren können damit unmittelbar Unterstützung anbieten, Syntaxfehler sind ausgeschlossen. Zum Vergleich: Bei Makefiles gilt die Einrückung und ob es sich dabei um Tabulatorzeichen handelt als klassische Fehlerquelle.

Falls gewünscht gewährleistet der Maven Wrapper, dass ein Projekt mit einer bestimmten Maven-Version gebaut wird, ohne dass Maven dafür installiert sein muss – die richtige Version wird zu Beginn des Builds heruntergeladen.

Darüber hinaus hat Maven Werkzeuge eingebaut, die bei der Problemanalyse im Build unterstützen, etwa die Anzeige des Abhängigkeitsbaums oder der Wirkung von Vererbung bei „verschachtelten“ Build-Files („Parent POM“).

Integrieren und Erweitern

Maven ist von Hause aus ein Kommandozeilenwerkzeug, und als solches einfach in viele Umgebungen einzubinden, allen voran in Build-Server. Die Java-API von Maven erlaubt aber auch eine tiefere Integration, insbesondere in Systeme, die in Java realisiert sind. Hier wären IDEs wie IntelliJ zu nennen, die passende Erweiterungen zum komfortablen Arbeiten mit Maven direkt aus der Entwicklungsumgebung heraus anbieten. Auch für CI/CD-Server wie Jenkins gibt es eine spezielle Integration, welche über den bloßen Kommandozeilenaufruf hinausgeht, aber auch ihre Tücken hat (zu Risiken siehe [Jenkins]).

Umgekehrt lässt sich über das Plugin-Konzept im Grunde alles in Maven integrieren. Man entwickelt in Java und implementiert ein Interface, was zeitgemäß Mojo heißt (in Anlehnung an POJOs, die 2002 durch Spring en vogue waren). Und klar: Maven stellt ein Archetype für eigene Plugins zur Verfügung.

Dass ein Projekt selber ein Plugin für Maven baut, ist nicht oft von Nöten – die Maven-Seite und das MojoHaus-Project [MoHa] listen zahlreiche funktionale Erweiterungen auf, um andere Aufgaben als die von Hause aus mitgelieferten im Build anzustoßen. Das betrifft sogar Plugins für das Übersetzen von Programmiersprachen, die nicht auf der JVM laufen. Gleichwohl bleibt Maven ein Werkzeug der Java-Welt, für andere Programmiersprachen sind andere Build-Tools üblicher. Etwa sbt für die JVM-Sprache Scala.

Neben den Plugins bietet Maven mit Extensions einen weiteren Erweiterungsmechanismus an. Bei Plugins geht es vorrangig darum, Aufgaben in den Build zu integrieren – Maven ruft die Funktionalität zum passenden Zeitpunkt auf. Eine Extension hingegen greift in Maven selbst ein – entsprechend fundamental sind die damit verbundenen Features. Hierzu zählen die Unterstützung anderer POM-Formate als XML, Profiler oder ein Build Cache für das effiziente Bauen insbesondere großer Vorhaben.

Große Projekte bauen

Der Schlüssel, um mit Maven auch umfangreiche Vorhaben zu bauen, ist die Modularisierung. Projekte lassen sich dazu in Maven beliebig schachteln, Eigenschaften und Abhängigkeiten aus übergeordneten pom.xml-Dateien übernehmen (Prinzip: „Don’t repeat yourself“). Maven berücksichtigt Abhängigkeiten zwischen Modulen und ermittelt eine sinnvolle Build-Reihenfolge, bzw. beanstandet Zyklen, die ein Bauen unmöglich machen.

Abb. 3: Zentrale Lösungsansätze von Apache Maven mit Zuordnung zu den Zielen (Farbcode)
Abb. 3: Zentrale Lösungsansätze von Apache Maven mit Zuordnung zu den Zielen (Farbcode)

Um auch effizient mit umfangreichen Projekten arbeiten zu können lassen sich Module gezielt einzeln bauen, Builds und Tests bei Bedarf parallel ausführen und auf den Build Cache zurückgreifen.

In Unternehmen, die viel mit Maven arbeiten, sind private Repositories und eigene Archetypes ein probates Mittel, um Bibliotheken und Projektstrukturen organisationsweit zu vereinheitlichen und durchzusetzen.

Die Welt nach Maven

Maven hat Ant praktisch verdrängt; auch nach über 20 Jahren ist es Marktführer bei den Java-Build-Tools. JRebel ermittelte 2022 bei der Frage “What Build Tool Do You Use in Your Main Application?” für Maven 68% [JReb2022]. Aber es ist nicht konkurrenzlos. 2008 erschien mit Gradle eine Lösung, die sich recht schnell den zweiten Platz erarbeitet hat. Andy Wilkinson diskutiert in einem Blog-Beitrag den Umstieg des Spring Boot-Projektes von Maven auf Gradle, Beweggründe inklusive [Wil2020]. Statt Maven Archetypes kommen vermehrt flexiblere sogenannte Initializr zum Einsatz, um ein neues Projekt aufzusetzen. Abbildung 4 zeigt als Beispiel den von Spring Boot – das Build-Tool lässt sich auswählen: Gradle oder Maven.

Abb. 4: Ein neues Spring-Projekt aufsetzen, inkl. Auswahl des Build-Tools
Abb. 4: Ein neues Spring-Projekt aufsetzen, inkl. Auswahl des Build-Tools

Gradle greift viele Ideen von Maven auf, setzt etwa auf das gleiche Directory Layout und nutzt dieselben Repositories und Koordinaten. Es punktet vor allem bei der Flexibilität. Die Build-Files sind keine XML-Dateien, sondern Groovy (bzw. Kotlin) DSL-Skripte, in die man im Extremfall direkt Dinge „hineinprogrammiert“. Nicolas Fränkel führt aus, dass diese Flexibilität nicht nur selten gebraucht wird, sondern schlussendlich das stärkste Argument für Maven, nämlich Standardisierung, aushebeln kann [Fra2023]. Unbestritten sind allerdings die Impulse, die Gradle in die Szene gegeben hat, und die auch Maven aufgegriffen hat. Beim oben beschriebenen Wrapper beispielsweise hat man sich direkt von Gradle inspirieren lassen.

Gradle hat bei den Build-Zeiten gegenüber Maven die Nase vorn und ist die erste Wahl bei Android-Apps. Gleichwohl steht es auf den Schultern von Riesen – make, Ant, Maven. Viele Dinge, die Maven für die Java-Welt etabliert hat, finden sich auch in den Tools anderer Plattformen wieder. Etwa npm (2010) für JavaScript/Node.js oder pip (2008) für Python. So gesehen ist Maven insbesondere in der Paketverwaltung ein Vorreiter über die Java-Welt hinaus.

 

Weiterführende Informationen

[Ant] Apache Ant, https://ant.apache.org
[Fra2023] Nicolas Fränkel: “My final take on Gradle (vs. Maven)”, Blog-Beitrag, https://blog.frankel.ch/final-take-gradle/
[Ivy] Apache Ivy, https://ant.apache.org/ivy/
[Jenkins] Jenkins Dokumentation: „Jenkins plugin for building Maven jobs“, https://plugins.jenkins.io/maven-plugin/
[JReb2022] JRebel: “Java Developer Productivity Report 2022. Java Development Trends and Analysis”, Perforce Software 2022
[MavPlug] Verfügbare Plugins für Maven, https://maven.apache.org/plugins/
[MoHa] MojoHaus Project, Sammlung von Plugins für Apache Maven, https://www.mojohaus.org
[Wil2020] Andy Wilkinson: “Migrating Spring Boot’s Build to Gradle”, https://spring.io/blog/2020/06/08/migrating-spring-boot-s-build-to-gradle
[Zör2023] Stefan Zörner: „Architektur-Portrait #7: Der mobile Instant-Messenger Threema“, in IT-Spektrum 04/2023

 

Cover IT Spektrum 06/2023 Dieses Porträt ist ursprünglich in der IT Spektrum, Ausgabe 6 | 2023 als achter Teil einer Reihe über Architektur-Ikonen der Softwareentwicklung erschienen. Rückmeldungen aller Art gerne an mich per E-Mail. Insbesondere auch Wünsche für weitere Porträts.

 

Mehr im embarc-Blog. Das könnte Sie auch interessieren:

Architektur-Porträt: Der statische Website-Generator Hugo
Architektur-Porträt: Der mobile Instant-Messenger Threema
Architekturikonen in Software Überblick über alle Porträts