Last week I posted an article on the future of Java build tools, which received lots of positive feedback both here on this blog and on JavaLobby. That post focused more on the differences between various build tools and advantages of one over another. This week I decided to follow up with an article, which instead will talk about something that all kinds of software have in common: the risk of feature creep (in the context of build tools).

Feature creep in action

Feature creep in action

Build scripts are very fragile pieces of software. They are treated differently than other programs that we write. The companies coding rules rarely apply to code written in XML, and refactoring or testing build scripts is something that’s hardly ever done. Because of that, it’s often easier to break the build by changing the build logic, than it is by changing application logic (the other one happens more often, but that’s because the application code is changed way more frequently).

The other problem, which is sometimes mentioned as a main headache with build scripts, is their complexity. Scripts can get thousands of LOC long, split (chaotically) over a dozen or more files. Can you imagine the pleasure of debugging those, when something starts failing?

In my opinion fighting complexity of build scripts can be done two-fold:

  • by using a better build tool
  • by reducing the scope of the script

Compared to regular application development, picking a build tool (Ant, Maven, Gradle, etc.) is more or less like choosing a programming language: you consider IDE support, friendliness of the syntax, sometimes performance characteristics (rarely ever done for build tools, though). There’s also your team’s qualifications, and more often than not, your companies standards (so the choice can be completely out of your hands).

On the other hand, there’s reducing scope, or managing feature creep if you will. The more your build script does, the longer and more complex it becomes. The more features you add over the time, the less maintainable it comes to be. This leads to conclusion that the smaller the scope, and the rarer the changes to it are, the better.

Build scripts can range from the most ascetic, which only build and package the application, to the most byzantine, which will download the applications sources, compile, package, test, generate reports, generate and upload documentation, install all prerequisites on the build and deployment machines and finally deploy and run the built application. As the CI servers grow in popularity, it is possible to do more and more with appropriate plugins instead of home-made build scripts, but while they help reducing the scope a little, there’s still a lot of stuff that they can not do.

It seems reasonable to ask: what should a build script actually do then? Should it stick to the very basics? Does it make sense to have A-Z build scripts which can do everything with a single command? I wish I could give you an answer to those questions right here and right now, but I can’t. The feature list of a build script is in my opinion heavily dependent on the application itself, and the technologies in use.

One thing that could possibly help fighting the feature creep, is defining what the build script should do in advance. What reports are relevant to this project? Should the script be able to deploy the application, and if yes, which deployment scenarios should it support? Should it just generate, or also upload the build artifacts, like .jar files or documentation somewhere? What kind of notifications should be implemented, and so on. With this, a build script once created, should be left relatively unchanged. However, this seems rather restrictive, and definitely not “agile” at all.

The more agile approach could be by mimicking what has been done in the Grails framework, which has a very friendly integrated build system (based on Gant), which can be easily extended. As Grails is very keen on “convention-over-configuration”, the commands reside in appropriately named files, thus helping you find the code you’re interested in easier. The separation is cleaner, and adding your own command is unobtrusive and straightforward. The problem here is mostly time, because rolling a build system like that on your own is definitely harder than using something “out of the box”.

So the best practices I can name are: do as little as possible, but as much as necessary and keep your build code in bite-size, easily identifiable pieces - not one 10k LOC build file, but maybe dozens of small files named by convention. Not much, huh? That’s why I’m counting on you, to comment on this post, and share your opinions.

Can you share any good/bad practices for build scripts? Do CI servers make your life easier, and if yes, how so, and which one do you use? How often does your build script change? Do you have any particular way of organizing your build scripts?

Waiting for you feedback,

Adam

PS. Thanks to Pete Johnson for inspiring me to write this:)

Share/Save/Bookmark

Posted in ant, project management at March 2nd, 2009. by Adam 'Psyho' Pohorecki 6 Comments.