The Source for Java Technology Collaboration
User: Password:



Ken Arnold's Blog

Tools Archives


The Sum of Ant

Posted by arnold on May 30, 2004 at 07:52 PM | Permalink | Comments (7)

In a previous blog on today.java.net I said some fairly strong things about ant, and I think I ought to say something more, both good and bad. This seems like the place to do it.

First, let us give ant its due. Ant is designed to be a portable way to replace make. Ant was to be platform independent, so the obvious implementation choice was Java, which is fine, mostly. And the obvious data format for the project description -- saying what needs to be built -- was XML, which is not fine, as we shall see.

Ant performs this task with some power, if little aplomb. On can build ant files that will compile Java, C, and many other languages; perform CVS and FTP tasks; build jar files and EJB deployments, and so forth. Ant can run the same configuration without modification, no matter the platform. This is no mean feat. There is a reason why it has been winning many awards.

But when I say it is "with little aplomb", I mean it. Nobody can accuse XML of being an easy read, of course, but if that were ant's worst problem, well, ant is hardly alone in this sin. XML abuse is rampant, and ant is far, far from the worst offender. Given the limitations of XML syntax, ant does pretty well. To see it really suck, try reading Graydon Hoare's essay on XML abuse. (Ignore the odd section headings and stick to the content.)

The real problem is the one I talked about in my brief java.net blog:

Ant is nothing more than the sum of its parts
By this I mean that ant has not learned the basic power of composition, building things out smaller parts. This was the great insight that our Unix forbearers bequeathed us toolsmiths, and it's pretty sad to see it forgotten. In Unix this is done with pipes -- the output of one program can become the input of another. Along with conventions about program output, this allows you to build up something that is more than the sum of its parts. A utility that finds file in the file system can generate a list of files for any purpose: removal, editing, rebuilding, copying, printing, ...

Ant has many kinds of tasks. These are portable because they are written in Java, and these task implementations can rely upon operating system abstractions in the underlying ant platform.

But they almost never work together. There are some common tools for building up lists of files, but if you want a list of files from any other source, good luck. This is why there are two different tasks (one optional) that calculate list of Java class dependencies, and they are incompatible. And if you want a list of Java class dependencies for a task that one of these two tasks can't handle, good luck.

A common quote in our biz is the observation that a good software tool will do things the author never expected1. I doubt that writers of ant tasks are very often surprised.

In fact, I will assume that the value of composable tools is so obvious, I will not belabor it further. Unless you ask...

My experience is that the primary legibility problem with Makefiles are strings and variables. The string operations are primitive, ugly, and limited. So to do anything at all interesting requires cryptic and hobbled work. After that, the next worst problem is the lack of flow control. Loops are put into the shell commands because make doesn't have loops, or (shudder) people use recursion as a replacement. Ugh.

The primary portability problem is obvious: Different system have different commands, and make just executes commands.

So where would one go to leverage existing tools that already know how to do these things well? Scripting languages, of course. Perl, python/jython, tcl, and so on live, breath, eat, and excrete strings for a living, and they are programming languages with real logic. They are ported to every platform that matters (more than Java runs on).

All they are missing are tools to express dependencies and how to apply them to building things. One of the response to my post pointed me at scons, which does this in Python. It seems just the right direction, although I haven't had a chance to do more than play with scons. I don't claim it is the right answer, but it sure is moving down the right path.

Johnathan Simon's blog entry about how to use ant tasks from jython points towards some hope that we can reuse all the work these folks put into ant tasks. This has often been non-trivial effort, and it would be good to keep this work viable.

One could pick any language, of course, and choosing a winner here would antagonize folks who would just prove they could do it better in the "right" language. I have my preferred scripting languages, but compared to scripting in XML itself (which is where the ant folks seem to be going), no major possibility is worse.

I intend to poke harder at scons, and if it looks good, dive in fully to find out. You'll be seeing a blog here about scons and the lessons to learn from it.


[1] Google has failed me. Can the death of the internet be far behind? I cannot find an attribution for this quote, despite the obvious set of words and the fact that it's a computer quote that I've heard a billion times.

Duncan Davidson is being kind...

Posted by arnold on June 25, 2003 at 07:39 AM | Permalink | Comments (6)

Duncan reports that I gently and kindly harangued him at MacHack about ant. I'm not so sure I was all that gentle, but I hope I was kind. It's interesting that after we talked, he said "You've got ant's killer weakness there." But what he quoted was not what I expected. His quote was:
The problem with Ant is that it violates something we learned with Unix. Tasks aren't composable.
But what I thought he would quote was my opening line:
Ant is nothing more than the sum of its parts.
I suppose it's the same critique, but my summary is more pungent. And yet he thought I was being gentle...

James Gosling once said that every configuration file becomes a programming language, so you might as well think that way. I think ant confirms this in spades. Duncan started it out as a quick way to build a few things. It has grown to be a monster. I admit it is a useful monster, but it works just like Unix would if there were no pipes. Each task has its own way of approaching issues that arise when performing that task. If you want to do something that the task author didn't think of, well, there you are. Good luck.

The Unix model would say that there were tasks that generate (say) dependency calculations and tasks that build jar files and tasks that did text transformations and tasks that deleted files. So if I wanted to delete all files that were depended on by a particular task, I would put these together. And if instead of deleting them, I wanted to jar them up, I would compose nearly the same tasks, but not quite. But with ant, these are two different tasks, unless someone happened to think of merging them.

Unix got it right. Ant needs pipes.

I'm trying to figure out how to build a platform for executing existing ant tasks and yet allow them to open up this way. Possibly something with the bean shell. Maybe jython, as Duncan started to describe.



Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds