Joker: Flex Your Scripting Muscles In (Almost) Clojure
Tags: clojure, scripting, joker
Published: 2019-06-07 20:07:08

---
title: Joker: Flex Your Scripting Muscles In (Almost) Clojure
published: true
description: Joker is a scripting language based on Clojure
tags: clojure, scripting, joker
canonical_url: https://dev.to/hlship/joker-flex-your-scripting-muscles
---

If you read enough dev blogs, and have a touch of imposter syndrome,
it starts to look like our field is full of Uber-coders who can constantly
switch gears between, say, writing machine learning code in Python,
complex user interfaces in JavaScript and React, and then jump down and throw together a quick device driver in C. For fun, I imagine these Uber-coders then go home to write retro-games in 6502 assembly.

These people probably exist.  I am not one of them. I've coded professionally
in many languages, everything from C, to PL/1, to Java, to Lua. But for day-to-day work, I *specialize*. I like [**Clojure**](http://clojure.org). And I'm terrible at switching gears and languages, unlike my mythical Uber-coder.
 
Clojure is *intensely* good at what it does: REPL oriented development,
functional thinking, data transformation, and leveraging existing Java libraries.

But you don't write shell scripts in Clojure, even if you are as hopeless at Bash scripting as me. 

Not that you don't want to, it's just that startup time is an obstacle: all the JVM startup time, plus all the Clojure startup time, plus all the time to load whatever libraries you need.

It adds up.

If you are working on an application, you may only fire up your REPL once in an entire day, so this startup time is inconsequential. But if you are writing a *script* ... either a throwaway, or something to  help you automate your environment, you don't want to be twiddling your thumbs waiting for that script to load (even a one second wait can feel like forever).

That's why [Joker](https://github.com/candid82/joker) is such a revelation; Joker is an interpreted dialect of Clojure, written in Google's Go, intended **just** for scripting: we use it internally on my team for all of our automation.

Nearly everything that makes Clojure amazing exists in Joker, including immutable data types, macros, and dynamic typing, and the vast majority of Clojure's core library.

Joker starts up *very* quickly:

```
> time joker -e '(println "There and back again")'
There and back again

real	0m0.050s
user	0m0.038s
sys	0m0.017s
```

That's virtually instantaneous. By comparison, Clojure has a noticable start up time:

```
> time clj -e '(println "A price must be paid")'
A price must be paid

real	0m1.011s
user	0m1.695s
sys	0m0.124s
```

Better yet, [Joker is batteries included](https://candid82.github.io/joker/): it has a selection of built-in libraries, that cover all of your typical tasks, including sending HTTP requests, JSON and YAML encoding, basic cryptography ... all the things you need to, say, work with Amazon AWS.

One feature near and dear to me is `joker.tools.cli`, a port of Clojure's 
[clojure.tools.cli](https://github.com/clojure/tools.cli) library. This is *first class* support for GNU-style command line options.

## Using Joker

Let's say you got yourself a sweet job working for the Department of Defense, and wanted to create a script to control a few things at NORAD:

{% gist https://gist.github.com/hlship/58651f64d8d4e128038dd947326740a9 %}

You can name this file `norad`, and make it executable (`chmod u+x norad`).

Because we made this a first class script, with properly parsed options, we can ask `norad` what it does:

```
> norad --help
norad OPTIONS

  -d, --defcon VALUE  Set DEFCON level
  -v, --version       Show version information
  -h, --help          Show this summary
```

That's a relief; a sloppy script that expected the user to remember its non-standard options might have changed the DEFCON to null, or launched some missiles or something. Real options can be a safety net.

And even though this script is non-trivial, it's still hella fast:

```
> time norad --defcon 3
Setting DEFCON to 3

real	0m0.086s
user	0m0.088s
sys	0m0.020s
```

And as someone who crusades for good **feedback** from my tools and libraries, it's great to see this:

```
> norad -d 0
norad OPTIONS

  -d, --defcon VALUE  Set DEFCON level
  -v, --version       Show version information
  -h, --help          Show this summary

Errors:
Failed to validate "-d 0": level must be 1 to 5
```

... even in a throwaway script. More safety net.


## How it Works

That first line:

```
#!/usr/bin/env joker
```

That's standard Posix for "find the `joker` command and run the rest of the file through it". Any additional arguments to the command will be provided in `*command-line-args*`, a sequence of strings.

Because this is a script, and not a program, there's no `main`; there's just Clojure _forms_, evaluated one after another.

The `ns` form is convenient for bringing in the other built-in libraries that are needed. We gave this namespace the name `script`, but that's pretty arbitrary.

The next few forms define constants and utility functions needed to parse command line options and perform actions based on them. A real implementation of `set-defcon` might, for example, send an HTTP request to update the big display in the war room.

The last form, the `let` block, is where the real work starts; this is where those command line arguments are parsed into options, and then actions are dispatched.  This is all very familiar to any Clojure programmer.

But that's it.  No `main`. No classes. No compilation. No CLASSPATH. No overhead.  Just your code, in (very nearly) The One True Language, but running instantly.