Vote for Clojure as the Most Innovative Java Technology of 2011!
Dependency Management First-Aid Kit
This article attempts to unravel some of the mysteries of dependency management with Maven and Maven-based tools.
Help, something’s missing!
Say you have a project named “my-new-project” which declares a dependency on version 3 of the “awesome-sauce” library by the Example.com corporation. You add the dependency to your pom.xml, project.clj, or whatever configuration file your build tool uses. You take a deep breath and start a build. And it fails!
If you’re using Maven 2, you see something like this:
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] Failed to resolve artifact.
Missing:
----------
1) com.example:awesome-sauce:jar:3.0.0
Try downloading the file manually from the project website.
Then, install it using the command:
mvn install:install-file -DgroupId=com.example -DartifactId=awesome-sauce -Dversion=3.0.0 -Dpackaging=jar -Dfile=/path/to/file
Alternatively, if you host your own repository you can deploy the file there:
mvn deploy:deploy-file -DgroupId=com.example -DartifactId=awesome-sauce -Dversion=3.0.0 -Dpackaging=jar -Dfile=/path/to/file -Durl=[url] -DrepositoryId=[id]
Path to dependency:
1) my.group:my-new-project:jar:1.0.0-SNAPSHOT
2) com.example:awesome-sauce:jar:3.0.0
----------
1 required artifact is missing.
for artifact:
my.group:my-new-project:jar:1.0.0-SNAPSHOT
from the specified remote repositories:
central (http://repo1.maven.org/maven2),
clojars (http://clojars.org/repo/)
Leiningen, which uses Maven 2 under the covers, produces similar output, but it mistakenly prints the current project name as org.apache.maven:super-pom:jar:2.0.
Maven 3 prints a less verbose (and less informative) error message, but the gist is the same.
What happened?
What is all this verbosity saying? Well, obviously, the build failed because something was missing. What was missing? Maven tells you:
Missing: ---------- 1) com.example:awesome-sauce:jar:3.0.0
The JAR file for the project “awesome-sauce”, version 3.0.0, published in the “com.example” group, is missing. That just means Maven didn’t find it in any of the places it looked.
Where did it look? Maven tells you that too:
from the specified remote repositories: central (http://repo1.maven.org/maven2), clojars (http://clojars.org/repo/)
These are the public repositories where Maven searched for the file. Each repository has an ID (“central” and “clojars” in this case) and a URL. Both are specified in the configuration of:
-
Your project, in pom.xml or project.clj
-
Your build tool’s global configuration file
- settings.xml for Maven
- N/A for Leiningen
-
Your build tool’s built-in defaults
- The Maven Central Repository for almost any Maven-based tool
- Clojars for Leiningen
If you visit http://repo1.maven.org/maven2/com/example/awesome-sauce or http://clojars.org/repo/com/example/awesome-sauce in a browser you will see that those directories do not, in fact, exist.
Although it’s not listed, the first place Maven checks for a dependency is your local Maven repository. The local repository is just a big cache of everything Maven has downloaded in the past. It’s typically located at $HOME/.m2/repository.
What to do next
You have two options at this point:
- Find a public repository containing “awesome-sauce”
- Install “awesome-sauce” in your local repository
The first option is generally less work, and more repeatable if you ever build your project on another machine.
Finding a repository
Odds are, if the library you are looking for is free, open-source, and popular, it will already be in a public Maven repository somewhere. Start with the source: who released the library? Large organizations with a lot of open-source projects often host their own repositories, like Google and Codehaus. Failing that, search engines such as Mvnbrowser may help you find it.
Once you’ve found a repository, you need to add it to your build. For example, to add the Codehaus repository to a Maven project, add these lines to pom.xml inside the <project> tag:
<repositories>
<repository>
<id>codehaus</id>
<name>Codehaus</name>
<url>http://repository.codehaus.org/</url>
</repository>
</repositories>
(You can pick your own <id> and <name>.)
For Leiningen, add the following lines inside the (defproject ...) block:
:repositories {"codehaus" "http://repository.codehaus.org/"}
Installing locally
If the library you want is not available in any public repository, you’re not stuck, you just have to do a bit more work. You need to get the JAR file for the library, either by downloading it manually or building from source. Then you need to install that JAR file in your local Maven repository. That’s easy, because Maven has already told you exactly how to do it:
Then, install it using the command:
mvn install:install-file -DgroupId=com.example -DartifactId=awesome-sauce \
-Dversion=3.0.0 -Dpackaging=jar -Dfile=/path/to/file
Copy that command verbatim, changing only /path/to/file to the path to the library’s JAR file. Maven will copy the file to $HOME/.m2/repository/com/example/awesome-sauce/3.0.0/awesome-sauce-3.0.0.jar. The next time you build your project, Maven knows exactly where to find it.
Installing remotely
If you want others to be able to build your project without having to go through these manual steps, you need your own public Maven repository to which you can upload files. Hosting a Maven repository isn’t hard: all you need is a web server.
If you work with a team, consider setting up a shared repository for everyone to use. A repository manager such as Nexus can help you take care of user accounts and authentication.
If you publish open-source libraries, I strongly encourage you to get an account on Sonatype OSS, a free service provided by the makers of Nexus. Releasing your projects to Sonatype OSS gives them a path to get added to the Maven Central Repository. While the requirements for projects in Maven Central are more stringent than just tossing code into your own repository, it’s worth the effort. In Maven Central, your project will have greater visibility and will be easier for anyone in the world to use.
But what if I don’t want that dependency?
Maven dependencies are transitive: if your project depends on project X, which depends on projects Y and Z, then your build will try to download X, Y, and Z.
But sometimes projects declare dependencies that aren’t strictly necessary. Or they declare dependencies on something you want, but the wrong version. How can you avoid including those extra dependencies in your build?
Maven supports dependency exclusions for these cases. For example, suppose the “awesome-sauce” library declares a dependency on “com.example:stupidity:0.0.1″. You know that you don’t need “stupidity” in your project, so you want to prevent the build from including it. In pom.xml, you write:
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>awesome-sauce</artifactId>
<version>3.0.0</version>
<exclusions>
<exclusion>
<groupId>com.example</groupId>
<artifactId>stupidity</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
Or in Leiningen’s project.clj, you write:
:dependencies [[com.example/awesome-sauce "3.0.0"
:exclusions [com.example/stupidity]]]
Note that once you start using exclusions, you’re on your own. It’s up to you to make sure you still have the correct versions of all the libraries your project needs.
On rare occasions, a project’s dependencies cannot be resolved at all. In particular, if you need two different versions of the same library with the same class names but incompatible APIs, you’re pretty much stuck. Time to refactor, or investigate multiple-Classloader schemes like OSGi. But that’s a whole ‘nother story.
Speaking at ÜberConf Denver in July
I’ll be speaking at Über Conf 2011 In Denver, CO July 12th to 15th.
I’m doing three (gulp!) sessions: two on Clojure, and one on my work with AltLaw.org.

Clojure in Philadelphia, April 27-28
I’ll be talking about Clojure at Emerging Technologies for the Enterprise in Phidelphia, April 27-28, 2011.
My talk is tentatively titled Clojure: Lisp for the Real World, and it will be a high-level overview of how Clojure’s unique features can solve real, pervasive problems in large software systems.
Edit Quotient
Remember Levenshtein Distance: the number of changes to turn one string into another? Here’s a naïve implementation in Clojure:
(defn levenshtein [s t]
(let [m (count s)
n (count t)
d (make-array Integer/TYPE (inc m) (inc n))]
(dotimes [i m] (aset-int d i 0 i))
(dotimes [j n] (aset-int d 0 j j))
(doseq [j (range 1 (inc n))]
(doseq [i (range 1 (inc m))]
(if (= (.charAt s (dec i)) (.charAt t (dec j)))
(aset-int d i j (aget d (dec i) (dec j)))
(aset-int d i j (min (inc (aget d (dec i) j))
(inc (aget d i (dec j)))
(inc (aget d (dec i) (dec j))))))))
(aget d m n)))
(assert (= 0 (levenshtein "" "")))
(assert (= 3 (levenshtein "foo" "foobar")))
(assert (= 3 (levenstein "kitten" "sitting")))
(assert (= 3 (levenstein "Saturday" "Sunday")))
I ripped that straight off Wikipedia’s pseudocode. Not functional at all, and probably not particularly efficient either.
But I’ve never seen this: the number of changes to turn one string into another, scaled by the lengths of the strings. Call it the “edit quotient,” computed as the Levenshtein Distance divided by the mean of the lengths of the two strings. The edit quotient of two empty strings is zero.
(defn edit-quotient [s t]
(let [sum (+ (count s) (count t))]
(if (pos? sum)
(/ (levenstein s t)
(/ sum 2))
0)))
(assert (= 0 (edit-quotient "" "")))
(assert (= 0 (edit-quotient "foof" "")))
(assert (= 1 (edit-quotient "foo" "bar")))
(assert (= 6/7 (edit-quotient "foof" "bar")))
(assert (= 2/3 (edit-quotient "foo" "faa")))
(assert (= 2/7 (edit-quotient "foof" "foo")))
(assert (= 1/2 (edit-quotient "foobar" "faabir")))
This has some interesting properties. The edit quotient is zero if the two strings are completely identical, one if they are completely different. Values in between zero and one give some idea of how different the strings are.
Single Abstract Method Macro
John Rose’s article, Scheme in One Class, introduced me to the notion of Single Abstract Method, or SAM, classes. One of the proposed APIs for JSR-292 allows a MethodHandle (the Java version of a closure) to be cast to any SAM class.
In Java, a SAM can be either an interface or a class, but if it’s a class then it’s usually abstract. The interface or class has exactly one method. Callbacks are often specified as SAM interfaces. The standard Java library has lots of SAM interfaces, such as Runnable and ActionListener.
In Clojure, it’s easy to interoperate with these Java interfaces with reify (or proxy for abstract classes) but it’s tiresome to type out. Since reflection can give us the name of the method, why not let the compiler do the work for us?
(defmacro single-method
"Returns a proxied or reified instance of c, which must be a class
or interface with exactly one method. Forwards method calls to the
function f, which must accept the same number of arguments as the
method, not including the 'this' argument.
If c is a class, not an interface, then it must have a public,
no-argument constructor."
[c f]
{:pre [(symbol? c)]}
(let [klass (resolve c)]
(assert (instance? java.lang.Class klass))
(let [methods (.getDeclaredMethods klass)]
(assert (= 1 (count methods)))
(let [method (first methods)
method-name (symbol (.getName method))
arg-count (count (.getParameterTypes method))
args (repeatedly arg-count gensym)]
(if (.isInterface klass)
`(let [f# ~f]
(reify ~c (~method-name ~(vec (cons (gensym "this") args))
(f# ~@args))))
`(let [f# ~f]
(proxy [~c] [] (~method-name ~(vec args) (f# ~@args)))))))))
The Expression Problem in Clojure
My article for IBM developerWorks has been published: “Solving the Expression Problem with Clojure 1.2″
Hair Color
An antisocial experiment to answer that age-old question: who really has more fun?
On Google, “blondes” get the most attention with 147 million hits. ”Brunettes” get 78.6 million and “redheads,” 12.8 million.
However, of the three, only “redheads” start off with lovingly hand-crafted images, suggesting that while people like to read about blondes and brunettes, they mostly like to look at redheads.
On Facebook, Brunettes have a commanding lead with 79,132 fans versus the comparatively meager 27,039 fans for Blondes.
However, brunettes seem to have a serious inferiority complex vis-a-vis blondes, as witness the more popular pages Brunettes are better then blondes (120,192 fans) and, more emphatic but less grammatic, BLONDES ARE “”"NOT”"” AS SEXY AS DARK HAIR GIRLS ! ! ! (90,417 fans).
Even the number of people on Facebook who think Brunettes are sexier than blondes! (18,255) is larger than the number who think Redheads do it better (16,637).
However, those of us who do admire redheads take it very seriously: two of the top-ranked redhead fan pages are classified as “Religious Organizations.”
Beware Choosing the Most Complex Tool for the Job
I once saw a TV show about competing groups of archeologists trying to demonstrate how the ancient Egyptians raised stone obelisks weighing hundreds of tons.
One group of archeologists built a complex apparatus involving a wooden frame and lots of rope. It looked impressive, but it didn’t work.
The other team built a sand pit, dragged the obelisk to the top, and gradually removed sand from below the obelisk until it reached its final position. Simple, unglamorous, and it worked on the first try. (See the whole series of photos.)
The leader of the wooden-frame group admitted they were mistaken in basing their design on the most complex ancient technology they could find, sailing ships. Instead, he said, “We should have asked, ‘What is the simplest way they could have done it?’”
***
From the ancient Egyptians, jump forward about four thousand years to me, sitting at my computer, writing a new testing framework for Clojure. I was excited about the new Clojure features datatypes and protocols. I based my whole framework around them. It was a beast. Lots of weird edge cases and complex interactions that were hard to reason about and even harder to debug. Datatypes and protocols may be a powerful tool, but that doesn’t always make them the right tool.
After my fourth or fifth rewrite of Lazytest, I started asking myself, “What is the simplest way I could do this?”
The answer was staring me in the face. Clojure is a functional language (mostly). What’s the simplest way to do anything? Functions!
All of a sudden, complexity started to fall away. My protocols, most of which only had a single method anyway, became ordinary functions. My typed data structures became ordinary maps. The code shrank by many lines, and it was vastly easier to understand. Even better, I discovered new possibilities in the simpler design.
Functions are a fantastic abstraction because they can be composed. In the new Lazytest, everything is a function: test cases, test suites, and contexts. The RSpec-like describe macros are still there, but they’re simpler. They do what macros are supposed to do: provide a convenient syntactic layer over functional definitions, not define a completely new language.
I haven’t completely finished the new API — fixtures, now renamed back to “contexts,” are not supported yet. But I’m much happier with this version than with the old one. I actually feel like this is something I’d be willing to release soon. So give it a spin and tell me what you think.
Assertions and Invariants
I’ve been thinking a lot about testing frameworks over the past six months, and I’m not the only Stuart doing that. Stuart Halloway, who spent some time on his own Clojure testing framework, Circumspec, recently wrote about his experiences refactoring some of the language tests included with Clojure.
One of Stu’s first points is that Clojure’s assert macro doesn’t provide enough context when an assertion fails. It doesn’t tell you why the assertion failed.
That’s exactly why I wrote the is macro in clojure.test. But, as both I and the other Stuart have noted, the macros in clojure.test are too tightly intertwined with the reporting framework. So I started working on Lazytest and the expect macro.
Stu made an improved assert that reports the current values of local variables. I’ve incorporated that feature into expect. Thanks, Stu!
***
The next takeaway from Stu’s post is that thinking about invariants — properties that must always hold — is a good way to design tests. Invariants are the basis of Haskell’s QuickCheck, which Meikel Brandmeyer adapted as ClojureCheck.
I really like the idea of invariants, although I think invariant properties are more likely to be found in highly abstract, mathematical domains than in, say, web applications. But Stu’s point is that there isn’t a good place to put invariants. Complex invariants can take a long time to evaluate, so you don’t want to run them in production code. But some assertions are cheap, and important, so you do want to run them in production code.
Stu asks if we need a “new thing.” Perhaps that new thing is assertion levels, like logging levels. Level 1 could be for simple, quick checks like argument types; level 2 for more involved consistency checks, and so on. The assertion level, rather than simply assertions on/off, could be specified at compile time.
***
There’s more to say Stu’s post, and about testing in general, but that will have to wait for another day.

