Recent entries
Recent Comments

Julian Simpson

Keep your dependencies to yourself

The average Java project has many dependencies - open source tools and frameworks, third party libraries, libraries that come from your project or organization - the list is endless. I just counted 84 jar files that my current project depends on (or may depend on!). Much pain can come from the way you manage these dependencies. Sometimes it's harder than you think to make software build or execute if it's not clear what the dependencies are. I think a lot of the pain of joining a new project and taking a day to make the code build comes from unclear code or environmental dependencies.

It's a good idea to keep your CruiseControl Enterprise installation and its dependencies clearly separated from your projects and their dependencies. So for the most basic example, lay out your cruisecontrol install something like this:

|-- cruise
| |-- 2.7.0
| `-- 2.7.1
|-- logs
| |-- blowfish
| `-- scorpion
`-- projects
|-- blowfish
`-- scorpion

Upgrading CruiseControl Enterprise should be the work of minutes.If you need to add libraries to CCE itself, this should be a warning sign that your project has dependencies it can't itself satisfy. The only exception to this rule that I can think of is custom CCE bootstrappers or publishers and the like.

There are two things in particular to take note of here: the logs and the '.ser' files. The logfiles represent the history of your project: this is why I always try to keep them in a different directory hierarchy from the CruiseControl installs. CruiseControl will also by default persist the state of its projects in files with the extension '.ser'. Make sure to keep those when you upgrade. If you do this, and your project has no dependencies on CCE, it should be simple to upgrade.

Next, think about the dependencies you have baked into your build tools. There's a common pattern of putting dependencies into your Apache Ant's 'lib' directory. For things that are hard to wire in like Junit, fine. But if your build depends on something that is actually resident in your build tool, then you have a problem. It will work today, but not necessarily tomorrow. If you upgrade libraries that your code depends on in the build tool, you can't build yesterday's code - which makes things interesting when you're trying to resolve a production bug!

The good news is, it's easy to fix: make the project contain its dependencies. For example, if your Ant build depends on Oracle (say, to support rebuild the database with the 'sql' task, and your standard project Ant build contains the Oracle drivers, your build may look like this:

<target name="drop_all_tables">
<sql driver="oracle.jdbc.driver.OracleDriver" userid="user" password="donttell" url="jdbc:oracle:thin:@localhost:1521:orcl" delimiter=";">
<transaction src="${sql.dir}/drop_all_tables.sql" />
</sql>
</target>

However in this case, the dependency on the 'in the default classpath' Oracle driver isn't stated; Ant will just look for the 'oracle.jdbc.driver.OracleDriver' class in the default classpath. The first thing to do is put the driver jar file into the project and set a classpath:

lib/
`-- ojdbc14.jar

<path id="buildtime">
<pathelement location="${lib.dir}/oracle.jar"/>
</path>

<target name="drop_all_tables">
<sql driver="oracle.jdbc.driver.OracleDriver" userid="user" password="donttell" url="jdbc:oracle:thin:@localhost:1521:orcl" delimiter=";" classpathref="buildtime">
<transaction src="${sql.dir}/drop_all_tables.sql" />
</sql>
</target>


Note the addition of the 'classpathref' attribute in the 'sql' element. This useful little attribute allows you to refer to paths elsewhere within the build, reducing duplication. When you have moved a dependency into a project, take to ceremonially deleting the dependency the moment that you can. On a project where I recently undertook this process, I was fortunate to have a regular release working in my favour. I fixed the dependencies in the trunk and revisited a few weeks later, once the release branches that depended on things outside the project weren't used.

So in summary, think about your project's dependencies, including the ones that are satisfied because they just happen to be satisfied. If you make those dependencies explicit, I promise you that you'll be asked less questions from your colleagues about why they can't compile! If you have many projects with the same dependencies, that's something that I hope to address in a future post.

©Copyright 2007 Julian Simpson. All rights reserved.

Tags : Cruisecontrol

Comments > (HTML is allowed)

  1. Sargon Benjamin
    May 24th, 2008 @ 12:15 AM

    Wow, I really needed this post. Aside from the dependencies discussion, particularly your statement: 'Upgrading CruiseControl Enterprise should be the work of minutes.If you need to add libraries to CCE itself, this should be a warning sign that your project has dependencies it can't itself satisfy'. I've been pondering on upgrading to CC 2.7.2 (for dashboard improvements) and have been worried about: - project history (this should be a non issue as my project work area is in a different directory than my cruisecontrol lib) - ant library updates with cc 2.7.2: I'm not using the ant that ships with cruisecontrol as my path is using the ant from /usr/local/apache-ant. I'm guessing cruisecontrol is using this ant lib instead of the default ant lib that ships with cruisecontrol. I'm not sure though. Either way, I'm comforted by your statement: "For things that are hard to wire in like Junit, fine" - changes in cruisecontrol.sh that I should be aware of. I don't believe I have made too many changes to cruisecontrol.sh aside from setting 'CCDIR=/opt/cruisecontrol-bin-2.7.1' and modifying the web port. I'm comforted by your article that we're not totally off track here. Thank you for the article!

Leave a Comment

Our comments policy


Products  |  Customers  |  Contact Us
Copyright 2008 ThoughtWorks, Inc.