Monday, April 13, 2009

Reason 1: Get your libs-folder out of SVN

This post is a part of a tiny series I'm doing on why we use Maven, and you should too.

Previous posts:


The libs folder


We have a libs-module in Subversion. When you check out the source code for our main product, this is one of the modules you get. It contains a hundred-and-some JAR-files. These are the dependencies for the sum of our modules:

fizz-project
\
fizz-core
fizz-web
fizz-libs
\
junit.jar
spring.jar
common.jar
Downloading all these MB's of JAR files is something you'll have to do no matter which build system you use, so bandwith cost isn't an argument. Subversion also uses binary diffs, so copying or changing a JAR file doesn't increase repository size significantly.

The problem arises when you want more than one product. As soon as you want to split your product into two applications (or services), each project needs its own libs-folder:

fizz-project
\
fizz-core
fizz-web
fizz-libs
\
junit.jar
spring.jar
common.jar
woop-project
\
woop-core
woop-web
woop-libs
\
junit.jar
spring.jar
common.jar
By doing this, we almost efficiently duplicate our dependencies. While each project can manage its own dependencies without fearing for breaking functionality in the other project, efforts to maintain the libs is duplicated. All upgrading, figuring out bugs, transitive dependencies will have to be done in two places.

The alternative is to introduce a global libs folder:
fizz-project
\
fizz-core
fizz-web
woop-project
\
woop-core
woop-web
global-libs
\
junit.jar
spring.jar
common.jar
... but unfortunately this would over time become a giant heap of libs of different JAR files in different versions, and for even the tiniest project you would need to check out the entire global-libs folder. Because you have no hard linking to which project a lib belongs, you can not actively do cleanups and get rid of unused JARs. Over time, it would grow to be hundreds of MB, perhaps even GB, containing every JAR file of very version all the products of the company ever used.

So neither of these approaches are particularly tasty for an organization with a large codebase and number of projects. The first approach enforces all-source-code-in-one-build with one gigantic sluggish workspace in your Eclipse, while the second enforces one gigantic global-libs JAR folder that everyone hates to download and deal with.

Maven's solution to this: There is one global JAR-repository like in the second approach, but download is done lazily. Each project has meta-data for which JAR-files it needs, and only upon building a particular project are the needed JAR-files downloaded from the company JAR-repository. Also, JAR-files are cached and referenced in a local Maven repository on each machine, so if you are working on three projects that use junit3.jar, you only have one junit3.jar in your ~/.m2/repository directory.

Additionally, Maven support inheriting dependency management. You can define parent projects that define dependencies, and have different projects inherit these.

This post is already long enough for publishing, so I'll continue next week with Reason 2: Clean up your JAR-files.