Dick and Carl have talked a lot about builds lately, prompting this
post...
I spent about a year doing nothing but Ruby and then ended up going
back to my old Java job. I learned a lot in the Ruby world, and one
of the big take-aways I had was that the way build systems work in the
Java world is completely broken.
In ruby there is this wonderful tool called rake (http://
rake.rubyforge.org). Rake is more than a build system, it's really a
system for anything you want automated.
You can leverage your code inside this system. So if you wrote a
class that cleaned a database as part of your main code base, you can
hook rake into it and run it something like: rake clean_db
Rake is just ruby code, you have the full power of Ruby within a
syntax a bit similar to Ant:
task :default => [:test]
task :test => [:clean_db] do
ruby "test/unittest.rb"
end
task :clean_db do
DBUtil.cleanDB
end
in this case the test target has a dependency on clean_db. And
clean_db is simply a ruby class that cleans all data from the
database.
In the ruby world, there are many Rake plugins that allow you to do
all sorts of automation. There are plugins that deploy/manage to
Amazon EC2. One called Capistrano that you run on your prod system
checks your source code out from source control, runs migration
scripts, backs up the old version, and starts up your new updated
system, all with one command. One of the most brilliant ideas in
Rails, database migrations is driven by Rake. So your deployment
might be as simple as "rake deploy". Your database migration is "rake
db:migrate", which will check your current version of the database and
apply and schema and/or database migrations needed to get up-to-date.
Since you can write Ruby code in your build file you can easily write
code that has conditionals, loops, string manipulations, etc. In
other words, you can easily put intelligence into your build! Doing
these simple tasks in Ant or Maven is nightmarish. Coding them sucks
and debugging them is even worse. XML is a terrible way to define
your build systems, it works ok for trivial cases, but as any
experienced developers know, trivial cases soon evolve - or devolve -
into complex cases. Don't believe me? Here's what the creator of Ant
(James Duncan Davidson)said back in 2003:
http://weblogs.java.net/blog/duncan/archive/open_source/index.html .
Or in 2004, he's more explicit:
http://web.archive.org/web/20041217023752/http://x180.net/Journal/2004/03/31.html
"If I knew then what I knew now, I would have tried using a real
scripting language, such as JavaScript via the Rhino component or
Python via JPython, with bindings to Java objects which implemented
the functionality expressed in todays tasks. Then, there would be a
first class way to express logic and we wouldn't be stuck with XML as
a format that is too bulky for the way that people really want to use
the tool. "
But 4 and half years later and 99% of the java world is still writing
their builds in XML.
Solution? Well there is Gant:
http://gant.codehaus.org/. Gant is
simply a groovy hook into Ant. Write your builds in Groovy script and
leverage ant tasks. Where I work, we are going down this path. After
doing this for a while, I can't recommend it. It's better than xml,
but has it's own set of problems - mainly due to the nature of
Groovy. Since Groovy isn't truly interpreted, it's very hard to
leverage your existing code base. For example, if I want to call my
Java class "DBUtil.cleanDB()", this class must be compiled for the
groovy script that calls it to run. So you have to jump through
multiple stage builds, just as you would with Ant. Another issue I
have with Gant/Groovy are the exception stack straces are terrible.
There are dozens and dozens of useless lines in every stack dump,
which stem from how groovy is implemented. Here's an example in an
issue I submitted:
http://jira.codehaus.org/browse/GROOVY-2944. I
have other issues, but these are the two big ones.
Better solution? Well you can always use Ruby to do Java builds using
a Ruby Gem called antwrap. Here's an example of a simple build I did
in JRuby:
http://pastie.org/323131
It's interpreted so you can leverage your whole code base and write
clever code to do whatever you can imagine. Ruby has a much easier,
more powerful File API than Groovy or Java, which is huge for builds.
Another Ruby option, this is more maven-ish with a bunch of dependency
management features - Buildr
http://incubator.apache.org/buildr/ .
This project scares me at first glance. I looked at it and got
confused pretty quickly. I actually discovered the AntWrap gem trying
to figure out Buildr and decided AntWrap was good enough for my
purposes.
The power of a scripting language is huge. I wish Sun would endorse
some sort of scripting(interpreted) language as the official java
scripting language. I say scripting instead of "dynamic" in this case
because I think being interpreted is very important, much more so than
duck typing or dynamic features. But I don't really see any scripting
language really making the big move on the JVM because Sun is
remaining agnostic. They still do all their builds with Ant (yuck).
They don't leverage a scripting language for any automation (like
maybe administrating glassfish?).
Perhaps JavaFx script could be leveraged and made into the language
I'm thinking about? The start is there... the syntax is quite a bit
nicer than Java. It's not interpreted, but it could be.
any thoughts on this? Am I the only one who sees this need (it seems
like it)...