Friday, March 2, 2012

How to integrate Maven in your current project

I am not going to discuss which are the best build tools available out there, this article could be entitled as well How to integrate Gradle on your current project since both tools have overlapping features. If you have already decided to switch to an automated build tool, this article and the following ones are going to help you with this tedious task.

The methodology

First let's talk about the methodology: What do we need to know before drafting our integration road map? To move the mind of old school developers into such a big change and to make them feel comfortable with Maven conventions is not an easy task. I'm starting with some really basic advices and we'll go deep into the subject on future articles:
  1. Learn and study the existing build system, the deepest part of it: How the application and the existing modules are built? You have to know the deploying paradigm of the project, how do developers integrate it to their IDE, your repository layout and (most likely) how you deal with your current jar hell. It's also important to have a metric on the current target quality level of the runtime classpath in your application.
  2. Move gradually to the goal, try not to break the existing process. It's important that the rest of the team can continue working while the changes are ongoing.
  3. Remember this is a long run goal, a step by step conversion. If you have a sprint release system you probably won't move the whole system directly to Maven. Write down the detailed road map and go one step at a time till you have a fully functional Maven build that all the developers are willing to use.
  4. Do not focus on just one part of the problem. Do a wide analysis over the current process: deploy, development, containers running... Try to see the current bad habits developers are running into.
  5. Be prepared to do sacrifices and builds that aren't purely the way Maven builds are supposed to be. For example.: In my current application we generate both a WAR and a JAR built for every project: The WAR built is used for running the application against a production environment, while the JAR is used to solve dependencies between the project. I'm not okay with it but intermediate steps and dirty Maven tricks are necessary to keep the old school developer happy.
  6. Use candy features to get developers involved: automatic integration with SonarSource, Jenkins, etc. Think of anything else you can integrate that eases development. It's important to emphasize separation of concern between building and developing; Explain what JRebel and WTP are for and how they can help optimizing your current work cycle. That's what Maven is about: you want to write more code and less configuration stuff.

A road map draft

Let's give a quick view on the road map we are going to follow to switch to an automated build system. Be aware that this is not a simple task, but no matter how frustrating it looks, if you take the first step you have to keep going forward:
  1. Changes in your current repository system: You must likely are going to face some changes in order to make your repository system Maven compliant. Update the current directory layout at this point and remove any dependencies with the preferred IDE if you have them. For more details on the standard layout, see the following Maven guide: Introduction to the standard directory layout.
  2. Analyze your current lib folder to generate all the dependencies into each projects POM. Do an output analysis to be sure you are using the same classpath you were using. Resolve any conflict at this point on both the old builds and the ones you are crafting. Start with the root projects and continue to the leaf ones. At the end you should be able to produce the same artifacts with both the new build system and the old one.
  3. Create a parent project to normalize all the dependencies you found across all the projects. This will help you keep one version of one dependency for all your projects. Upgrade jars in the current build if it's necessary and refactor your code accordingly. You might find some rare cases at this point: projects using overlapping dependencies with different versions. Try to see this point as inheritance problem in object design, after all your projects must obey a command hierarchy.
  4. If you are using SVN it's worth mentioning that at this point you can also embrace the recommended repository layout and fix those convention Maven imposes over your SCM. You can check this layout here : Recommended Repository Layout.
  5. Create an aggregator project. This aggregation will help you compose projects that should compile and work together. This point is specially useful if the preferred IDE is Eclipse, it will help you link your project in Eclipse and have WTP understanding of your project; easy server deployment and drag and drop features. Do not forget about the command line users, give them a fast way to run the deployed artifacts, Check out the Tomcat Maven plugin as a proof of concept.
  6. Consider linking your brand new build system to other useful applications: Integrate Jenkins to easily deploy your artifacts into the whole system, integrate SonarSource to give a dashboard, enforce unit testing and code coverage tools, integrate Cargo to automatically deploy a successful build to a QA environment.
  7. Do a showcase of your new build system, encourage developers to embrace it: See point #6 in methodology.

One more note

I'm also publishing articles about versioning and release problematic as well as branching strategies. I'm thinking of showcasing the current branching problematic we have at Nuroa and Migoa: how we moved from our old build system (Ant) to the new one (a mix of Gradle and Maven). I would also like to take the time to talk about the benefit of Jenkins jobs integrated into the work cycle in QA and production environments.

I promise I won't forget about more technical details on automatic build systems!

Posted by , Software Engineer.


  1. A really nice an encourging article, at my current project we’r dealing with an inherited “jar hell” project with such “features” as:
    • Unmatained ant builds.
    • Multiple artifacts for each project: jars, war, even an ear.
    • Half-mavenized projects with broken depend√®ncies and custom folder layouts.
    I went throught some mavenitzation which more or less followed your methodology from 1 to 5, it is the natural way. Right now we use Eclipse with m2eclipse to be able to manage dependencies and local development (war deployment in Tomcat), and the old ants to build the final artifacts (ear, war and ejbs).
    As you comment, to avoid interrupting others work, I add changes gradually. From time to time I experiment and add some changes to move ahead into a total maven build, but the final steps requiere heavy refactoring which we cannot afford :/
    About the roadmap I have used steps 1,2,3, 5, 7 (specially 7) in all the project we had a chance. Intalling CI env is out of the plan :/
    The last steps taken have been installing a SonatypeNexus intance in our development environemnt which I am introducing to developers.

    Looking forward for a graddle artice , or a Groovy-maven-eclipse integration :P

    PD: wtf do u mean by “It's also important to have a metric on the current target quality level of the runtime classpath in your application.”

    1. implementing step 6 with jenkins can be 30 minutes on you developer machine. java -jar jenkins.war (plus download time)

      You can start playing around get familiar warn people when the build has broken. Other members of the team will quickly see the advantages.

      jenkins is extremely light weight and can be run on any old recycled computer.

  2. Well, the important things known as target quality level of runtime classpath is mainly "Do they strictly care of versions and want classpath to have exactly what they decided" or "It's working thanks to luck...".

  3. Right now I'm following this procedure on the crawler project we have at Nuroa, so far I'm in between step 2 and 3 of the roadmap (I have to deal with both at the same cause we already have a parent project that normalizes versions across all projects) and I have to say this article is being a great reference for the task.

    Thanks Alexis.