Here's a quick little Clojure1 macro I've started using.
The Book Feed is a new website I've put together where you can write short book reviews, and optionally post them to Facebook. When testing, I don't want the post-to-Facebook code to run while I'm developing, or my Facebook account would fill up with test-data. It should really only run in production.
That's straightforward to code in any language. I write some kind of
isLive()
function, then wrap the relevant code in
if ( isLive() ) {.... }
. Easy, right?
Well, in Clojure we can go one better. Take a look at this code:
(defn is-live? [] ...)
(defmacro if-live [function & args]
`(if (is-live?)
(~function ~@args)
(println "DEVELOPMENT Skipping:" '~function ~@args)))
...then later in my code I replace:
(post-to-facebook data1 data2 ...)
...with:
(if-live post-to-facebook data1 data2 ...)
At first glance this looks like syntactic sugar. It's super-short, but is it really any better than what we'd say in something like Java?
if (isLive()) {
postToFacebook(data1, data2, ...);
} else {
log.debug("DEVT Skipping: " + data1 + " " + data2 ...);
}
Well, yes. This macro is significantly better, and not just because of
all the typing it saves. The if-live
macro has a magic property we'd
struggle to get in other languages: Instead of just skipping the code,
or printing a generic debugging message, it prints the exact code and
arguments it would execute were we in production. In other languages
we're stuck with the tedious problem of keeping the log message & the
call in sync with each other2.
But because Clojure code can be treated as regular data, it's trivial to print the call instead of executing it. With no effort, I can see exactly what the call would send to Facebook, without worrying about keeping the debug message in sync with the function call.
Yay macros.