Why using Maven for Clojure builds is a no-brainer

Put simply:

It’s the community, stupid.

Or:

If you have to pick, choose function over form (at least when it comes to build tools).

Ahem. Sorry, let’s start from the beginning.

Like any group of super-smart programmers using a relatively new language, a lot of folks in the Clojure community have looked at existing build tools (the JVM space is the relevant one here, meaning primarily Maven and Ant, although someone will bark if I don’t mention Gradle, too), and felt a rush of disdain. I’d speculate that this came mostly because of XML allergies, but perhaps also in part because when one has a hammer as glorious as Clojure, it’s hard to not want to use it to beat away at every problem in sight. Ruby has rake, and python has easy_install, so it seems natural that Clojure should have its own build system that leverages the language’s stellar capabilities – “just think of how simple builds could be given macros and such”, one might think.

I can sympathize with that perspective, and I admit that I, too, once thought that a Clojure-based build system was an obvious move. This notion runs off the rails pretty quickly for one reason:

Builds inherently involve stitching together lots of bits from disparate sources. Clojure is great for building amazingly flexible and featureful programs up from first principles, but don’t confuse that foundational capability with being able to easily deploy a Compojure web application to any of 12 app servers, or building Windows installers (or Windows executables, even), or tagging revisions in your SCM of choice, or easily using continuous integration servers like Hudson.

You can either help reimplement all of these things – or, if you’re lucky enough to have access to a build tool that has a community that has built all these things already, you can use that.

Handily enough, Clojure is a JVM language, so using all of the goodness that’s been built up over the years in Maven-land is extraordinarily easy to do. This means you have to write less code, and you get to use more mature, well-tested, well-supported code and tools, allowing you to focus on building awesome Clojure apps, not dicking around with implementing shell invocation, or Java compilation, or deployment via scp, or whatever “simple” build task you need today that’s been in Maven’s quiver for 5 years.

As if that weren’t enough, Sonatype has its Polyglot Maven project, where they are working on making it possible to drive Maven builds from your favorite language, be it Clojure, Ruby, Groovy, or Scala. For now, I stick to using XML POM files (they’re incredibly well-supported by tons of JVM-land tools – code completion on dependency version numbers FTW); while I love s-expressions, I’m too happy to trade off a pinch of syntactic elegance in exchange for tons more capability.

OK, enough blather. Demo-time!

With that said, let’s see what building a Clojure app using Maven looks like. First, the demo, where I start with the simplest Maven POM for building Clojure projects, and add in a Maven plugin to wrap my application into an OS X .app bundle (also available in HD):

For reference purposes, here’s that simplest of all Maven POM files you can use for your own projects:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.snowtide</groupId>
    <artifactId>easy-maven</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>Easy Clojure Maven setup</name>
    <dependencies>
        <dependency>
            <groupId>org.clojure</groupId>
            <artifactId>clojure</artifactId>
            <version>1.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.clojure</groupId>
            <artifactId>clojure-contrib</artifactId>
            <version>1.1.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>com.theoryinpractise</groupId>
                <artifactId>clojure-maven-plugin</artifactId>
                <version>1.3.2</version>
                <executions>
                    <execution>
                        <id>compile-clojure</id>
                        <phase>compile</phase>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>clojure</id>
            <url>http://build.clojure.org/releases</url>
        </repository>
    </repositories>
</project>

Further Reading

If you’re going to use Maven for your Clojure builds, here’s some links:

  1. Please make sure you check out the documentation on clojure-maven-plugin, which is where all of the Clojure-specific goals come from.
  2. You’ll do yourself a world of good by keeping the Maven books ready at hand (not the old one published years ago, BTW, the newer ones available online or through lulu). Yup, there’s a lot of material there. No, you don’t need to know it all to become super-productive with Maven.
About these ads
This entry was posted in Clojure, Maven. Bookmark the permalink.

7 Responses to Why using Maven for Clojure builds is a no-brainer

  1. gdjsky01 says:

    Maven for any project bigger than a source file quickly becomes a beast you will never tame. I have mega-projects in maven and I cringe and take downers everytime I have to modify a POM. As seen on twitter: “The difference between ant and maven is the author of ant has apologized.” Or as I have said, Maven is Native American for dependency hell. However I should mention, the plugin is a very fast way to get a clojure build environment running. Far far faster than anything else I have tried in emacs. With it, you can get a REPL up and running in no time and use swank-connect to plug emacs into it. But as a long term, large project tool, it’s like Rube Goldberg on speed.

    • Chas Emerick says:

      That’s a lot of hyperbole, but I’m heartened by this: “…the plugin is a very fast way to get a clojure build environment running. Far far faster than anything else I have tried in emacs…” That’s interesting (and I agree!), insofar as most of the substantive complaints I’ve seen about maven relate to it being difficult to get started with.

      The real question is: are those “mega-projects'” builds are so painful to work on because they use maven, or because the build process is necessarily complicated? That is, don’t confuse inherent for incidental complexity.

      • gdjsky01 says:

        Not hyperbole. Experience. But please, feel free to make the same (IMO) mistake. Wait till you need to do something slightly outside simple ‘examples’. “… don’t confuse inherent for incidental complexity.” Rich Hickey right?? Remember I am trying Clojure and fp to adopt that philosophy as best I can – undoing 25 years of C/C++/Java. I am listening (and learning.) I think it’ll make me a better engineer. However starting with a tools programmed in data interchange format (XML) is exactly the opposite of what you just quoted. Maven starts with the wrong solution and makes it work. So there we agree to disagree. YMMV. Still I enjoy your writing. People can an will disagree on the details. And yes, the plugin is a GREAT way to get going fast. And used just for that, is a ‘no-brainer’.

        • Chas Emerick says:

          I’m happy to say we’re far, far past using Maven’s “examples”. :-)

          In this case, complexity does not flow from what’s used to describe the build, it comes from the permutations of complex operations that people need in order to configure, build, and deploy their software.

  2. Name says:

    Also check out maven-clojure-plugin (http://code.google.com/p/sandflea/wiki/MavenClojurePlugin) which lets you enhance your build using Clojure scripts. It’s great for times when a suitable plugin doesn’t exist, or for working around limitations in existing plugins.

  3. Pingback: …wherein I feel the pain of being a generalist | cemerick

  4. Pingback: Adding Gzip compression to a Clojure webapp in 30 seconds | cemerick

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s