Skip to content

Instantly share code, notes, and snippets.

@wilmoore
Last active June 21, 2017 01:42
Show Gist options
  • Save wilmoore/4742594 to your computer and use it in GitHub Desktop.
Save wilmoore/4742594 to your computer and use it in GitHub Desktop.
A build automation tool should be simple...

I am sure there are lots of strong opinions floating about regarding what a good #buildautomation tool should look like.

There are many camps; however, I will talk about the two extremes:

  1. Kitchen sink - where the trivial is awesomely simple (this is how they sell you the snake oil); however, anything even remotely non-trivial results in code bloat.

  2. Fantastically simple; albeit, barebones but you are free to use the operating system's facilities to do as you please.

I know what you are thinking...There is no way I'm relying on unix tools and shell scripts for my build automation.

Perhaps you are easily persuaded by tools that have a prescribed workflow for certain languages (Java, Groovy, C++) and have a lot of features (Gradle immediately comes to mind). To be honest, Gradle is not too horrible for a non-trivial tool; however, Maven and similar tools are much worse.

At the most basic level, a #buildtool is simply a glorified script wrapper. A build tool should generally do four things well in order to be useful and not get in the way:

  1. Executes a series of scripting tasks or small utility programs. The output of each command can be piped to the next. No crazy DSLs allowed. You should be able to copy and paste those commands into a new terminal and test their output in-line. Immediate feedback.

  2. Allow you to define task dependencies without writing classes, interfaces, or conditionals.

  3. Give you a simple way (preferably without needing to install a fancy GUI/IDE) to look at what build steps will be run without running them.

  4. Issue a sane exit status code when any of the defined steps fail.

Consequently, #4 is all that Jenkins, Travis, or any sane CI server cares about. If you have #4, your #continuousintegration server can report whether the build failed or succeeded. As a tool moves further away from these core tenets, more layers are necessary to get anything done.

Below is a simple build script using #gnumake for a #JavaScript which handles installation and #concatenation:

#################################################
# environment
#################################################
BINDIR=$(CURDIR)/node_modules/.bin
LIBDIR=$(CURDIR)/lib

#################################################
# programs
#################################################
UGLIFY=$(BINDIR)/uglifyjs --no-mangle
MOCHA=$(BINDIR)/mocha
VOLO=$(BINDIR)/volo add -nostamp -amdoff -f

#################################################
# sources
#################################################
TARGET=stream
SOURCE=$(LIBDIR)/superagent.js $(CURDIR)/index.js

#################################################
# targets
#################################################
all: $(TARGET).js $(TARGET).min.js

$(TARGET).js: $(SOURCE)
	cat $^ > $@
	
$(TARGET).min.js: $(TARGET).js
	$(UGLIFY) $< > $@
	
install:
	npm install && $(VOLO)

test:
	@$(MOCHA) --reporter spec

clean:
	$(RM) -f $(TARGET){,.min}.js

.PHONY: test clean install

If a single tool handles package management, dependency resolving, code loading, and build automation, it is no longer a single-purpose tool but rather a leaky, over-architected, and unnecessary abstraction. Unfortunately, if you squint a little, these atrocious tools actually seem useful. If you've only ever worked with over-architected tools, then this advice will be much more difficult to identify with, let alone accept. I realize this and accept that this will fall on many deaf ears.

If a tool wants its declarations written as XML, beware. XML is a horrible DSL and should not be allowed in any professional setting. It is good for other things (arguably) but please do not recommend XML as an elegant DSL. It is overly verbose and not concise at all.

If a tool publishes a fluent API, that is fine; however, please call it a fluent API, not a DSL. At best this is slightly misleading, at worse, a flat out lie.

Do not let the tool vendor sell you snake oil. Writing portable scripts is not difficult. There is no magic to it. If you accept magic, you also accept the ensuing pain when the tool fails to think for you (and it will). You may as well start thinking for yourself in the first place.

FWIW, I prefer #gnumake. It is not perfect, but it is the only tool I've found that generally doesn't get in the way and runs essentially everywhere (yes, windows too). It is also agnostic enough to fit into a polyglot environment. If you have a mono-environment, fair enough, perhaps something very environment-specific is actually right for you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment