Build management
April 2008 - Geen softwareontwikkelaar voert graag herhalende taken uit. Een beetje programmeur zal zo veel mogelijk via scripts automatiseren. Het voordeel daarvan is dat het natuurlijk tijd bespaart en de kans op fouten verkleint. Bovendien kan zo'n script ook een goede vorm van documentatie zijn: nieuwe ontwikkelaars kunnen sneller aan de slag gaan met ontwikkelen.
In een softwareproject is het belangrijkste doel het ontwikkelen van een afgerond softwareproduct. Alle softwareontwikkelaars binnen het project werken aan het project door ondermeer broncode te schrijven, die gecompileerd moet worden en daarna samengevoegd tot een installatiebestand of een webapplicatie. Vervolgens kan de applicatie geïnstalleerd worden. In grote lijnen is dat het build-proces.
Als al deze taken binnen het build-proces geautomatiseerd zijn, dan wordt het mogelijk dit proces met regelmaat automatisch uit te voeren. Er kan een centrale build-server opgezet worden, die automatisch een installatiebestand maakt (zoals een install.exe), of het product installeert op een webserver. Automatische tests kunnen uitgevoerd worden, zodat mogelijke fouten automatisch gedetecteerd worden. Testers en ontwikkelaars kunnen zodoende makkelijk de laatste versie testen en de kans op sluipende fouten is een stuk kleiner.
Om die reden is er inmiddels legio software voor automatiseren van het build-proces. Voor de Java-ontwikkelaar is de meest gebruikte en bekende software het pakket Ant. Taken die vaak herhaald moeten worden, zoals het compileren van de broncode, het inpakken naar een library of het bouwen van een archief ter distributie kunnen geautomatiseerd worden via Ant-scripts.
Helaas heeft Ant een aantal nadelen. Ten eerste, fraaie technieken zoals overerving, relaties aangeven tussen objecten of classes die de java-ontwikkelaar in de software kan gebruiken, kunnen niet gebruikt worden in Ant. Ant-scripts zijn platte, op XML-gebaseerde scripts. Via includes is hergebruik mogelijk en via macro's kunnen een soort van functies gedefinieerd worden. Zaken als overerving of aangeven van zijn niet mogelijk.
Een ander nadeel is dat Ant niets vastlegt over de structuur van een project (Network World, Inc., 2005). Source-code in een directory src of in een directory java/src, classes in een directory bin of classes, het is voor ieder project aan de ontwikkelaar om dit te bepalen.
Meestal legt een IDE als Eclipse, Netbeans of IntelliJ wel een structuur vast. De structuur verschilt alleen per IDE en is meestal beperkt tot de source en classes directory. Kortom, de structuur is meestal per project bepaald, en vaak zelfs per module door iedere ontwikkelaar afzonderlijk.
Een ander belangrijk probleem binnen softwareontwikkeling is het beheer van externe dependencies. Dependencies zijn (in dit verband) externe libraries die gebruikt worden binnen ontwikkeling (in Java meestal jar of war bestanden). Een beetje project gebruikt al snel tientallen verschillende libraries, zoals log4j, spring, hibernate en apache-commons. Veel libraries zijn zelf weer afhankelijk van andere libraries. Een library als Apache CXF (het vroegere XFire) heeft in zijn lib directory al zo'n 46 verschillende .jar files staan. Minimaal een gedeelte van die jar bestanden moeten uiteindelijk in een war of ear bestand komen. Verder hebben al die libraries weer eigen documentatie en bijbehorende tools.
Sommige van die libraries kunnen en zullen met elkaar conflicteren: al met al kunnen deze dependencies snel een chaos worden. Alle libraries in alle subprojecten administreren en controleren kost behoorlijk wat tijd en is een bron van fouten.
Hoewel al deze problemen te overzien zijn, nemen ze behoorlijk wat tijd in in beslag. Bovendien kost het nieuwe ontwikkelaars (bijvoorbeeld voor onderhoud), een stuk meer tijd een build-omgeving op te zetten, uit te zoeken hoe software gecompileerd en getest kan worden en productief te worden. Vaak ben je minimaal een halve dag bezig een werkende development-omgeving op te zetten, alle directories goed te zetten, je IDE in te stellen en een lokale testomgeving starten.
Build-management software biedt oplossingen voor alle of enkele van deze problemen. In dit artikel zal eerst een kort stukje over Ant geschreven worden en vervolgens worden een aantal producten voor build-management geïntroduceerd: Maven (Maven 2) en Ivy. Maven is een build-tool die Ant volledig kan vervangen en Ivy is een plugin voor Ant die dependency-management toevoegt. Tot slot volgt een kort verhaal over de migratie van Ant naar Maven binnen een bestaand project.
Ant
Voor de meeste Java-ontwikkelaars zal Ant geen introductie behoeven. Met het programma kunnen eenvoudig vele ontwikkeltaken geautomatiseerd worden. Ant is geschreven in Java, en werkt daardoor op alle systemen die Java ondersteunen. Er zijn tientallen standaardtaken die uitgevoerd kunnen worden. Ant-scripts hebben xml als formaat. In de xml kunnen allerlei taken uitgevoerd worden. Naast xml kunnen ook op Java gebaseerde scripttalen aangeroepen worden, zoals Groovy, JYthon of JRuby.
Op het Internet is veel documentatie en een grote hoeveelheid uitbreidingen beschikbaar voor Ant. De meest uiteenlopende taken kunnen hiermee geautomatiseerd worden, zoals het bouwen en starten van een testomgeving, het genereren van webservices en het maken van een installatiearchief. Veel development software bevat al Ant-scripts, en alle IDE's voor Java kunnen Ant scripts aanroepen of soms zelfs genereren. Met een goed Ant-script is het mogelijk compileer, deployment of distributie automatisch te laten verlopen.
Maven
Maven is een in Java geschreven tool voor build-management. De eerste versie van Maven, Maven 1 was gebouwd op Ant. Deze eerste versies van Maven werkten in veel opzichten nog niet heel soepel. Al enige jaren terug is Maven 2 uitgebracht. In tegenstelling tot de eerste versie, leunde Maven 2 niet langer zwaar op Ant. Ant-scripts kunnen nog steeds aangeroepen worden, maar alleen binnen het Maven-build-proces.
Out of the box biedt Maven een structuur voor het opzetten van een softwareproject en uiteenlopende taken voor het bouwen en distribueren van software (O'Reilly Media, Inc., 2006):
- Standaard-directorystructuren - binnen een Maven project liggen een hoop directories vast, waaronder de directory voor broncode, testcode en webapplicatiebestanden. Maven houdt vast aan het volgende principe: convention over configuration. In plaats van vele configuratiebestanden, ligt de directorystructuur en bestandsstructuur vast. Uiteraard kan via configuratie veel van die standaardnamen en structuur aangepast worden, maar dit is niet noodzakelijk en in veel gevallen ook niet aan te raden.
- Standaard build-proces. In Maven is het build-proces opgedeeld in opeenvolgende build-phases, zoals clean, compile, test, package en deploy. Tijdens iedere build-phase worden, wanneer nodig, voorgaande build-phases uitgevoerd.
- Plugins voor de meest uiteenlopende taken, zoals het aanmaken van webarchieven, ear-files, jar bestanden, deployen op een Websphere server en uitvoeren van Checkstyle op alle code. Ook is het makkelijk om zelf een plugin te maken, in bv. Java, Ant-script of Groovy.
- Depencency-management. Met Maven kunnen de afhankelijkheden tussen libraries (zoals log4j, hibernate, spring en oracle-jdbc) makkelijk aangegeven worden. Meer hierover in een volgend hoofdstuk.
- Ondersteuning voor het opdelen van projecten in subprojecten. Een Maven project kan opgedeeld worden in meerdere subprojecten. Wanneer het hoofdproject wordt gebouwd, worden alle subprojecten ook automatisch gebouwd, maar losse subprojecten kunnen ook gebouwd worden. Ook tussen projecten kunnen afhankelijkheden aangegeven worden.
- Mogelijkheid om een (web)site met informatie over een project te genereren. Zo kan automatisch een checkstyle rapport gegenereerd worden, of een rapport met de uitkomst van alle JUnit tests.
- Ondersteunen van meerdere IDE's. Maven biedt prima integratie met verschillende IDE's als Eclipse, Netbeans en IntelliJ. Het is daardoor mogelijk verschillende IDE's te gebruiken binnen een project.
Via Maven kan erg makkelijk een softwareproject voor het bouwen van een webapplicatie, of standalone applicatie opgezet worden. Het build-proces kan binnen het project makkelijk opgezet worden.
Demonstratie van Maven
De laatste versie van Maven kan gedownload worden van http://apache.maven.org. Het installatiearchief kan uitgepakt worden in bv. C:utils, waarna het handig is de bin directory aan de windows-path toe voegen (als Windows gebruikt wordt uiteraard). Nu kan het commando mvn gebruikt worden. In dit voorbeeld zal een webapplicatie opgezet worden (Network World, Inc., 2005). De structuur kan met het volgende commando:
mvn archetype:create -DgroupId=nl.whitehorses -DartifactId=hello
De eerste keer zal maven een groot aantal plugins downloaden. Na korte tijd is een projectdirectory aangemaakt, met een standaarddirectorystructuur en een voorbeeld bestand.
Figuur 1, Directorystructuur Maven
De directory bevat een pom bestand. Een pom is het Maven project-bestand. Daarnaast wordt ook een test directory aangemaakt. Hierin kunnen unit tests gezet worden. Bij het compileren van de code zal Maven standaard deze tests uitvoeren.
De meeste ontwikkelaars zullen liever met een IDE ontwikkelen. In dit geval gaan we er vanuit dat een ontwikkelaar in Eclipse wil ontwikkelen. Een eclipse project genereren kan met de Maven Eclipse plugin (Apache Software Foundation, 2008) en gaat als volgt:
mvn eclipse:prepare-workspace
mvn eclipse:eclipse
Er worden nu Eclipse project bestanden gemaakt en het project kan geïmporteerd worden in Eclipse. Maven is helaas nog niet geïntegreerd in Eclipse zelf. Deze integratie is wel mogelijk middels m2Eclipse, een Eclipse-plugin. (codehaus.org, 2008)
Er zijn zeer veel tutorials beschikbaar over Maven. Een goed begin is de Maven website zelf: http://maven.apache.org/what-is-maven.html. Op de website zijn links naar enkele gratis boeken geplaatst (Apache Software Foundation). Het boek Maven: The Definitive Guide is een redelijk goede handleiding voor Maven. Het boek Better Builds with Maven leest nog wat makkelijker. Helaas wordt dit boek niet meer gratis aangeboden, sinds het bedrijf erachter is overgenomen.
Ivy
Een alternatief voor Maven is Ivy. In tegenstelling tot Maven biedt Ivy alleen dependency-management aan. Overige taken binnen het build-proces zullen, of beter gezegd kunnen, via Ant gedaan worden. Ivy is een plugin voor Ant en is compatible met Maven, in die zin dat een Maven repository ook door Ivy gebruikt kan worden (Apache Software Foundation, Jayasoft, 2008). Om Ivy te kunnen gebruiken moet het build-script van Ant toegevoegd worden en er moet een Ivy-project bestand aangemaakt worden, zoals in het voorbeeld hieronder. Dit project bevat twee dependencies, commons-lang en log4j:
<ivy -module version="1.0"> <info organisation="whitehorses" module="mycomponent"/> <dependencies> <dependency org="commons-lang" name="commons-lang" rev="2.0"/> <dependency org="commons-cli" name="commons-cli" rev="1.0"/> <dependency name="log4j" rev="1.2.8"/> </dependencies>
</ivy>
Vervolgens moet Ivy aangeroepen worden in Ant, dit kan met de volgende toevoeging aan het build-script:
<target name="resolve"> <ivy :retrieve/> </target>
Met deze toevoeging, worden, als resolve wordt aangeroepen automatisch de opgegeven jar bestanden gedownload van een publieke repository en in een lib directory geplaatst. Niet alleen de opgegeven libraries worden gedownload, ook libraries waar deze van afhankelijk zijn.
Relaties tussen verschillende componenten kunnen grafisch weergegeven worden:
Figuur 2 Relaties tussen componenten
Het is dus vrij eenvoudig Ivy toe voegen aan een bestaand Ant project en al snel biedt de plugin een hoop voordelen.
Introductie van build management software binnen een project
In dit hoofdstuk zal ik kort toelichten hoe Maven geïntroduceerd is binnen een project. Het project liep al een redelijke tijd en was behoorlijk gestructureerd opgezet. Toch duurde het opzetten van een nieuwe ontwikkelomgeving behoorlijk wat tijd. Bovendien traden af en toe tijdrovende problemen op door conflicterende of verkeerde versies van libraries.
Een belangrijke uitdaging was het uitzoeken van de dependencies, wat bij zowel gebruik van Ivy als Maven relevant is. Verder was praktisch overzetten van Ant-scripts naar Maven-projectbestanden redelijk ingewikkeld zijn.
Bij introduceren van Maven binnen het bestaande project waren de volgende obstakels te overwinnen:
Opzetten van de projectstructuur
Gelukkig was het project behoorlijk gestructureerd, de bestaande projectstructuur kon grotendeels gebruikt worden. Enkele problemen die optraden, waren vermenging van testcode en productiecode. In een Maven-project moet dit strikt gescheiden zijn.
Ieder subproject kreeg een eigen Maven-project bestand, de zogeheten Pom file. Om de projectstructuur geschikter te maken voor Maven, zijn alle source-en resource-directories en binary directories verplaatst, zodat ze compatible met Maven werden.
Er werd een aantal 'Abstract' projecten gemaakt, service en webclient. In deze projectenbestanden werd de algemene structuur gezet voor respectievelijk de verschillende webservices en de verschillende websites. De structuur werd grofweg als volgt:
Figuur 3 Relaties tussen subprojecten
Het project bestond uit meerdere services en webapplicaties. De Userregistration webapplicatie was afhankelijk van de Users-service, de AccountView webapplicatie van zowel de Accounts- als Users-service. Afzonderlijke projecten konden gebouwd worden, alsmede in een keer alle projecten te samen.
Invoegen proprietary tools
Het project maakte gebruik van diverse proprietary, commerciële tools. Die werden gebruikt om webservices te genereren en te gebruiken (consumeren). Doordat deze software een bepaalde directorystructuur verwachtte, waren behoorlijk wat aanpassingen en werk nodig. Een service applicatie produceerde zowel een war bestand als een client-jar bestand, om de service te benaderen.
Uitzoeken dependencies
Het uitzoeken van alle dependencies bleek een behoorlijke uitdaging. Het project was afhankelijk van ruim 20 verschillende libraries. Soms werden binnen verschillende projecten verschillende versies gebruikt. Vaak waren libraries ook niet beschikbaar in publieke repositories.
Er moest een lokale repository opgezet. Na een korte evaluatie is voor Artifactory (jfrog, 2008) gekozen. Deze repository server is vrij makkelijk om op te zetten en in gebruik.
Vervolgens moesten alle relaties van alle subprojecten met externe libraries benoemd worden in de Maven projectbestanden gezet worden. De relaties tussen de projecten moest ook benoemd worden. Dit was niet bijzonder moeilijk (als dat niet duidelijk zou zijn, is er vermoedelijk een groter probleem binnen het project).
Om uit te zoeken welk Maven artifact gebruikt kon worden voor elke library, zijn een aantal zoekmachines beschikbaar, zoals http://mvnrepository.com/ en http://maven.ozacc.com/search en tot slot Google.
Veel libraries, waaronder commerciele libraries waren niet beschikbaar in de publieke repository. Zo'n library is in de lokale repository geplaatst. zodat deze beschikbaar was binnen het project, maar niet voor de gehele wereld. Installeren van zo'n library in de lokale repository kon als volgt:
mvn install:install-file -DgroupId=com.oracle -DartifactId=ojdbc14 -Dversion=10.2.0.2.0 -Dpackaging=jar -Dfile=libsharedojdbc14.jar
Al met al duurde het introduceren al een maand. Achteraf kan gezegd worden, dat wanneer al een groot aantal Ant-scripts in gebruik zijn, introductie van Maven meer tijd kan kosten dan het oplevert. Of het een kostenbesparing oplevert, hangt natuurlijk mede af van de lengte van het project.
Wanneer een nieuw softwareproject gestart wordt, waar geen bestaande Ant-scripts gebruikt hoeven te worden, lijkt Maven de beste keuze.
Conclusie
Het automatiseren van het build-proces binnen een softwareproject levert heel veel op aan gemak en tijdbesparing. Veel bestaande projecten gebruiken al Ant. Als een softwareproject een redelijke grootte heeft, is het waard dependency-management software te gebruiken als Ivy (Sampaleanu, 2005). Relaties tussen subprojecten en externe libraries kunnen dan makkelijk beheerd worden.
Bij nieuwe projecten is het gebruik van Maven een erg goede keuze, gezien het grote aantal plugins en standaardfunctionaliteit die het framework biedt.
Bronvermelding
- Apache Software Foundation. (n.d.). Books on Maven. Retrieved April 2008: maven.apache.org/articles.html
- Apache Software Foundation. (2008). Maven Eclipse Plugin. Retrieved April 2008: maven.apache.org/plugins/maven-eclipse-plugin/
- Apache Software Foundation. (2008). Maven Getting Started Guide: maven.apache.org/guides/getting-started/
- Apache Software Foundation. (n.d.). What is Maven. Retrieved 2008: maven.apache.org/what-is-maven.html
- Apache Software Foundation, Jayasoft. (2008). Retrieved April 2008: ant.apache.org/ivy/features.html
- codehaus.org. (2008). Maven Integration for Eclipse: m2eclipse.codehaus.org/
- jfrog. (2008). Retrieved April 2008, from Artifactory: www.jfrog.org/sites/artifactory/latest/
- Network World, Inc. (2005). An introduction to Maven 2. Retrieved April 2008: www.javaworld.com/javaworld/jw-12-2005/jw-1205-maven.html
- O'Reilly Media, Inc. (2006). Maven 2.0: Compile, Test, Run, Deploy, and More. Retrieved April 2009, from OnJava.com: www.onjava.com/pub/a/onjava/2006/03/29/maven-2-0.html
- Sampaleanu, C. (2005). Decision to use Ivy is a no-brainer. Retrieved April 2008, from sampa : colin's blog: blog.exis.com/colin/archives/2005/04/29/decision-to-use-ivy-is-a-no-brainer/
- Whitehorses (2007). Voortdurend Integreren, Voortdurend Controle. Retrieved April 2008: http://www.whitehorses.nl/voortdurend_integreren%252C_voortdurend_controle__1736.1195.html
Over de auteur
Gerbrand van Dieijen is java-consultant bij Whitehorses. Ooit begonnen als softwareontwikkelaar naast zijn studie, ontwikkelt hij al vijf jaar professioneel software. Hij heeft ervaring in het ontwikkelen van software in Java, web- en desktop-applicaties, persistency en continuous integration.