Publié par

Il y a 11 ans -

Temps de lecture 2 minutes

Maximum Maven

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.

Utilisez un artifact repository

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 :

  • Accélérer le téléchargement des dépendances : grâce au proxy-cache.
  • Maitriser les dépendances accessibles aux développeurs : on peut appliquer sur le proxy des politiques d’accès aux dépendances et ainsi les restreindre finement. Une règle serait, par exemple, d’interdire de dépendre d’un quelconque morceau de code licencié GPL, pour éviter la contamination de votre projet.
  • Déployer et rendre disponibles nos propres artefacts à nos équipes : en bout de chaine d’intégration continue, en déployant les artifacts sur le repository, on peut faire reposer des projets annexes sur des versions maitrisées de nos librairies.
  • Centraliser la gestion des repositories sur lesquels on s’appuie : dans l’administration de Nexus, on ne gère plus que la liste des repositories chez qui on récupère nos dépendances et on évite de polluer nos pom.xml avec ces considérations.

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.

Déclarez toutes vos dépendances directes

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 :

 
	  
	 ch.qos.logback 
	 	 logback-classic 
	 	 0.9.15 
	  
	  
	 	 org.springframework 
	 	 spring-jdbc 
	 	 2.5.6 
	  

le mécanisme de gestion des dépendances transitives de Maven (merci à lui) vous fournira toutes celles ci :

Dépendances transitives

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.

Utilisez des propriétés partout où cela est possible

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:



  
    ch.qos.logback
    logback-classic
    0.9.15
  

  
    org.springframework
    spring-jdbc
    2.5.6
  

  
    org.springframework
    spring-core
    2.5.6
  


et celui là:


  0.9.15
  2.5.6






  
    ch.qos.logback
    logback-classic
    ${logback.version}
  

  
    org.springframework
    spring-jdbc
    ${spring.version}
  

  
    org.springframework
    spring-core
    ${spring.version}
  


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.

Utilisez les profils

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 :

  • l’adresse d’un serveur de base de données
  • le niveau de log a utiliser
  • le reporting à générer lors du build

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 :

  • la version du JDK détectée
  • la présence ou l’absence d’un fichier dans l’arborescence du projet
  • le type et/ou la version du système
  • l’architecture du processeur
  • la valeur d’une propriété présente dans le pom.xml

Si vous utilisez ce genre d’activation automatique, il est toujours utile de se souvenir de l’existence de certains plugins fournis :

  • help:active-profiles : vous donne la liste des profils actifs pour votre configuration.
  • help:effective-pom : effectue la consolidation de la hiérarchie des pom.xml dans le cas d’héritage ou de modules, et vous affiche le pom.xml résultant. C’est ce pom.xml consolidé qui est utilisé par le binaire mvn lorsqu’on lance un build.

Réfléchissez bien au découpage de vos artefacts

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 :

  • un projet GUI, par exemple application web
  • … qui dépend d’un projet couche business
  • … qui dépend d’un projet couche dao
  • … qui dépend d’un projet model

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 :

  • un projet application web
  • … qui dépend d’un projet couche business impl, lui-même dépendant d’un projet couche business api
  • … qui dépend d’un projet couche dao impl, etc.

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.

Evitez de vous appuyer sur les préférences locales

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.

Osez écrire des plugins

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.

Pour conclure

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 :

Publié par

Publié par Aurélien Maury

Aurélien est passionné par les frameworks web haute productivité comme Grails, JRuby on Rails ou Play! framework. Il est également intéressé par tous les aspects de performance et d'optimisation (mais aussi par la phytothérapie, la PNL, la basse électrique, la philosophie et pleins d'autres sujets). Il est également formateur au sein de Xebia Training .

Commentaire

7 réponses pour " Maximum Maven "

  1. Publié par , Il y a 11 ans

    Nexus peut être le premier « Artifact repository » que l’on peut rencontrer car il est proposé par Sonatype qui publie notamment « maven the definitive guide » qui reste à mon sens le document le plus complet sur Maven. Cependant il n’est pas le seul… Je pense qu’une petite étude comparative serait la bienvenue (un contest xebia :)) Au banc des challengers on pourrait mettre PROXIMITY (http://proximity.abstracthorizon.org/) ou ARTIFACTORY (http://www.jfrog.org/products.php)

    Sans rien prétendre je rajouterais que l’utilisation des balises dans un pom PARENT par exemple permet de fixer la version d’une dépendance pour tout le projet…. (redondant si l’on a mit un repository efficace qui n’autorise le téléchargement que des versions cibles mais c’est asez long à configurer pour chaque composant.

  2. Publié par , Il y a 11 ans

    errata : des balises… <dependencyManagement> dans un pom PARENT…

  3. Publié par , Il y a 11 ans

    Effectivement l’utilisation du dependencyManagement est une bonne pratique. On peut de plus le partager entre différents projets via le scope import. On peut aussi noter comme bonne pratique l’utilisation du que l’on peut en général aussi partager entre différents projets via un pom parent commun. La liste est encore longue et comme l’a dit Aurélien il sera difficile d’être exhaustif (cela lui laisse de bons articles à faire).
    Concernant les repositories, Proximity est aujourd’hui remplacé par Nexus : http://nexus.sonatype.org/about/history.html. Archiva est très à la traîne (c’est triste de l’avouer quand on fait partie de l’équipe) et si j’ai l’accord de mon client je vous raconterai très bientôt notre migration Archiva -> Nexus. Le deux gros compétiteurs sont donc aujourd’hui Nexus et Artifactory.

  4. Publié par , Il y a 11 ans

    En réalité, Nexus a été lancé en 2007 par Sonatype, en contactant Tamas Cservenak, le développeur principal de Proximity (lancé en 2005). La version Proximity 2 est en fait Nexus, puisque la quasi totalité des sources de Proximity ont été absorbées par Nexus [Source]. Quant à Artifactory, je l’ai bien sûr listé dans les challengers, mais pour ne l’avoir jamais utilisé, je n’ai pas trop détaillé cet outil.

    Quant aux balises je ne peux qu’être d’accord avec vous. Car même avec un repository efficace, cela permet également d’économiser beaucoup de lignes dans les pom des modules.

  5. Publié par , Il y a 11 ans

    A propos de dependencyManagement, on utilise en parallel le plugin « enforcer » qui nous permet d’ecrire en dur des regles globales sur les dependances. Par example:
    – Tout plugin doit avoir une version
    – Utiliser les jar Spring et jamais le jar aggregateur
    – ne jamais utiliser cglib
    – …

    Vous pouvez regarder l’example dans le parent POM d’Artifactory http://subversion.jfrog.org/artifactory/public/trunk/pom.xml le plugin « maven-enforcer-plugin ».

    Faisant parti de l’equipe d’Artifactory, notre impression du marche confirme les commentaires precedents: Archiva perd du terrain, Nexus et Artifactory sont les deux principaux produits du marche.

    A vous de comparer!

  6. Publié par , Il y a 11 ans

    Voici quelques liens intéressants. Nexus et Artifactory se confrontent eux-même et se répondent à travers les posts suivants.

    Sonatype présente son produit ou plutôt les pseudo « points faibles de son concurrent » en finissant par mettre en avant sa solution professionnelle :
    http://www.sonatype.com/people/2009/01/contrasting-nexus-and-artifactory/

    Artifactory se défend (ce billet est une réponse directe) :
    http://blogs.jfrog.org/2009/01/contrasting-artifactory-and-nexus.html

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Nous recrutons

Être un Sapient, c'est faire partie d'un groupe de passionnés ; C'est l'opportunité de travailler et de partager avec des pairs parmi les plus talentueux.