Wednesday, July 14, 2010

Some useful Maven configurations, practices and lessons learnt

After using Maven for a while, my colleagues and I have configured a couple useful things and learnt a few lessons.

Edit: as per comments
Local Repository Managers
On the maven site here: Repository Management there is a brief description of the major repo managers out there
and a very good breakdown on why they are a good idea. We had a couple issues with Artifactory, (this was a couple years back) and in the end went with Nexus, which has proven to be very stable and offers all we need.

Parent POMs
Define common things, like versions, compiler settings, reporting settings and common build plugins in a parent POM to allow this configuration to be used throughout the applications' components and sub projects. If you have multiple projects with different requirements you can create another layer of Parent. To give an example, we had a legacy project, and the new re-write. For the legacy system we could not enforce checkstyle or code coverage but we did want to enforce it for the new project. So we created a base parent pom that had some general configuration and version numbers in it and then another parent pom for the new system that had the base parent as it's parent and then all the specific code coverage and style checks.

Versioning(See update at end of post)
In a parent POM define variables for all out internal component versions, so that you would have 1 central place to change release versions / snapshots etc.
We didn't include the versions of common 3rd party libraries like Spring, The Apache commons projects, JUnit etc, which in hindsight was a mistake. This is now really quite a pain 3 years and 30ish POMs down the line when trying to upgrade a specific library, and invariably one gets missed and then you have 2 / 3 versions of Spring or Hibernate sneaking into the dependencies.

Parent POM:


Project POM:


Compiler Settings
Just to ensure that it is the same accross all the projects using the parent.


Common Build Settings
1.
Unit Testing
Actually running and reporting on the unit tests and results.
1.a. In the report plugin I have included command line arguments to increase the VM size, we found that on our large projects with tons of unit tests it did occasionally ran out of memory.
1.b. In the build plugin, there is a "parallel" config, that i recently saw in John Smarts blog, that allows you to run the test classes concurrently.
2. Cobertura Code Coverge, This is great way to ensure that there are atleast a certian amount of test cases and that code is being run.
It unfortunately can't check the validility of the test cases so developers will be developers and code "useless" tests just to pass the coverage requirement, but it is still worth putting the plugin in, and "useless" tests can be caught with code reviews.

1. Surefire - Running and Reporting



2. Cobertura Code Coverage
We found that in our predetermined deadline environment going for more that 50% coverage really extended the development time and effort for components more than we could afford. There were a couple smaller components that off the bat had 80%+, but we couldn't enforce it on all due to the time constraints.We are now slowly increasing that percentage when ever there is new work on a component but that is also quite a slow and painful process.
The "totalLineRate" is the setting that determines the coverage % required.




Checkstyle
We defined our basic coding standards within Checkstyle, and to ensure that they are followed we would fail the build if the code doesn't comply. I have also snuck in the "taglist-maven-plugin" plugin under this topic as it was a pet peeve on one of the developers, and with it in the reporting section it will show up when using 'mvn site'.




Profiles
One of our .EARs needed to be deployed on both Glassfish and Weblogic and there were unfortunate compatibility issues between the 2 so we couldn't actually deploy the same ear.
We configured that specific POM with 2 profiles. The Weblogic on was set to be the default, and when we required a new deployment onto Glassfish we would run maven with -Dglassfish-build=true.



Edit 2: Dependency Management and Versioning
Again, thanks to the people that commented. I am always happy to learn something new. So a couple people pointed out that I completely missed this. When writing this I based it on personal and team experiences and we somehow missed this section of the maven docs. I state in "Versioning" it is now a bit of a pain in our lives, so to help out others, below is the link to how Maven says you should handle dependencies.

Dependency Management

10 comments:

  1. Brian, good article. A couple of points I would add here:

    1. Making use of the Maven release plugin. Invaluable taking care of your branching, tagging, releasing and deploying artifacts without the schlep.

    2. Switch off checkstyle, cobertura and surefire - use Sonar instead.

    3. Use a local repository, preferably managed by Nexus or Artifactory.

    ReplyDelete
  2. Thanks,
    1. I haven't looked at the release plugin... we are just building off promotion states and deploying from hudson scripts... I know there is a drive now again for a central deploy team, I am sure we'll look into that then.

    2. I know someone looked at Sonar, not sure what happened to it, I think we had "corporate bandwidth and rights issues", i.e couldn't download what we needed... I remember it looked cool, completely forgot about it when writing this though...

    3. Yeah we use Nexus, Artifactory caused Joe endless hassles... local repo's a must... I'll add that in if I have time tomorrow..

    ReplyDelete
  3. Thanks. Some comments:

    1. When using parent POM, I always use relativePath=../pom.xml in child POM. That will help me to avoid installing parent POM before building the source tree

    2. About controlling dependency versions from parent POM, there is another way using dependencyManagement

    3. Using profile: I often define a profile A using !env property, and another profile B using env=B (similar if you have more profiles). In this way, I can build "mvn package" and profile A will be used. When I using "mvn package -Denv=B", profile B will be used instead of profile A.

    ReplyDelete
  4. Your past Artifactory experience dates a few of years back - I think your experience today will be much different. For us, it is extremely fast and stable (we actually switched from Nexus for the slow searches and too many random not-found under heavy load). I also came to rely on the nice integration of Artifactory with Hudson.

    ReplyDelete
  5. Thanks a lot for your informative article.

    One important point that Thai Ha already mentioned:

    dependencyManagement ist the "correct" way to manage versions:

    http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Management

    ReplyDelete
  6. Hi !

    Just a warning : using activeByDefault in your weblogic-ear profile could lead to bad behaviour.
    The activeByDefault means "active if no other profile has been explicitely activated".

    That is to say if, for some reason, you put a new profile (for example, in your super pom, allowing to unleash some reporting-only behaviour when activated) and activate in in CLI mode (example : "mvn -P reporting clean install"), your weblogic-ear will then not be activated !

    Prefer to use the section to define profiles by default there !

    ReplyDelete
  7. *Prefer to use the "activeProfiles" section to define profiles by default there !

    (tags are not imterpreted here)

    ReplyDelete
  8. @Gromo, yeah I suspected that it would not be the case any more, thanks though, good to know if Nexus gets us down there is a good alternative.

    @Simon/Thai I just quickly scanned over the link you posted... damn, how did we miss that??... I will add a section onto the post at the end describing dependency management, that is a lot neater. Thanks

    @Atma/fcamblor I actually didn't know that, just lucky that we didn't run into that I guess, good to know.

    ReplyDelete
  9. this is a very interesting article, but it led me to what i now consider as a big mistake: what's the point in defining the version of a project in its parent?

    i thought it would be convenient to handle versions in only one file, but if another project depends on one of our children projects, that means it is necessary to have both the child and parent projects delivered, which means that the version of the parent has to be handled as well, and that implies changes in all pom files!

    ...or is there some important point i missed?

    ReplyDelete
  10. @Sylain, yeah I missed the versioning bit too...

    In a previous comment Simon Martinelli added a link to how it is supposed to be done "Dependency Management":
    http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Management

    ReplyDelete

Popular Posts

Followers