Ant considered harmful was Re: JSP still relevant
On Sat, 27 Jun 2009, Arved Sandstrom wrote:
Tom Anderson wrote:
[ SNIP ]
The 'if' task in ant (actually ant-contrib - and don't get me started on
how much i hate ant) looks like:
[ SNIP ]
I'm a shit disturber...I don't mind getting you started on how much you
hate Ant. :-)
I'm no fan of it either.
Right, time for a hate-on-ant thread!
For starters I don't like the fact that it's in XML (a serious Ant build
file is bloated and unnecessarily difficult to understand).
Yup. It's a classic example of XML for its own sake - ant gains nothing by
being in XML. It's not like people use CSS to display it, or XSLT to
transform it. It just adds verbosity and awkwardness.
And I don't find it nearly as powerful or flexible as make-type build
tools, not without major extra effort.
I have no experience with make, so i can't comment. I find ant to be of a
similar power to shell script, but taking four times as long to say
anything, and that's what makes it agonising.
Unfortunately I have to use Ant on the job - not many of the junior or
intermediate Java developers I work with have ever seen any other build
system.
We're in the opposite situation: we had a build system made entirely out
of shell scripts. Yes, it was pretty hairy, but it worked, and as time
went by, we refactored and bulletproofed and added sanity checks and so
on, and it was actually pretty decent - although i wouldn't enjoy being
someone unfamiliar with it who had to do anything but run it. Recently, we
started work on a new project which had different needs for its build, and
where we'd have to deliver the build system to the customer, who was using
windows on their development boxes. For that project, we went with ant,
because shell scripts are neither portable nor widely understood and
accepted as a serious build tool. We've since started retrofitting that
new build system to our previous project, and i've had a chance to compare
the two languages side by side.
Someone, i think on kuro5hin of all places, said that the problem with ant
is that it was invented by someone who thought make was too complex, but
later discovered that there was a reason for that complexity. In other
words, it consists of some basic ideas that are really too simple to do
the job, with a load of extra complexity shoehorned in on top.
I am increasingly of the opinion that build scripts are programs, and
should be written in a programming language. They're complex enough to
both use the power that real programming languages provide (simple things
like loops, arrays, if-then-else) and to benefit from the rigour that
comes with it (subroutines with named parameters and return values,
lexical scoping, typed values, if not typed variables). Of course, a
general-purpose language isn't ideal for build scripts, because there are
all sorts of things you frequently need to do that are cumbersome to
express (my canonical example is "do this task, but only if it hasn't
already been done" - trivial in make, but taking a few lines in a
general-purpose language, or in ant for that matter).
That's the core of my problem with ant, really. To do even the simplest
thing seems to take lines and lines of horrific XML.
My plan is for a thin layer on top of python, with a conceptual approach
more like ant than make, ie tasks not targets. Python is concise and
readable (and writable), on a similar order to make, and is easily
extended in certain directions. Tasks would just be functions with a
special decorator; further decorators could be use to express particularly
buildy ideas (note - python's decorators look like java's annotations, but
are more like lisp's macros; they can actually change the definition of
the thing they decorate). And there would be a library of functions and
classes based on ant's building blocks, like filesets and so on. I'm
thinking it would look like:
@onlyonce
@task
def installRunConf():
copy("/run-resources/run_myapp.conf", JBOSS_HOME + "/bin")
@ifnewer("/sql/oracle/create_tables.sql", "/sql/mssql/create_tables.sql")
@task
def regenerateMSSQL():
run("/bin/ora2ms.sh", "/sql/mssql", glob("/sql/oracle/*.sql"))
@public
@task
def setupConfigurationFiles():
"Sets up the run.conf and SQL files for MyApp."
installRunConf()
regenerateMSSQL()
There'd then be a fairly simple driver tool which would load and run build
scripts (doing some necessary trickery with imports), and also let you do
things like list the tasks in them (with descriptions), run a script with
some level of tracing, and whatever. Like:
pant --trace setupmyapp.pant deployApp instanceName=myapp-demo-1 dbType=oracle dbName=DEMO1
Bruce Eckels previously and independently had a similar idea:
http://www.artima.com/weblogs/viewpost.jsp?thread=241209
Although his is much more make-ish than mine.
tom
--
What's the secret to our success? Shouting Robots! People love it when
robots yell at them!