Maven, Ant, Ant Builder, Gant, and the hand that rocks the Gradle


Developing software is an iterative process that begins and ends with a build system. Over the years I’ve learned that such a system can make or break a project. As such I’ve become very anal about the build process because IT is what it takes to complete a development cycle and the development cycle is what drives the direction of software. If the cycle is too long developers take or create shortcuts. If the cycle is too complicated requiring too many steps or too much setup, developers make critical mistakes which lead to the creation of imaginary-required safegaurds. These shortcuts and safegaurds make their way into the core of your software creating baggage and removing features while adding no functionality. So the build system is very important to the overall health of your project.

In Java land there has long been the world renowned Ant project. Something that started as a simple hack but became an ecosystem of good ideas. Years later another project, Maven started as an attempt to standardize on these good ideas. The Maven project recognized one important thing… all of these Ant based projects were doing the same thing, building software. It was early in its time and had some rough spots so then the Maven2 project was born. I’m not going into the history of Ant and Maven, instead I want to focus on what I feel is the most important goal. While there may be more than one way why does there have to exist so many right ways? Look at the title above. See all of those build entries in the list? Every entry in the list represents a genius idea. Each one addresses a slightly different problem. Now what would happen if we could throw them all into a pot with some curry, stir well, then bake for about an hour and 15 minutes? More important, what would happen if we took the core dev team from each project, locked them in a room with a limited supply of beer and oxygen and allow them to exit with only one 4-5 letter acronym to save the day of struggling engineers trying to build and deploy software?

I personally like Maven, not because I believe it to be the best or even easiest build technology, but because it remembers and enforces the most important idea: “We’re all doing the same thing, building and deploying software!” I’ve seen so many discussions and efforts on build stuff mostly focused in the wrong area, syntax. People usually get themselves into a tangle with Ant where they need a mutable property or a loop or an if/then or some other procedural thing and feel trapped. Other people get themselves into a tangle with project structure and/or build lifecycle where they feel they need to impose order of operations to skirt what’s actually a circular dependency they’ve blinded themselves to or some improper manual contrived dependency management solution. Whatever the case they always point to one of the two biggest scapegoats: Syntax and XML. (Of course XML is a syntax! That was the point of that last joke!)

Syntax isn’t everything!
Syntax is important but it’s not the whole picture. You can create a marvelous project with even the most hideous syntax if you understand structure. True syntax lets you better identify and express good structure but it’s not a prerequisite. Let’s look at it this way. X may have better prettier syntax than Y which has better syntax than Z. But if Z requires a certain structure or orderly way of thinking where X and Y allow and possibly encourage random structure then what are the true advantages?

What’s this Gradle Project?
I just finished reading up on Gradle which would almost look like Gant except that they’ve taken an slightly different approach. There is some Maven’ish convention over configuration in it and I gotta say… I really like what I see. I think I’m on like the 2nd chapter or so of the PDF documentation, which is well written. You know a good project when you see well written docs and comprhensive examples. You can just tell a lot of thought went into the overall design. Gradle attempts a build language using Groovy DSL concepts. What that dumb sentence means is that it contorts the Groovy syntax to allow you to logically express build constructs like tasks, dependencies, sub-projects and the like. Like Gant it integrates Groovy’s Ant Builder which gives you direct and full access to all of Ant’s capabilities using Groovy’s builder notation which mirrors XML tag syntax without the restrictions of XML. You can do stuff like:

   mkdir(dir: scriptDir)
   copy(todir: scriptDir) {
       fileset(dir: 'bundle-includes/scripts', excludes: 'start*')
    }


Which mirrors Ant syntax like:

   <mkdir dir="$scriptDir}"/>
   <copy toDir="${scriptDir}">
      <fileset dir="bundle-includes/scripts" excludes="start*"/>
   </copy>

Gradle goes further allowing multi-project builds and dependencies to be expressed in this syme syntax:

subprojects {
   manifest.mainAttributes([
           'Implementation-Title': 'Gradle',
           'Implementation-Version': '0.1'
           ])
   dependencies {
      compile "commons-lang:commons-lang:3.1"
      test "junit:junit:4.4"
   }
   sourceCompatibility = 1.5
   targetCompatibility = 1.5
   test {
      include '**/*Test.class'
      exclude '**/Abstract*'
   }
}

What about Gant?
As much as I love Groovy and Maven I also dig Gant. I’ve written my first build with it. I n my build I wrap a Maven multi-project build and assemble a tarball of Tomcat with our application pre-installed. It sounds much fancier and prettier than it really is. Gant much like Gradle gives you the builder syntax and a rich set of APIs to interact with. Gant also mirrors Ant structure more closely than Gradle, following the same nomenclature that Ant uses. Gant targets equal Ant targets, Gant tasks equal Ant tasks and so forth. Gant introduces target sets which from my limited understanding are preconfigured targets that know how to do certain things. So far I’ve only used the “clean” target set which already knows how to clean your project. In my build I overrider the clean directory (a feature of target sets), just because I can. Gant promises Maven target sets and also integrates with Ivy. Here’s an example build that uses the MavenTargetSet to build Gant itself:

includeTargets ** gant.targets.Maven * [
    groupId : 'org.codehaus.gant' ,
    artifactId : 'gant' ,
    version : '1.2.1-SNAPSHOT' ,
    javaCompileProperties : [ source : '1.5' , target : '1.5' , debug : 'true' ] ,
    deployURL : 'https://dav.codehaus.org/repository/gant' ,
    deploySnapshotURL : 'https://dav.codehaus.org/snapshots.repository/gant'
    ]

setDefaultTarget ( install )

Overall there’s a lot to be gained by using Gant and I’ve only scratched the surface.

Then there’s Maven
While new projects like Gant, Gradle, Raven, Rake or whatever promise better syntax along with convention over configuration simplicity there’s still Maven. It’s an established project with a lot of maturity that not only builds with far less XML than Ant but also brings in a lot of other features. Maven has plugins that operate almost like mini programs within your build system. I couldn’t understand the complexity involved in creating a plugin initially as I’ve been used to Ant’s simple “create a class with an execute method” idea. But when you look at what Maven plugins do and can do you see they are more than just software components. A build plugin can do anything from simply attaching additional artifacts to the build to completely altering or replicating the build life cycle. Cargo is a good example of the possibilities. With cargo you can completely automate every step in the life cycle of a JEE application from the aquisition of the container (it auto-downloads from the net), to the installing of your product starting and stopping of the container, to integration testing and more. Maven offers the release plugin that ties in your VCS system. Performing releases with Maven allows you to tag not only your product but record the tags or release version of everything your product and your product’s build depends on. That alone is a very powerful feature that you only appreciate when attempting to rollback and reproduce an earlier build. While tools like Ant and Ivy can manage project dependencies Maven manages build dependencies the same way so you can garauntee for eg. that the same version of JUnit and the Xalan Compilers that ran 3 weeks ago during a tag are invoked today when you wish to reproduce. This works because everything involved in a Maven build is either a plugin or a dependency marked with the same name, group ID, and version convention. When releases are performed Maven ensures that there are only released versions involved in the build and commits an expanded project descriptor that notes the precises versions involved to the VCS (Version Control System). In other tools like Ant and Gant, extensions are stored in the tool’s home folder typically in a lib directory and are subject to change. Maven pulls every extension and artifact from a shared repository.

There’s a lot of features in all of these build technologies and I’ve gotten waaay off topic forgetting my point. I’ll summarize: There are a lot of options for building software and each looks more enticing than the others. However, I encourage you to do your homework when selecting one.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s