« 'Content is king' the continuing saga, now with tight money | Main | Cloud computing - A side by side comparison »

September 1, 2009

Java build tools: Why Ant will never go away and Maven will never prosper

I recently had a discussion on what Java build tool to use for a particular project. Its a small project in terms of the amount of code it will use -- a book project to be exact, with all its examples. But one of the co-authors suggested we use Maven. Even though I've learned to use Maven I shy away from it, but now that my co-author has hinted with A Survival Guide to Maven, OR, Why Maven's Still Cool , I thought I'd write this post on why Ant will never go away and why I believe Maven will never prosper.

[Entry continues to the left and below ad ]

A build tool's purpose is to help you be more productive, by not having to go over-and-over the same tedious steps. In Java there are many tools for automating tasks, but one of the first to appear was Apache Ant. Inclusively, Apache Ant is even used as a facility in many Java IDEs -- which are the 'mother' of all build tools.

For some projects Apache Ant seemed to lack certain features, which is essentially what paved the way for Apache Maven as the build tool of choice for many projects. However, I have to say with great distraught that I've now seen Apache Maven used in projects that simply seem overkill, not the least of which were confused faces on development teams trying to make out Maven's configuration for simple tasks.

Why Ant prospered - Compiling, copying and building

If there are 'bread and butter' tasks in software projects you can likely count on them to be: edit source, compile, copy, package...and repeat ad nauseam. If you were to perform these tasks from a console or command line you would likely spend all day typing something like:

 
javac -classpath="$CLASSPATH:./lib/servlet.jar:utils.jar" src/*
cp classes/* build/WEB-INF/classes/
cp ./lib/servlet.jar build/WEB-INF/lib/
jar cvf build.jar -C build/ 

With Apache Ant, it became possible to create a file that could replicate this entire process. So instead of typing all these instructions, you would simply type ant build. Sweet for many development tasks, just like any other script except for Java specific chores. And indeed so sweet, that you are likely to see these Apache Ant scripts -- or build.xml files -- in many projects for ant FILL_IN_THE_BLANK - copying files, compiling classes, creating JARs, creating WARs, performing tests, even sending emails.

Though Apache Ant files can be lengthy and sometimes tricky to create, they are intuitive and adaptable.Here is a sample Apache Ant file used to compile classes, copy a file and create a JAR file.

 
<?xml version="1.0"?>
<project default="init" basedir=".">

  
<project default="init" basedir=".">

  <property name="debug"          value="on"/>
  <property name="optimize"       value="off"/>
  <property name="deprication"    value="off"/>
  <property name="build.compiler" value="modern"/>
  <property name="target.vm"      value="1.5"/>

  <property name="build.dir"      value="classes"/>
  <property name="dist.dir"       value="dist"/>
  <property name="src.dir"        value="src"/>
  <property name="lib.dir"        value="lib/build"/>

  <!-- Load JAR's onto the classpath, taken from lib/build sub-dir -->
  <path id="classpath"> 
   <fileset dir="${lib.dir}">

    <include name="*.jar"/>
   </fileset>
   <pathelement location="${build.dir}"/>
  </path>
</target>

 <target name="build" depends="init" 
                   description="Build project">

 <!-- Copy file -->
 <copy file="${src.dir}/config.ini" 
        tofile="/production/config.ini" overwrite="true"/>

 <!-- Compile -->
 <javac srcdir="${src.dir}"
         destdir="${build.dir}" 
         debug="${debug}"
         optimize="${optimize}"
         deprecation="${depreaction}"
         target="${target.vm}"> 
     <classpath refid="classpath"/>
  </javac>

 <!-- Create JAR -->
  <jar destfile="dist/library.jar" 
          manifest="${src.dir}/META-INF/MANIFEST.MF">
       <fileset  dir="${build.dir}">
           <include name="com/package/justthisdir/**"/>
         </fileset>
  </jar>

While it might take you time to create an Apache Ant script file at first, if this is the series of tasks you will be performing over-and-over again after you modify something, you've saved yourself considerable time by being able to type ant build every subsequent time.

This is the whole purpose of a build tool. And Apache Ant is widely used especially because it adapts to your build process. However or in whatever way you need to compile classes, copy files, create JARs, its likely to offer you a solution.

Why Maven got started - What JAR did you use? And version if you have it?

I first saw Maven being used in Apache top level Java projects(e.g. Apache Tomcat, Apache Struts,etc.). Apache top level projects have a few distinguishing characteristics: They are large and have interdependencies among one another, they are generally worked on by various teams around the world and they are constantly being released in newer versions(e.g. 2.0, 2.0.1, 2.0.5).

If managing this type of work isn't a feat onto itself -- even using version control and project managers if any -- think about the build process. How come 'X person' could build the project? But 'Y person' couldn't? Oh yeah, 'X person' was using commons logging JAR 1.1.0 and 'Y person' had upgraded to the latest commons logging JAR 1.1.2, so the build process for Apache Tomcat 5.5.23 failed.

The problem was obvious and it was solved by establishing a repository, a central location were JARs and their corresponding versions were stored. So instead of different teams keeping track of whatever JARs and versions were needed to build an Apache top level project, all that was needed was a Maven file -- or pom.xml(POM) file.

So come next build, since all required JARs and versions were now declared in a POM file, they were now automatically downloaded from a repository in order to perform the build. Problem solved, everyone using the same dependencies and the build successful. But hey, how about if Maven also compiles the project files, creates JARs and even tests the project, throw in Java doc generation just for the heck of it? Be careful what wish for they say, because you just might get it.

At first, it's my understanding Maven was used to automate the nightly builds on Apache top level projects. I'm sure incorporating all these bells and whistles into Maven made perfect sense for automating builds. Inclusively, if you add to this that Apache top level project aren't created every day, its pretty clear there isn't much need to poke around Maven files constantly.

But beware small to medium sized projects that have build processes in constant flux.

Why Maven will never prosper - I'll leave it for some other time

This is a TRUE STORY with the names of the guilty removed

  • We need to start using Maven, is there a tool to map Ant to Maven?
  • Nope, not that I know of.
  • Ok, its just a few servlets and stuff, no biggie. How do I start?
  • You need a POM file so you can get the artifacts from the Maven repository
  • WAH? I already have the JARs to build the stuff, can you give me a vanilla pom?
  • Sure, its something like this (Scroll down to next paragraph)
  • But I just want to start by compiling? What is that servlet declaration? I already have it!
  • Well maven automates...
  • Nah, i'll leave it for some other time.

The gist of the matter is Maven solves problems, too many problems in fact. On top of this, Maven's syntax is likely to seem alien even to experienced Java developers. Its not entirely clear how a POM file's declarations 'blossom' into JARs and how are things copied around. This is what can drive some people bananas about Maven. You want to make a 'quick and dirty' JAR ? Copy some .properties file out to a directory? Not that easy, unless you Maven-ize your entire build process.

As the old joke went in the ERP world 'An ERP doesn't adapt to an organization, an organization needs to adapt to an ERP'. Truer words I believe could not be spoken for Maven, your build process doesn't adapt to Maven, your build process will need to adapt to Maven.

To give you example, here is an Apache Maven POM file. Judge for yourself.

 
<project xmlns="http://maven.apache.org/POM/4.0.0" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd"> 
 <modelVersion>4.0.0</modelVersion> 
 <groupId>com.library</groupId> 
 <artifactId>utilities</artifactId> 
 <version>1.0-SNAPSHOT</version> 

<dependencies> 
<dependency>  
   <groupId>javax.servlet</groupId>  
   <artifactId>servlet-api</artifactId>  
   <version>2.4</version> </dependency>

</dependencies> 
</project> 

Not every intuitive is it? But in fact, it does a lot more work in lesser lines than what could be an equivalent Apache Ant file. Execute mvn compile and it will compile classes under the src directory. Execute mvn install and it will create a JAR named utilites.jar with the compiled classes under the build directory. Execute mvn javadoc:javadoc and it will generate Java docs from the classes.

That dependency declaration will actually take care of downloading the Java Servlet JAR version 2.4 and any related dependencies -- from a Maven repository -- to your workstation, so you won't have to hunt them down in order to compile your classes -- the same can be done for other dependencies. Want a web site with documentation on the structure of the project ? Just type mvn site. Heck, want to do unit tests? Go ahead, place them under src/test/java Maven will test them for you. That's a lot of work for a few lines isn't it?

But while brevity is an admirable quality for a build tool, in this case it comes at the price of obscurity. Where are files being copied? If at all? This is the main issue your build process will need to adapt to Maven, not Maven to your build process. So how about the simple task of creating two separate JARs from the same source tree with Maven? Simple, you create two different artifacts and use the....I hear that WAH? again.

This is the way Maven works, it will force your to change your build process. Something that not every developer, project or organization is willing to do. It may be right for some, but its the same reason why many stay away from it. Your build process won't be aided by a tool, it will be dictated by it. So no aleatory copying of files, building of JARs, creating temporary directories 'just a single line please' the Maven way.

And then there is Apache Ivy

For the creators of Apache Ivy, one of two things were evident: That Apache Ant was lacking the very thing Apache Maven was designed to solve in the first place -- the capability to use a central JAR repository with versions -- or that Apache Maven was simply making the tasks already provided by Apache Ant too stringent.

Apache Ivy works in conjunction with Apache Ant to provide it with that initial problem addressed by Apache Maven, to be able to guarantee that a build will take place with a certain set of JARs and versions, without manually having to hunt them down across a series of projects or the Internet.

That's my take on the Java build tool landscape. So what was the final build tool decision in this small project I'm undertaking ? Maven, my co-author was kind enough to say it would be a snap to use Maven, so fast that he could easily Maven-ize the whole project. Thanks Josh! I'll stick to Ant and Ivy ;) at least until I see those POM files.

Business corollary: It's more likely that a tool/solution that adapts to your problems will have greater success, than a tool/solution that requires you to adapt your problems to a tool/solution.

History lesson: ERP(Enterprise Resource Planning) was the mania before the Internet, where every company had to have one. SAP I think is the only remnant from this era, there were others like JDEdwards, PeopleSoft and Baan that went they way of the dinosaur (i.e. bought up by Oracle). But what can you expect when entire organizations had to adapt their ways to a tool.

[Comments below ad ]

Posted by Daniel at September 1, 2009 3:50 PM


Comments

Nice writeup. Interesting to hear that the repository concept came first, and all the dependency management malarchy kind of followed. Maven has some good ideas, but all of them are either implemented badly or non extensibly. There is a definite space for abstractions over ant tasks, but Maven tried to do that and far too much else, and didnt do anything well in the end

Posted by: Ross Duncan at March 5, 2010 9:18 AM


Post a comment




Remember Me?

(you may use HTML tags for style)

Track back Pings

Track Back URL for this entry:
http://www.webforefront.com/mtblog/mt-tb.cgi/112.