It’s no secret I have a love/hate relationship with Maven 2.0. I hate it. And I love using it as an example of how not to build software. Maven 2.0 is proof that good intentions, hard work and an open source community can still lead to all kinds of wrong.
And apparently I’m not the only one who feels that way.
It has come to my attention that you are responsible for the loss of many, many hours of my life, hours that could have been spent on more worthwhile endeavours but that now I will never get back. In addition, the resultant fluctuations in my blood pressure have likely reduced my life-expectancy by a corresponding amount.
The road to Maven started full of hope and promise, quickly adding one module after the other. But in less than a month the build escalated into a maintenance nightmare. I seriously could not believe spending a whole day on the trivial task of copying one file from here to there. Can you imagine it takes 34 lines of XML code to concatenate two SQL scripts into one? And that’s before we start using them to populate the test database.
So everyone around me is wondering “what’s taking you so long?”, and I’m asking myself the same question. Did I finally meet my foe? The one technology that’s groundbreaking, forward thinking, and just beyond my grasp? Is it time to admit defeat and move on to something else. Maybe landscaping?
But I stayed the course, got something half working, enough to get the other developers to start using the new build. I’m glad I did. Now that everyone else was in the same sinking boat, I no longer had to explain the unexplainable. I finally felt vindicated. It wasn’t me. I wasn’t a retard, just unfortunate enough to use the build system that couldn’t.
We were already committed to make a release, and so the project went live, Maven and all. But we knew what will come next. The continuous build server reported random bugs, sometimes it would build, sometimes it won’t. Every few days, a developer would e-mail to let us know the build system doesn’t build. When it just did, a minute ago.
We quickly dubbed it the Maven Uncertainty Principle, though in fairness we knew there was little uncertainty or doubt whether the build will work: .
Almost everything I’ve ever downloaded that used maven for its build process, didn’t build.
Finally, one day we just had enough. The test cases stopped working. The surefire plugin surely did not fire. Even worse, a few days before I had to go and disable one of our critical test suites. Maven couldn’t deal with the fact that we excluded an old Log4J brought in by one of the dependencies, so we can then include the Log4J version we certify against. Perhaps Maven was telling us not to use test cases and we were too thick to listen.
Either way, we had to choose. Agile or Maven. One of them will have to go.
So we started imagining the happy life we could all live with Maven out of the way. Maybe we’ll switch back to Ant? For all its shortcomings, at least Ant builds work. Repeatedly. With certainty. You tell Ant what to do, and it does exactly that. No more guessing, hurting knuckles from crossed fingers.
Sure, Ant is not “declarative”, the holy grail of software developers everywhere. But declarative done badly is worse than any imperative spaghetti code. Between the phases, goals, profiles, modules, transitive dependencies, configurations, other people’s POMs, plugins, build.xmls all over the place, and the funky reactor, how do you know what your build will end up doing? It requires running a lot of imperative code. In our head, and by trail and error builds for hours on end.
With Ant, we just had to imagine and make it happen.
Or maybe we should try something else? , the Ruby equivalent of Make? It lets you declare tasks and handles the dependencies between them. It slices through file dependencies like a hot knife on butter. It even has a Make-like rules system. It uses Ruby which, we’re told, is more capable than the Ant mock-language. It has … get ready for this … mutable variables, functions and classes! We can use these to keep our code DRY and neat, write and reuse code. Heck, we could even write “plugins” with just a few lines of code
So we did it. We started with Rake. Let me spoil the surprise for you. It turned out to be an excellent choice.
Rake was a good start, but not what we’d hope for. The typical Java application we work on consists of several modules, all of which have the same common lifecycle tasks: compile, test, package, deploy. Writing those over and over for each and every module would make it not much better than Ant. There’s got to a a better way.
They don’t just all have the same lifecycle tasks, they also have the same directory structure. So we used that to build a little framework that, by just pointing at a project could infer all the common tasks based on the files it finds. And for everything that deviates from conventions, we could just script with a few lines. There’s no escaping all and special considerations, but with Ruby we can make them easy.
Want to see some examples?
Build me a JAR:
define "utils" do compile.with COMMONS.logging, COMMONS.pool, LOG4J, XERCES, JAVAX.stream package :jar end
With XML beans generated from the schema, if you don’t mind:
define "bpel-schemas" do compile_xml_beans "src/main/xsd", "src/main/xsd/*.xsdconfig" package :jar end
No, wait, I want to merge two SQL files I just generated, and build a database from that:
derby_sql = concat("derby.sql"=>[engine_sql, quartz_sql])
derby_db = Derby.create("derby/jpadb"=>derby_sql)
The nice thing about the little example, is that it will build the database once, but regenerate it every time you chance one of the source files. There’s a free t-shirt for you if you can show me how to implement this in two lines of Maven or Ant code.
Now, let’s compile, package and install all of that in the local repository, so we can use these modules in other projects:
rake install
That, in a nutshell, is how we went from the deeps of frustration to a build system that … hold on a second … is actually fun to use. And dead easy to customize. And works repeatedly.
Say goodbye to frustrations and the Maven Uncertainty Principle. Stop arguing over declarative vs imperative, just have both.
Now I hate using the Beta tag, but let’s be clear, we’re a few short weeks from making a final release. We’re using it in several projects already, enjoying every minute of it. We’re happy, the continuous integration server is happy, life is good. But it’s still rough around the edges, and some bits will change before we hit 1.0. And the documentation is terse.
So if you want to get started today, I recommend picking up an existing Rakefile (and check out some of the custom tasks). It’s a complex project, but it will show you the extent of what Buildr can do.
Lovable Lyle » Blog Archive » Buildr as a replacement for Maven
Labnotes » Buildr, or when Ruby is faster than Java
monkinetic | Blog Archive » I hate RDoc
Agylen » Introducing Buildr
monkinetic | Blog Archive » Structured Docs v. The Blank White Sheet
David Bolton Strikes Again » Blog Archive » O’Reilly Radar, Buildr, Mingle & “The Corporate World”
prozz’s blog » Blog Archive » Ruby researches
JavaSPEKTRUM Blogosphäre » Blog Archiv » Blogosphäre (aus JavaSPEKTRUM 04/07)
IT-eye » Maven, Ant, Buildr, or what?
Hints for Mavenization of Java Web Applications « Java and more …