Graeme Rocher answered my previous post. He strongly believes that maven will be replaced by Gant, Raven or Buildr.
I decide to learn about all them to see their features. Maybe I could find something better than Maven, something that justify expecting the replacement. But as soon as I started to evaluate the solutions I verified that some of then cannot be compared to maven. Gant is much more close to Ant than to Maven. A lot of people think of maven as a replacement for ant, for them they are equivalent tools with different approaches. They are not equivalent tools, actually maven is a different category of tool. So I think is a good idea to explain what is this "different category".
Ant is a rewrite of Make in java. The main advantage of ant over make was the new build file format (in xml instead of the really bad space sensitive makefile format) and the fact that is cross-platform (so better for using in a cross-platform language). So ant operate in the same level of abstraction of make, a little higher because it abstracts the operating system but the developer still creating targets (even the vocabulary is the same in both tools). The main advance of the make/ant model is an different computational model (this is better explained by Martin Fowler in http://martinfowler.com/articles/rake.html#DependencyBasedProgramming, in my personal point of view it is a specialization of lazy evaluation in the pure functional languages sense, but it came from a different context and solving a different domain problem).
So in make/ant model you define targets and dependencies between this targets to make your build.
For example:
<project name="MyProject" default="dist" basedir=".">
<description>simple example build file</description>
<!-- set global properties for this build -->
<property name="src" location="src"/>
<property name="build" location="build"/>
<property name="dist" location="dist"/>
<target name="init">
<!-- Create the time stamp -->
<tstamp/>
<!-- Create the build directory structure used by compile -->
<mkdir dir="${build}"/>
</target>
<target name="compile" depends="init" description="compile the source ">
<!-- Compile the java code from ${src} into ${build} -->
<javac srcdir="${src}" destdir="${build}"/>
</target>
<target name="dist" depends="compile" description="generate the distribution">
<!-- Create the distribution directory -->
<mkdir dir="${dist}/lib"/>
<!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file -->
<jar jarfile="${dist}/lib/MyProject-${DSTAMP}.jar" basedir="${build}"/>
</target>
<target name="clean" description="clean up">
<!-- Delete the ${build} and ${dist} directory trees -->
<delete dir="${build}"/>
<delete dir="${dist}"/>
</target>
</project>
I took this example from ant manual - http://ant.apache.org/manual/using.html#example.
As you can see in this simple build file is defining three properties and four targets. These four targets are really commons (init, compile, dist and clean).
Let's look close to the compile target:
<target name="compile" depends="init" description="compile the source ">
<!-- Compile the java code from ${src} into ${build} -->
<javac srcdir="${src}" destdir="${build}"/>
</target>
Who, that uses ant for more than 6 months, have not written (or copy-and-paste) this target at least 5 times?
If we analyze we can see that it has one dependency (init), one task (javac) and two parameters for the task (srcdir and destdir). Why should I put this in my way if all I need is to specify the srcdir and the destdir?
When maven started it was just a layer on top of ant to avoid copying the targets around, but looking forward for opportunities to improve they make the right question: "why not put the files always in the same place?". It was born the standard layout directory of maven. Instead of having to think in the directory layout for each project use the same and take advantage of standardization ("Where is the java files?" /src/main/java "and the test cases?" /src/test/java "where do I put my resources files?" /src/main/resources "no, but it is just for my test environment" ok, /src/test/resources). This directory layout was created by maven, before the commonest one was /src for java sources and /bin to put the generate ("where should I put the groovy files?" "Choose a directory name and put in your build file" (or copy the maven layout /src/main/groovy)).
So maven is not comparable with ant/make it works on top of this layer. You still need the "scripts" but now the scripts are encapsulated in plugins that exposes goals (the tasks) and properties (that allow configuration when the default is not enough). This plugins are managed by the dependency system themselves so you don't need to install then, you just need to get then from the repository, the external ones (you can find virtually all open source java libraries/frameworks available there) or your internal (any medium size should have one, it's just a http server with a specific repository layout). Maven works in the project management level, you just set a few properties and your project is running. You don't need to write/copy-and-paste a war target the generate a war, just declare that that your packaging property is "war" and the package target will generate a war instead of a jar (yes, it is just that, you don't need to read the manual).
So with this understanding of the different layers levels of maven and ant/make, let's see the tools cited by Graeme.
Gant:
Quoting there site "Gant is a build tool for scripting Ant tasks using Groovy instead of XML to specify the build logic." So they are change the xml syntax of ant to a groovy one, it seems a a good idea to me. But you still have to copy the scripts around. It's not there problem, they are in the ant/make level and anyway they are doing a step in the right direction. (The weakest point in ant IMHO is to use xml to define the targets, for me xml is for data, I never liked programming in xml (like jelly).
Raven:
Raven it's between both levels. It uses Rake and Gems. Rake is a re-implementation of make in ruby, like ant in java, but with a syntax better than xml (it uses ruby itself as the language for the scripts instead of the awful make syntax or xml syntax of ant). As in other make implementations, you still need to copy your scripts around. Gem is a package system used in ruby. It manages not just the dependencies but the install process of the software. Gems is similar to the package system of the linux distributions (if you want to go deep read about Portage or APT). You can search/install/upgrade/remove/query applications with just one command. This pattern works really well in system administrator. Gems brings this pattern for the development environment. Maven just get the library from your repository and make it available in the the classpath of your build environment (maven has the concept of scopes and each scope has a different classpath), Gems do that installing the library in your system, what is a more wide operation. The other downside is that the final artifact of gems is always a gem. Generating anything different of that is a side effect of a project specific script provided by you. Gem is user visible, the command is present in the user environment, maven is developer only, just the final artifact is delivered. The advantage is that for developers of desktop applications, gems is the installer (forget about InstallShield or Izpack). For server developer there is no installer at all, we delivery a war (or ear, or sar :) ) and this is deployed in the application server (or servlet container). Bring the package system pattern (in the portage/apt meaning) for build environment is a interesting idea because they are unifying a broader pattern (manager dependencies). But in the packaging system the main artifact are programs, libraries are there just as dependency for multiple programs (portage is able to manage side-by-side 2 versions of the same package but not all package are able to do that). In the developer environment there is no programs, libraries are the main artifact in the dependency system, put 2 versions of the same library is trivial (it's not installed, it is just available in the system file), I can use version 2.4 of some library in one project and version 2.5 in another. If they can remove the unnecessary complexity in the developer environment this can be interesting to see. Things became more and more distributed, type "emerge mutt" (or "aptitude install mutt") and have the package and dependencies downloaded, installed and pre-configured (these package system are able to interact with the user) are amazing. Type "mvn package" in a clean machine and have all the libraries downloaded and placed in the right place is amazing. Have the same tool scaling up and down for both situation will be great. That is not yet the case for gems (developer environment is not their focus) or maven (manager installation is completely out of their scope) . But this is an are this can be worth researching. (If it has the simplicity of the minimal approach of the GoboLinux package system it will be a paradigm shift in the field).
- Buildr:
They use the maven "file layout, artifact specifications, local and remote repositories" (good, don't reinvent the wheel, if it works copy and improve it if it is possible). They simplify maven using ruby (what is cool IMHO), but they simplify the maven model in the wrong place. Quoting the main page of their site: "No overhead for building “plugins” or configuration. Just write new tasks or functions.". Ok, do I have to re-write again the compile task? do I have to re-write again the compile task? re-write again the compile task? re-write ... OK, you got the idea. That was a RBT (Really Bad Thing, ok, I made-up this name). So they copied maven but they missed the main point of maven. Using ruby is a good idea, but I need a way to reuse this scripts. Plugin (or give another name if you want) is just a script that can be reused. They think that maven plugin system is complex, simplify it. Actually this is a good point to simplify maven using ruby, a maven plugin has to implement org.apache.maven.plugin.AbstractMojo (http://maven.apache.org/guides/plugin/guide-java-plugin-development.html). Thanks to the dynamic typing I think that this can be simplified in ruby. Not all tasks are an "one-off task". So buildr can be a maven replacement if they provide a good way to reuse the scripts. But for now I don't want to get back to the times when all I had was ant and a big set of scripts.
So Gant is not intended to be a maven replacement (it is a ant improvement using groovy instead xml). Raven is a different sort of tool (ant/make level plus installer, no reuse of the scripts). Buildr is the only one that is intended to be a maven replacement, but they made a big mistake removing the plugin system. It will be interesting to look again if they fix this.
PS: Answering a comment thay "all ASF projects used to have Ant, they have Maven now... There is a reason ;)", Graeme says that "ASF use maven because maven is Apache and they have to eat their own dog food". Actually this is inaccurate, ant was created in the very first project of jakarta (jakarta was the java branch inside Apache Foundation, now there are quite a few top level java projects). Jakarta was create when sun licensed the source code to the JavaServer Web Development Kit (JSWDK) to Apache Foundation to create Tomcat in 1.999. Ant was created by James Davidson in the process of opening the source of the jswdk. It was necessary a cross platform build tool because they could not know anymore in what platform developers will use to build it. So practical problem, practical solution, re-implement make in java. So ASF didn't change because they "have to eat their own dog food", both was created in the ASF (maven was created inside turbine web framework that was a good alternative to struts but is dead now because of internal problems) and I don't think that none of then are dog food. They are different tools, each one with its own merits. Both projects helped to evolve the way we build systems with new ideas.
Comments
:-)
"But you still have to copy the scripts around." -> wrong look at how Grails uses Gant to provide user interface. Scripts are written and "No" you do not have to change them. Sometimes scripts do not do the thing you need them to do and have bugs but this is not to say that you can not encapsulate your build practices into scripts and reuse them (BTW, the same will happen to your maven plugin that just does not cut the muster or buggy).
If you ever wrote a Grails script you would see how easy it is to extend the build system (try it out - do not read the articles ... just do it). Then try to create a maven plugin. Compare the difference, hopefully you will find that maven plugin development is a lot of ceremony without much traction while grails build system just gets to the point and out of your way.
Gant is definitely lacking some of the features needed but I think it can get where maven is. I wish it had came with default functionality similar to waht Grails built on top of it, for example. Multi-modular build are not out of the box either, otherwise it is a pretty good tool. Light-weight for sure, something that maven not going to be.
Gant
"Do not read the articles ... just do it" is not a reasonable advice.
Have a look in the Gant site. Yes you can import scripts but you still have to create your script. For sure been able to "import" a script in your is a step in the right direction but it still a main script. If they change the focus from target creation to configuration then it will be a better build system. Until there you still have to recreate your main script. Pay attention to your mindset, you are programming a build script, in maven you are configuring your build environment (just when the default is not what your project need).
The next step will be to have dependency management and it will be working in the same level as maven.
Cheers,
Jonas Fagundes
Did you check Gradle?
I think it takes the best of all worlds: ant + ivy integration, plugin system which automatically adds targets, multi project builds, and more.
check gradle
I think the gradle project (http://www.gradle.org) got things right:
1. it uses Ivy for dependency management and you can use any ant task.
2. the build scripts are in groovy, so you have a real language to code the build logic in
3. there's a plugin system which allows plugins to add targets and methods to the build as well as a 'convention' object that defines common paths, properties, etc. building a jar file is just using 'usePlugin("java")' in your build file
4. every module is represented as an object together with the rest. this means you can manipulate all of them together (to set some common attribute, etc.), create cross-module dependencies, etc.
5. in particular, you don't need to have a build file per module, you can write all your logic in one root build file, but if you do want to separate, then the sub-module build files inherit properties and methods from their parents.
6. you can redefine targets. so if a plugin adds some targets, with dependencies, but one of them isn't exactly what you need, you can just change it. so it's like maven's lifecycle (where the lifecycle is constant regardles of what you do in each phase), but with the ability to define it as you (or the plugin) want (and not as maven decided). you can add dependencies also.
Ittay
Gradle
Hi,
It seems interesting but I had a look in the documentation in the site and there are *a lot* of programming.
Could you provide me an example of a simple project with no programming (just a configuration file) in the build?
Cheers,
Jonas Fagundes
p.s. Dog food is not a derogatory term, so don't be offended
The first time that I came across the term was on XDoclet http://xdoclet.sourceforge.net/xdoclet/install.html
Generating the XDoclet Documentation
XDoclet uses Maven and XDoclet (yes, we do eat our own dog food!) to generate the documentation.
Dog Food
Hi,
I'm not offended but in the context of Graeme's comment it was depreciative:
"ASF use maven because maven is Apache and they have to eat their own dog food"
It means that ASF moved to maven not based on the benefits of maven of ant but because maven was created in house and ant wasn't. This information is incorrect as answered in the post.
Cheers,
Jonas
Great article and your PS was
Great article and your PS was dead on.
Pingback
[...] discussion follows in http://graemerocher.blogspot.com/2008/01/why-grails-doesnt-use-maven.html and http://jonasfagundes.com/blog/2008/01/the-misunderstood-maven. [...]
Why they are all wrong yet have good ideas
About the best thing Ant/Maven did was the plugin architecture. Ivy did well with the dependency resolution. Using XML to describe anything but simple software projects is very ineffective and inefficient.
Quite often build systems are pushed to the limits by bad practices used to: layout source trees, normalizing properties, targets, and workflows and an entire host of issues.
Another thing to consider is, a build system that is good for a technology team, may not be good for an application team, and even the way a software team is organized can contribute to build system simplicity and complexity. Its not just a tool problem. The build system has to fit the culture of the software team. For example. When I put in build systems for technology teams, we are working to eliminate release engineering which means the build system must be accessible to everyone in engineering (meaning it should be eash, straightforward for everyone in engineering to maintain and extend). To do this the implementation must be like a campground where everyone has what they need to camp and do what they need, as compared to the resort where you don't know how anything about how things work, someone else will take care of everything for you.
Campground versus Resort build system deployment. A resort is == to a black box, and a campground is == to a white box. A white box people can see how things work, and how to modify to get results. The black box, no one really knows how it works or requires a significant ramp up or even worse a build specialist. Certain types of software organizations can deal with campground systems, others are better off with the resort (In my mind the resort style of building engineering infrastructure is the worst thing to do. But I did just state that "others are better off with the resort". These are the teams where the culture is made up of silos and people are not expected to develop breadth)
A build system should empower the individual contributors, yet that is very rarely the case. Groovy and Java scripting languages are a symptom of poor build utility architecture and implementation (i.e ant, maven). Ant and Maven both have some good concepts, but in the end they generally are difficult for most teams to deal with. One of the traps people get into is trying to do everything inside of Ant or Maven and thats when the build system turns into something most team members would prefer to avoid.
First thing that would help is if the people designing these build utilities articulate what problems they are solving and how they are solving them. What we generally get from the authors is a description of the symptom they are solving not the essence of the problem. Its like a piling on effect, where there is rarely mention of the fundamentals being solved. BTW Ant is in no way a rewrite of Make in Java. The design of Ant and Make have nothing in common.
Next thing that would help is if the people designing these build utilities not mimic the rest of the Java community by selecting XML as the language used to perform build configuration/description. The Java community has gone bananas with XML.
Every instance I've been involved with where people resort to scripting with groovy and other like languages results in an even worse mess as the build system turns in a bad Sherlock Holmes novel. At one startup I worked at, one engineer could not stand using Make, so he wrote the build system in shell scripts... The first thing I explained was the importance of normalizing the data in a build system, which was lost in the shell script implementation. When I see scripting languages applied to the Ant and Maven problem, what I'm looking for is: ant tasks, plugins, or mojos to be written which is in keeping with the declarative approach, instead what is generally done is willy-nilly scripting occurs right the midst of all the XML. This drives most developers bananas or to heavy drinking.
Unfortunately the Java community has yet to create a reasonable system.
Re: Why they are all wrong yet have good ideas
Kramer,
You completely skipped the subject of the article. This discussion has nothing to do with white box versus black box but the differences between ant and maven. You clear stated the in your opinion none of them are reasonable. So no point left to argue about in your comment. Just one question: what do you use do build your systems in java?
BTW, ant it IS a make re-implementation in java. The idea was to create a multi-platform make reimplementation to be used in all platforms that java can run. Portability was the reason they didn't use make or any shell script.
Cheers,
Jonas