tags:

views:

66

answers:

2

My project is made of 5 sub projects. One is a War, and the other 4 are jars. Basically the war project needs all 4 jar projects, and their dependencies.

I can strip down the dependencies to have something like war->A->B->C->D. Every sub project add their share of external dependencies (spring, struts, hibernate) so that in the end the war gets everything needed to run.

This looks pretty well organised and square, but then I ask myself if this is very practical to make changes.

Imagine I have to change one line of code in project D, without changing anything to its Maven dependencies. I would have to re-release project D obviously, but then I have to re-release projects C, B, A, and the war just to reflect this change in their pom files. This can be long and annoying, especially if you have to quickly release a new version to fix something in production.

I could make the war depend on all 4 projects, so then I just have to change project D version number in the war pom file. But then I have project A depending indirectly on project D 1.0 and the war specifying project D 1.1. I think that the war direct dependency would win in that case wouldn't it ?

This would make the new war release quicker, but it would also mess my sub projects dependencies, as they would be outdated.

What would be an acceptable way to handle this situation ?

+1  A: 

Do you actually release any of projects A to D independently, without the WAR? If not, I don't see any problems with your current setup. You should absolutely use the same version of any module throughout the project. Otherwise you open the door to classloader hell - believe me, you don't want to get there :-(

To make releases easier, the maven-release-plugin may help you.

Péter Török
Hi Péter. Projects A to D are specific to the WAR, but I have to release them individually so that other developers can build the WAR and Maven release plugin finds the dependencies. Maybe these releases are not necessary ?
IceGras
@IceGras, bumping up the version number every time you make a change may be overkill indeed. In our project, we are happy with SNAPSHOT versions during development time, and we create a new concrete version only for official release (candidate)s.
Péter Török
Working with snapshots during development time seems the best solution indeed, but then I have this question: If you release RC1 with all modules in version 1.0, and you just need to change module C. If you release RC2 all the other projects will increment version for nothing then ? Also my main worry is about production change. If my release needs to be changed I will have to bump all versions number to transitively reflect the change.
IceGras
@IceGras, yes, if you have really frequent releases/patches, this can be inconvenient (although the maven-release-plugin does make it easier to update versions).
Péter Török
+2  A: 

There is no simple answer to your problem.

If you indeed do have a chain of transitive dependencies (A->B->C->D), then releasing each modules up the chain independently is not a bad option. Although it is tedious, there is a good chance your nested dependencies are simple lib jars and will not see changes too often. Hopefully you will not be forced to go through that process frequently. Pretend it would be the same situation as if log4j was updated and all of your modules needed to be updated as well.

Another thing to consider is your WAR's dependencies. Yes, Maven will pull dependencies in automatically for you but it is often a good practice to declare your known dependencies explicitly so you can specify a version number yourself for each module. This would mean A depends on D and the others directly. Unfortunately, if you have conflicting version numbers, as you've described, then you are looking for trouble on your classpath. If you really need to do this though, maven does allow you exclude transitive dependencies explicitly:

<project>
  ...
  <dependencies>
    <dependency>
      <groupId>my.project</groupId>
      <artifactId>module-B</artifactId>
      <version>1.0</version>
      <exclusions>
        <exclusion>
          <groupId>my.project</groupId>
          <artifactId>module-C</artifactId>
        </exclusion>
        <exclusion>
          <groupId>my.project</groupId>
          <artifactId>module-D</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>my.project</groupId>
      <artifactId>module-C</artifactId>
      <version>1.0</version>
      <exclusions>
        <exclusion>
          <groupId>my.project</groupId>
          <artifactId>module-D</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>my.project</groupId>
      <artifactId>module-D</artifactId>
      <version>1.0</version>
    </dependency>
  </dependencies>
  ...
</project>

Here is the documentation describing these optional dependencies and exclusions.

Do you actually need to release B, C, and D independently? If not, consider using an Aggregator pom.xml file at the root of your modules. This will allow you to use SNAPSHOT versions throughout your modules and then release the bunch at once. This is the way our team manages our multi-module project. Using SNAPSHOT dependencies ensures you use the version that was JUST built when those artifacts are needed.

Gweebz
hi Gweebz. Thanks for the detailed reply. I do not need to have every sub project released individually, so I will give a good look to this aggregator concept I didn't know about. The modules containt all business and data code, and are bound to change regularly. Another solution would be to exclude the transitive dependencies as you said, I didn't think about that. Thanks for the light on this.
IceGras
With no requirement to release every module independently, I strongly suggest to use the Aggregator solution. It's pattern is the perfect fit for your scenario. Glad I could help :)
Gweebz