- Blog Xebia France - http://blog.xebia.fr -
Maximum Maven
Posted By Aurélien Maury On Jeudi 30 avril 2009 @ 17:28 In Divers | 7 Comments
Maven, le célèbre outil de management de build de projet, est souvent considéré comme difficile d’approche. Le principal point rebutant, souvent mis en lumière, est la complexité de gestion des fameux fichiers pom.xml, qui décrivent les processus de build. Pour se motiver, il est important de se souvenir que, parmi ceux qui ont pris le temps de s’y intéresser, bien rares sont ceux qui font demi-tour. Comme en code, il existe des bonnes pratiques qui, si elles sont respectées, permettent de s’y retrouver facilement.
La route est longue mais la voie est libre. Voyons donc ensemble quelques règles de bonne conduite pour conserver des pom.xml maintenables et faire durer la lune de miel avec Maven.
Dès que vous travaillez avec Maven sur un véritable projet, c’est la première chose à faire. Un classique est d’utiliser Nexus, le dépôt open source de Sonatype. Avoir un dépôt en réseau local accessible par tous les membres de l’équipe présente de multiples intérêts :
Pour bien commencer, Sonatype fournit un guide très complet sur l’installation et l’usage de Nexus : Repository Management with Nexus. Bien entendu, vous pouvez également vous tourner vers Apache Archiva ou encore Artifactory pour répondre aux mêmes besoins.
Pour améliorer la maintenabilité des pom.xml, il est utile d’avoir sous les yeux les dépendances sur lesquelles vous vous appuyez. Derrière ce conseil qui parait évident se cache un risque d’erreur non négligeable.
Si vous déclarez ces dépendances :
<dependencies> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>0.9.15</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>2.5.6</version> </dependency> </dependencies>
le mécanisme de gestion des dépendances transitives de Maven (merci à lui) vous fournira toutes celles ci :

On pourrait s’arrêter là. Cependant, à ce stade, notre pom.xml ne permet pas de se rendre bien compte des librairies sur lesquelles nous nous appuyons réellement. Dans l’exemple ci-dessus, il est possible que du code de notre projet lance des appels directement sur spring-core. Cela ne pose pas de problèmes ni à la compilation, ni au build, mais, pour pouvoir gagner en lisibilité sur notre pom.xml, Maven nous a gratifié d’un plugin très utile : dependency:analyze, qui va lister toutes les librairies qui sont des dépendances directes pour notre projet.
$ mvn dependency:analyze ... [INFO] [dependency:analyze] [WARNING] Used undeclared dependencies found: [WARNING] org.slf4j:slf4j-api:jar:1.5.6:compile [WARNING] org.springframework:spring-core:jar:2.5.6:compile [WARNING] Unused declared dependencies found: [WARNING] ch.qos.logback:logback-classic:jar:0.9.15:compile [WARNING] ch.qos.logback:logback-core:jar:0.9.15:compile
Les Used undeclared dependencies sont toutes les dépendances que nous pouvons ajouter à notre pom.xml pour en améliorer sa lecture et donc sa maintenabilité. Faites attention cependant, car ces dépendances sont des dépendances à la compilation. Les librairies listées dans les Unused declared dependencies peuvent très bien être des dépendances au runtime, auquel cas elles doivent rester en place.
Je vous recommande d’utiliser autant de propriétés que possible dans le pom.xml. Par exemple, n’hésitez pas une seconde entre ce pom:
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>0.9.15</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>2.5.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>2.5.6</version>
</dependency>
</dependencies>
et celui là:
<properties>
<logback.version>0.9.15</logback.version>
<spring.version>2.5.6</spring.version>
</properties>
<!-- ... -->
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
La deuxième version vous permettra de placer toutes vos propriétés en évidence en haut de votre fichier pom.xml et ainsi d’avoir en un rien de temps, sous les yeux, toutes les versions de vos dépendances. Encore une fois, l’objectif est ici de gagner du temps dans la manipulation de vos fichiers. Comme en code Java, il est toujours préférable de gérer une variable et d’en changer la valeur, que d’aller modifier tous les paramètres constants qui traîneraient dans le code.
Il est courant d’avoir des opérations différentes à faire selon la machine sur laquelle on souhaite construire ou installer un projet. En effet, des informations telles que :
diffèrent selon l’environnement (machine de dev, serveur de qualification, de pré-prod, etc.). Pour répondre à ce besoin, Maven propose d’utiliser le mécanisme de profil de build. Ne vous en privez pas.
A l’intérieur d’un profil, vous pouvez surcharger les propriétés que vous injectez dans les fichiers properties, les plugins associés aux phases de build, les rapports à générer… Bref, pratiquement tout ce que vous pouvez inscrire dans un pom.xml est surchargeable dans un profil.
On peut activer les profils souhaités en utilisant l’option -P du binaire mvn :
mvn clean package -P monProfileTest,monProfilDev,monProfilReportingVerbeux
En complément, les profils Maven peuvent être configurés pour une activation automatique en fonction d’un ou de plusieurs paramètres tels que :
Si vous utilisez ce genre d’activation automatique, il est toujours utile de se souvenir de l’existence de certains plugins fournis :
Vaut-il mieux faire un projet avec des modules ou faire des projets séparés interdépendants ? Cette question est certainement une des plus génératrice de débat. Il n’existe pas de règle à proprement parler, cela dépend surtout de l’utilisation que vous comptez avoir de vos morceaux de code. Il est tout à fait possible d’appliquer une séparation de responsabilité stricte du genre :
Si on souhaite avoir de multiples implémentations de nos couches business et dao, on peut pousser encore le découpage en créant des projets contenant uniquement les interfaces et spécifier dans nos pom.xml l’implémentation qui nous intéresse. Cela nous donnerait quelque chose du genre :
A moins que nous n’ayons que peu de réutilisation dans d’autres équipes et qu’il faille juste ranger un peu notre code pour avoir des tests unitaires jouables sur chaque couche. On pourrait alors se contenter d’un projet avec un sous-module par couche.
La philosophie du KISS devrait vous éviter de verser dans des extrêmes inconfortables. Le point à retenir ici est de toujours prendre un temps de réflexion pour ce découpage, il est très structurant. En changer en cours de projet prend du temps pour éviter les régressions et les pertes de code.
Vous trouverez sans aucun doute sur le net beaucoup de conseils tournant autour du fichier settings.xml ou du fameux Super-POM. Ces fichiers font partie de l’installation de Maven sur votre poste local. Je trouve qu’il est dangereux de s’appuyer dessus, dans la mesure où ces fichiers ne sont, par définition, pas intégrés à votre gestionnaire de sources. Par conséquent rien ne garanti leur versionnage d’une machine développeur à une autre, et cela peut entraîner des comportement inattendus.
De plus, tout ce qu’on pourrait y mettre peut être glissé dans le fichier pom.xml de votre projet. Mon conseil donc : évitez-les.
Si par hasard vous étiez obligé de vous en servir, lors de l’écriture de vos pom.xml, souvenez vous bien qu’aucun héritage ne permet d’écraser la valeur d’une propriété définie dans le fichier settings.xml. S’il est présent et contient des directives, il aura raison.
Il faut se souvenir que Maven est, avant tout, une machine à lancer des plugins. Il fournit certes un cadre d’exécution axé sur les builds de projet mais nous pouvons y ajouter les plugins qui nous plaisent sur n’importe quelle phase de build. Le développement de plugin est relativement bien documenté et nous permet d’ajouter des fonctionnalités à l’infini.
Si, en plus, vous avez suivi le premier conseil de cet article, vous pourrez déployer vos plugins sur le repository de votre réseau local et ainsi étendre facilement l’utilisation de vos plugins à travers vos équipes et vos projets.
Nous n’avons vu ici que l’essentiel des pratiques permettant de mieux vivre son expérience Maven. Il existe beaucoup de bonnes pratiques et il est rarement possible de toutes les appliquer en même temps tellement cet outil est flexible. La meilleur méthode est sûrement de bien réfléchir à votre environnement, vos besoins, et à votre utilisation des projets que vous gérez. Une fois ceci fait, vous pourrez édicter vos propres bonnes pratiques, et les faire connaître et appliquer à vos équipes de développement sur le long terme.
Pour approfondir :
Article printed from Blog Xebia France: http://blog.xebia.fr
URL to article: http://blog.xebia.fr/2009/04/30/maximum-maven/
Click here to print.