Build Automation Software is still just Software

Whenever you move out of your cozy Java (-Language)/Eclipse/Maven comfort zone you recognize there is a whole plentitude of build systems coming with different environments. While you would probably associate the classic Java language with ant or Maven (or even 5000+ lines of BASH scripts written a hundred years ago), the polyglot programmer must be aware of:

  • Scala and SBT
  • Groovy and Gradle (becoming more and more popular in Java)
  • Clojure and Leiningen
  • (J)Ruby and Rake

Leaving the JVM community, there’s still C/C++ with Make (with the beloved  automake, autoconf & Co.), NANT for .NET and certainly a lot more.

How languages rub off on their build tools

There seems to be a strong need to leverage the feel and the qualities of the production language to the build system. The bad properties get inherited, too:

  • Ant and Maven rely heavily on XML (remember EJB 2.x?) and I remember that internally, domain values  are mostly Strings.
  • Non-trivial Gradle scripts lead to these “Oh, there is a coniditionally dynamically added method that makes just the release artifacts for the customers fail.”
  • SBT forces you to leave blank lines – wonder when tabbed punchcards come back.
  • Leiningen invents yet another syntax for GAV coordinates.

Business risks of 3rd party tools

Especially one-man shows and small companies should think about the impact of having yet another third-party tool that needs updates twice a year:

  • Maven Plugins have defects fixed in features that you don’t actually use and defects introduced in features your business relies on.
  • The Maven Release Plugin is still not the right way to do continuous delivery.
  • Testing of Maven plugins was cumbersome and still is no fun.
  • Using String ${properties} and not objects that provide the proper level of abstraction remains the source of many hacks in build scripts. javaCompilerConfiguration.invokeJavaC(buildChain, context) is quite different from setting untyped properties for a Maven plugin, right?

Why you might want to roll your own Build Automation System

Many people still think that programming in a general purpose language and programming by configuring a model are basically two different things. They are not. Anneke Kleppe introduced the term Mogram, which is a portmanteau of Model and Program. Think of JSON, which is data as a program. You are not configuring Maven or Gradle, you are programming them.

The problem with, say, a Maven pom.xml is, that it is hard to test its abstract behavior. Does it generate all the artifacts with the content we expect? While the plugin might be correct, you might have missed a configuration parameter or set up a wrong (or no) base path. I am always afraid when someone changes the build system – did they do more than a manual smoke test after the last-minute-change?.

Test-First development of your Build Automation System

Build Automation is extremely relevant for the delivery of the final product, still it is often treated as a kind of glorified AUTOEXEC.BAT: The build system people tinker around with plug-in configurations in the pom.xml like in the old MS-DOS days. But it’s real software!

So, why not treat it as a first class citizen? Having an easily maintainable, customized process written in your production general purpose language prevents 1500+ line build files (your coding stanadard says ~200 lines per unit max, right?), hard coded values and doomsday events on important releases.

A few Ideas

  • Use Test-First Development, TDD, all of it. I want my build system to be at least as good as the final product – when it has a defect or is not exensible I cannot deliver my products with the desired quality or in time.
    • The machines that build a consumer product often outlive the product they build for economical reasons.
  • Apply the same (or even more strict) design and coding rules.
  • Look out for self-similar structures. Even a Build Tool needs a Build Tool – but usually just not that complicated.
  • Do not use Language A to build Language B (except when A is a subset of B).  You will have more tools that may behave wrong after an innocent update.
  • Leverage compiler type checks (an ArtifactId is pretty well defined…) and IDE auto-completion.
  • Favor small build tasks over the Maven do-it-all-and-in-one-file approach (try configuring Maven to distribute an artifact to 5 different repositories, depending on different conditions.).

And please: Don’t invent yet another embedded DSL: A ten line build script is something you only find in textbooks (just like SELECT * FROM ORDERS …).