Friday, October 30, 2009

Converting to the Ultimate Java Build Stack

Over the past 6 months, I've had the pleasure and pain of working with Maven. Even with all of the pain, I've found myself a fan of the technology, assuming, of course, that you have the appropriate Maven stack set up.

During my time at the client, I setup Hudson, Nexus, and Sonar as outlined in Christopher Judd's blog post. We had actually already decided upon Hudson and Nexus through discovery before Judd published his post. Sonar was a nice discovery we added to the mix a bit later. Having setup this stack, I thought I'd offer some thoughts on my experiences.

I cannot stress how important having Nexus (or Artifactory) is to keeping your Maven projects running smoothly and effectively. Having a repository management tool and proxy allows for all of your developers (and Hudsons) to simply point at the proxy and download everything required for a build quickly. It also provides a place for you to host your third party jars from apps that have been purchased by your organization. Not everything is open source of course.

The steps are simple enough, install Nexus and setup your settings.xml file to point to it. For developers, they can use their own settings.xml file. For Hudson, you may want to modify the settings.xml in your Maven install (especially if you're running on Windows). You might need to add a mirror for's Maven 2 repository. You might not. It depends upon how up to date Maven's central repository is.

Sonar was a nice surprise. Providing PMD, Checkstyle and Cobertura results in a nice visual manner that allowed for quick feedback was surprisingly effective. As a developer, I found it to be my favorite part of the switch to Maven. Sure, Maven provides this information as part of its site goal, however, it doesn't present it like this.

Obviously there are huge gains to be made by integrating Hudson and getting it to build upon version control commits, but I found more intriguing was its ability to trigger downstream builds. When I built the commons library for the app, every maven artifact that used the commons library was triggered for build. Numerous times, I discovered that I or someone else had broken something in a downstream library due to an API fix. That instant feedback (through RSS feeds) was an invaluable time saver.

What about Maven itself? What does it gain you? In the case I was working on, tremendous build granularity. The original build used Ant, and was built in a monolithic manner. Each component was built by the single script and bundled together. One could argue it wasn't the best ant script in the world, and they'd be right. Maven allowed us to break these dependencies apart. So now, instead of having one monolithic code base which included what were really five separate artifacts, we now had five separate projects, each self contained using dependencies to draw in the needed artifacts. As such the WAR and EAR builds ended up being very simple where they just drew in their needed dependencies and just worked.

Additionally, Maven offered unit testing at a very cheap cost. The initial code base had no unit testing. The developers were keen to use the debugger to test scenarios, which is needed to understand the mass amounts of reflection which were in use. However, that's only helpful in understanding the code. There should have been unit tests which were stood up to test each component on its own. Maven automagically gives you unit testing with the surefire plugin enabled by default. Make sure JUnit is a test dependency and start writing tests into the test source tree. Keep your tests in the same package as your code and start gaining coverage. In between adding new features to the code base, I was able to increase code coverage on the base level components from 0 to 40%. Obviously there's still a long way to go, but this was a vast improvement!

One thing I will note about Maven is the tooling. There is tremendous tooling available in the m2eclipse plugin for Eclipse. Netbeans 6.5 and above opens Maven projects without needing to do much of anything. It just opens the directory containing the pom and imports the project. If you're moving to Maven, make sure that your development tools can support it. As an example, RAD 7.0.x is Eclipse 3.2. As such the m2eclipse plugin does not work for it. If you must use RAD 7.0.x, I would advise building your project outside of RAD. Use a more up to date IDE to get the projects started and structures built. Then use the maven-eclipse-plugin to build the proper project eclipse artifacts for your projects. It will still be a challenge to build proper EAR and WAR projects for RAD. Maven has a lot of help for this sort of pain. However it can only be applied if you use the proper tools.

I've got a bit more to say about Maven, especially with my experiences of converting projects to Maven, the various pain and joy points I experienced and overall satisfaction. But I'll leave that for another post. Until then, I strongly suggest that if you have new development and you are looking for a pure Java based project build management tool, that you should take a long hard look at Maven.