Search This Blog

Sunday 23 September 2012

Managing module dependency versions with Maven

When building a complex application with Maven it is normal to split the code among multiple projects. Every project has its own pom file and we use a parent pom file to build all projects in the process generating our final build or deployment artifact. The problem observed is that the different projects have their own dependencies.
So for example a certain project that includes the data access code will need reference to an ORM jar while an utility project will need reference to encryption libraries or mail libraries. Then there are the common jars that are needed in most projects. These could be logging related or certain utility jars etc. As the dependencies need to be resolved for every project, we add suitable entries in our pom files.Consider the commons library jars:
<dependency>
    <groupId>commons-lang</groupId>
    <artifactId>commons-lang</artifactId>
    <version>2.6</version>
</dependency>
This dependency could finds its way into several pom files. If we are using a framework like Spring, then its varied jars are needed in different projects. Jars like spring-core on the other hand will be needed in almost all the projects. So there is a lot of dependency floating across multiple pom files.
This leads to headaches when there is a need to identify the different dependencies. Also ensuring the same version is used is difficult. For e.g. a developer could add the commons-lang dependency in two child poms for two different versions. Or simply put, if we need to change the version of a particular jar throughout the project we will have to do it in multiple pom files.
You have probably guessed by now that most of the above issues are rooted in the occurrence of the version element. As the version element is spread across multiple pom files it opens up bad possibilities in dependency management. Maven has a very nice solution for this, one which I came across here - The trick is to let the child poms decide what jars they need. The parent pom on the other hand decides the versions for any jars used  in the project. So even if multiple poms specify the same commons-lang jar , its version will be declared in the parent pom. So managing the version is now controlled from one pom file only.
This can be achieved by using the <dependencymanagement> element. The child pom would look like this:
<dependencies>
    <dependency>
        <groupid>commons-lang</groupid>
        <artifactid>commons-lang</artifactid>
    </dependency>
 </dependencies>
The parent pom on the other hand would include this fragment:
<dependencymanagement>
    <dependencies>
        <dependency>
            <groupid>commons-lang</groupid>
            <artifactid>commons-lang</artifactid>
            <version>2.6</version>
        </dependency>
     </dependencies>
<dependencymanagement>
The version element is only in the parent pom now. At build time, Maven will look here to resolve the dependencies for all the child projects.
This can be further improved by specifying the version using a property element. This is especially useful for Spring which has multiple jars as a part of the same release. (They have the same group id differing only in artifact-id) A single property change will be enough now to move the code-base to a different version of Spring. 
 I really liked this centralized management of dependencies and the single point control obtained thus. Only concern I had is that, enforcing this practice is manual. As in each developer needs to be educated about this practice. If some one accidentally slips in a version in the child pom, that jar will be loaded by Maven. It would be cool if there was like a central switch to prevent Maven from entertaining version elements set in child pom. What do you think?

No comments:

Post a Comment