The Disco Blog

Can you dig it?

Continuous Integration Is a Hack!

Continuous Integration is a hack!” said my friend Ben Rady years ago during a discussion on CI hosted by Stelligent. At the time, I was incredulous! How dare someone question the value of CI, especially when we had just finished writing a book about it! What’s more, our book had been nominated for a prestigious Jolt award; indeed, the following day, our CI book won it!

In retrospect, Ben’s point was poignant: CI is reactionary. You still have to wait some amount of time to ascertain correctness. That is, CI implicitly relies on a passive process to run a project’s build and any corresponding tests. If those tests fail, you are of course, notified. Nevertheless, that notification is somewhat delayed: by the time a CI process runs the tests and reports on their status, you’ve already moved on to the next task. So much for failing fast!

On the other hand, if tests, which are arguably the quintessential proof of valid integration, are run continuously, then there’s no wait time to ascertain issues! Ben’s stance is really no surprise (especially if you know him) as he went on to play a major role in Infinitest and co-author Continuous Testing: with Ruby, Rails, and JavaScript. I’ve come to realize Ben’s wisdom since then and have become a huge fan of Continuous Testing.

A more proactive means to ensuring all is kosher with a code base is to continuously run your tests as you work. In fact, an even more superior process would be to run any tests for code that has changed. That is, once a mapping has been established between code under test and a corresponding test, then when that code changes, the quickest, arguably most effective way to ensure that code isn’t broken is to run its test(s).

One efficient way to ascertain mapping is to name tests after the code they verify proceeded with a test moniker. For example, an Account object would have its corresponding test called AccountTest (or AccountSpec, etc). Any time the Account object changes, then the AccountTest would be run.

Continuous Testing is an established practice in the world of Ruby. A great framework that facilitates it is called Guard. Briefly, Guard is a framework for watching a file system and sending out a notification upon some event (like a change). With Guard, you can define specific file matching patterns and a corresponding action to take when an event is triggered. You can probably see that this linkage facilitates running tests continuously.

There’s really no corollary framework or tool in Java (other than Infinittest and other IDE tools). Nevertheless, you can use Guard to continuously test a Java project. I wrote about how to do it with an Android over two years ago and about 6 months ago I got involved in a Guard plugin for Gradle, dubbed Guard::Gradle.

To use Guard::Gradle, you’ll need to have Ruby installed. For those on OSX, you already have Ruby. Once you have Ruby installed, the installation of Guard::Gradle couldn’t be more easy: just open up a terminal in your desired Gradle project and type:

Simple installation!
$ curl | bash -

The above command will download a script and execute it. That script will:

  • Install Ruby’s Bundler
  • Install the Guard::Gradle plugin
  • Create a default Guardfile
  • Create a Guard launcher script, dubbed

Therefore, after you run the above command, just execute to start Guard::Gradle! Any time you change a file in your source tree, a corresponding test will be executed using the Gradle test task.

The default Guardfile assumes a standard Gradle project setup, with source code located in src/main. In fact, if you are curious, take a look at the generated Guardfile and you’ll see:

Default Guard::Gradle Guardfile
guard :gradle do
  watch(%r{^src/main/(.+)\.*$}) { |m| m[1].split('.')[0].split('/')[-1] }

That watch command examines the src/main directory and attempts to execute a matched file’s test. If no test is found, all tests are run. So either way, if a change happens, you’re covered with some amount of tests. which ostensibly updates your local directory with all upstream changes). Consequently, if upstream changes have broken your local branch, you’ll know instantly. No more need to remember to “run the tests” – they’re always running.

Of course, Continuous Integration isn’t a hack. But Ben made a prescient point back then: if you want to fail fast and shorten the time to detect failures, why not do it at the source? Why not know instantly while you’re working instead of some later time after you’ve moved on? Assuming your project has tests, then Continuous Testing is the answer. Continuous Testing is the proactive yin to CI’s reactive yang.

Check out Guard:Gradle today and know instantly when you’ve made a breaking change! Now that’s something everyone can dig, right?