Build Refactoring: Delete Boolean Property

(image taken from Kurtis Scaletta's photostream)

Last time, you read about the extract target refactoring. Today, I'm going to show you one that I love to perform: delete boolean property. Have a look the smell first:

<project default="unit_tests">

	<property name="junit.enabled" value="true" />

	<target name="-check_junit_enabled">
		<condition property="junit.really.enabled">
      <and>
        <equals arg1="${junit.enabled}" arg2="true" />
      </and>
    </condition>
	</target>

	<target name="unit_tests" if="junit.really.enabled" depends="-check_junit_enabled">
		<mkdir dir="build/test-results"/>
		<junit>
			<test name="FooBarImplTest" todir="build/test-results"/>
			<classpath>
				<fileset dir="build"/>
				<fileset dir="lib"/>
			</classpath>
			<formatter type="xml"/>
		</junit>
	</target>
</project>

This smell starts out with the notion of properties to control the execution of your build. So far so good. "Hang on", someone pipes up: "If you're going to have a property, I want to be able to set it to values like 'true' or 'false'". With more work you manage to express the logic in Ant. Each target now needs to depend on at least one other to set the properties that control the execution of the build. This rapidly turns the build into dependency soup.

You also have to set two properties: the one that has the boolean value, and the other that exists to actually signal to your build tool that it should run a target.

How do you resolve this? Start deleting all those extra targets that ensure that the right properties are set. Like this:

<project default="unit_tests">

	<target name="unit_tests" unless="junit.disabled">
		<mkdir dir="build/test-results"/>
		<junit>
			<test name="FooBarImplTest" todir="build/test-results"/>
			<classpath>
				<fileset dir="build"/>
				<fileset dir="lib"/>
			</classpath>
			<formatter type="xml"/>
		</junit>
	</target>
</project>

What do you have to change in the targets that do the work? Just choose a decent property name to put in the if or unless tags and then delete any dependencies on targets that resolve properties. I decided that the default behaviour should be running the unit tests. To opt out you can pass the argument -D:junit.disabled=foo onthe command line.

So what about the person who wanted the boolean properties? Either:

  • Make them support the build,
  • Write a custom Ant task to do all this, and make it run in the body of the Ant build file and not inside a target. I'll even write one for them if they dig deep enough.

Happy refactoring. If you like this post, my article on Ant Refactoring is available to buy in the ThoughtWorks Anthology:


DevOps New Zealand