This is now reaching the height of some ridiculousness, but this was made with a base formed through the following process:

  1. Forming an oil-based marinade with the Srichacha rub mentioned in my earlier post about the kaeng pa.
  2. Taking the remnants of the marinade which weren't absorbed by the tofu.
  3. Make a chicken stock from the carcass of a whole chicken that was leftover from making Sri Owen's ayam bakar, about which more later.
  4. When the ayam bakar is produced, it produces scorched chicken skin which melts into a mixture of rendered fat and unidentified black pieces.
  5. Combine the stock with the Srichacha marinade and the chicken skin.
  6. Raise to a rolling boil for 10 minutes for safety.
  7. Re-blend the entire mixture until smooth.
  8. Let the mixture cool, the fat will rise to the surface.
  9. Skim off all the fat, you should be able to just use a teaspoon. It will form a kind of foamy mass. You won't get rid of all of it, though.
  10. Pass the mixture through a fat separator. This will get rid of any clumps and hopefully remove remaining fat.

First cook the veggies by sauteeing them for around 5 minutes. It's good to use shallots, though you don't need any spices. Don't overcook the vegetables.

You'll now have a rather concentrated stock with a slightly bitter flavour. To form it into something suitable for soup, you simply dilute with equal amount of water (50% stock, 50% water). Then bring to the boil. Once boiling add the noodles. Do the noodles until al dente. Don't add salt.

Wait for the stock & noodle mix to cool, now add the veggies.

Posted 2017-10-17

In Emerick, Carper & Grand's 2012 O'Reilly book, Clojure Programming, they give an example of using Java interop to create JAX-RS services using a Grizzly server. These examples are now outdated and don't work with recent versions of Jersey.

Here's an updated version that is working correctly, at least for this tiny example.


(ns cemerick-cp.jaxrs-application
  (:gen-class :name cemerick_cp.MyApplication
  (:import [java.util HashSet])
  (:require [cemerick-cp.jaxrs-annotations]))

(defn- -getClasses [this]
  (doto (HashSet.)
    (.add  cemerick_cp.jaxrs_annotations.GreetingResource)))


(ns cemerick-cp.jaxrs-annotations
  (:import [ Path PathParam Produces GET]))

(definterface Greeting
  (greet [^String vistor-name]))

(deftype ^{Path "/greet/{visitorname}"} GreetingResource []
  (^{GET true Produces ["text/plain"]} greet        ; annotated method
   [this ^{PathParam "visitorname"} visitor-name]   ; annotated method argument
   (format "Hello, %s!" visitor-name)))


(ns cemerick-cp.jaxrs-server
  (:import [org.glassfish.jersey.grizzly2.servlet GrizzlyWebContainerFactory]))

(def myserver (atom nil))

(def properties
  {"" "cemerick_cp.MyApplication"})

(defn start-server []
  (reset! myserver (GrizzlyWebContainerFactory/create "http://localhost:8080/"

This uses the following Leiningen coordinates to run.

[org.glassfish.jersey.containers/jersey-container-grizzly2-servlet "2.26"]
[org.glassfish.jersey.inject/jersey-hk2 "2.26"]]

You probably also need to AOT some of these namespaces, I used :aot :all for this example.

Posted 2017-10-14

These are a few notes that I came across while trying to get GitLab CI working.

Fulfil the system requirements

There are some pretty insane system requirements for GitLab. You need at least 4GB of memory, which is not always so easy to come by in a VPS environment. Even when you fulfil the system requirements, GitLab will run out of memory and have to be "kicked" sometimes, in my experience. You could probably automate this with some kind of systemd configuration, but I haven't tried that yet.

Realize that things differ depending on your package

gitlab hosts Debian packages themselves that are more up to date, but perhaps less integrated with the rest of the system. For reasons, I was reluctant to use the packages from upstream. Instead, I used some backported versions for Jessie that were created by Pirate Praveen. You don't need to worry about this, because gitlab has migrated to stretch, so you just need to choose: use the upstream packages, or use the official Debian stable packages. You won't have problems, unless you run across features that you need from the newer versions.

Understand the GitLab CI environment

There are several things to realize about GitLab CI. The environment can differ a lot. The two primary environments are 'docker' and 'shell'. If you use docker, you build up all of your infrastructure prerequisites from a docker base image. Whereas if you use shell, your builds run under a regular shell environment, as a special (non-root) user.

Personally, I found that although docker was easier to get started with, I got benefits by moving to the shell executor, because having a preconfigured environment eliminated some run-time from the integration test suite. These problems could also have been resolved by creating my own docker base image, but that seems to be putting the cart before the horse, in a way: I already have all my infrastructure under configuration management, so why would I invest in a new method of ensuring that the docker base image meets my needs when I can address it with existing tools? Ther's also the problem that docker can't use background processes as it doesn't have a real PID1.

Understand Gitlab CI files

They're in YAML format, which is well documented. There's an existing lint tool for gitlab-ci.yml, which has stricter semantic rules than a simple YAML violation. If you do just want to validate your YAML, you can use the snippet:

validate_yaml() {
    ruby -e "require 'yaml';puts YAML.load_file(ARGV[0])" "$1"

Assuming you have ruby.

You can use "tags" to separate groups of runners. If you are trying to move from docker to shell executors or vice versa, you can set tags in a job to ensure that that job doesn't get executed on the wrong runner.

The key to understanding the execution cycle of GitLab CI jobs is that any job could essentially be executed on any runner. That means that you can't make assumptions about what files will be available at any time -- because if a job j1 executed on host mercury, when job j2 executes later on host venus then the output files produced by the build tool won't be available in venus.

There are two ways to get around this.

The first is to declare that the job has build artifacts.

  OUTPUT_TAR_PATH: "mybuild.tar"

  stage: compile
    - shell

The GitLab CI runtime will automatically make sure that $OUTPUT_TAR_PATH is copied between any runner hosts that are used to execute jobs in this build.

Another related mechanism is the cache:

  untracked: true
    - node_modules/

This is useful for JavaScript projects, otherwise you're going to end up downloading >1GB of npm modules at every phase of your project.

One last point: command under a shell list are parsed in a special way and line breaks or special characters may not always work as you expect. So far, it was mostly trial and error for me. Don't assume that you need to quote unless you try it and it fails: AFAIK, the interpreter does its own mangling to the shell lines.

Posted 2017-10-13

This is pretty thrown together, it's mostly adapted from the Rasa Malaysia recipe (despite being a Thai dish). I had Srichacha marinade left over plus some yellow curry paste from an old housemate.

There's really nothing to it: stir fry courgette and red pepper, add curry paste, use bamboo shoots and fish sauce, add coconut milk, add previously deep-friend tofu. Now you've got something insanely yummy.

Posted 2017-10-13

This is Sri Owen's ayam bakar (grilled chicken) which is rather different from many of the other Javanese style recipes that I have found online. This one requires roasting of the full chicken first, then a later grilling. It also includes the chicken breast where most recipes include the leg only, and omits the kecap manis.

Start off by roasting the whole chicken. The inside and outside is vigorously rubbed with a lemon, butter and salt mix.

After this you need to joint the whole chicken, which is not shown as it's rather gory. (You can email me and I'll send you the X-rated version.)

Creating a spicy marinade, marinating the jointed chicken and grilling at the top of the oven until blackened. The most notable thing about the marinade is that it uses terasi, shrimp paste, which you can get from Thai-focused oriental shops in the UK. This stuff is extremely pungent.

The jury's still out on the flavour of this one. Eat it with rice and cucumber slices, of course. I hope to update this post soon to give you a better idea, but there are a lot of different recipes for this widespread Indonesian dish. I think you're going to want some sambal anyway.

Posted 2017-10-12

The integration test vs unit test debate is a minefield. More particularly, see J.B. Rainsberger's talk, "Integrated Tests Are A Scam". I don't want to dig in to this particularly for this post, except to say that definitely if you are working on a greenfield project, watch that talk first.

Now for those who for reasons have to or want to do integration tests, there are several options. The fundamental problem is that databases are inherently stateful. Therefore, you need some way of getting back to a clean state at the beginning of each test.

We assume that the user is using some kind of database migration tool to manage the database development. That is that they already have "up" and "down" migrations. In this case, it's reasonable to solve the problem by doing the following:

  • Before each test:
    1. Run the "down" migrations.
    2. Run the "up" migrations.

This is relatively trivial to implement as a fixture, assuming that you are using clojure.test.

The problem comes when this becomes intolerably slow, which can easily happen once you get above 10s of migrations. Let me refer back to the Rainsberger talk now, which is a must-watch. If you want to stick with integration testing, you'll need some hack or workaround. There are several possibilities.

One possibility is using database transactional rollbacks. I found that this was impractical when interacting with real code, because of the possibility of transactions committing from within the system under test itself.

There are several guides to this method:


However I found this wouldn't work for when the code under test was using more hairy database interactions.

Another method that you can use is the following:

  • Create a template database t that already has all "up" migrations applied.
  • Assume an ephemeral database named e.
  • For each test:
    1. Drop e.
    2. Make sure that t has all up migrations applied (should be a no-op).
    3. Create e from template database t.
    4. Run test against e.

The concept of a "template database" is PostgreSQL-specific, hence the post title. In my experience, this procedure will introduce about a second of latency to each test in practice (that's a rough measurement based on my laptop). In this way it definitely precludes running the whole suite at once (and please refer back to the Rainsberger talk), but can make isolated feature development much faster.

You can see the code below. Note that some-reporter is a Ragtime reporter, which has the signature [data-store op id], as below.

(defn reporter [data-store op id]
  ; ignore data-store
  (case op
    :up (debugp "migrating" id)
    :down (debugp "rolling back %s" id)
    :else (break)))

This is the functionality, with drop-and-create being the top-level function that the fixture should use.

; If the migration already happened, these tests will be fast in any case.
(defn migrate [db-spec]
  (tracep "using authentication details" db-spec)
  (repl/migrate {:datastore  (ragtime.jdbc/sql-database db-spec)
                 :migrations (ragtime.jdbc/load-resources "migrations")
                 :reporter some-reporter}))

;; returns a vector
(defn get-drop-commands [test-databases-conf]
  (let [leaf-db-name (get-in test-databases-conf [:leaf :database])]
    [(format "DROP DATABASE IF EXISTS %s" leaf-db-name)
             (get-in test-databases-conf [:root :database])
             (get-in test-databases-conf [:leaf :username]))]))

;; also returns a vector
(defn get-reassign-commands [test-databases-conf]
  (tracep "about to reassign" true)
  [(format "REASSIGN OWNED BY %s TO %s"
           (get-in test-databases-conf [:root :username])
           (get-in test-databases-conf [:leaf :username]))])

(defn drop-and-create [test-databases-conf]
    (jdbc/db-do-commands test-db/root-postgres-db false
                         (get-drop-commands test-databases-conf))
    (catch Exception e
      (doseq [e0 e]
        (println (.getMessage e0)))))

    (jdbc/db-do-commands (merge test-db/leaf-postgres-db
                                (select-keys test-db/root-postgres-db [:user :password]))
                         (get-reassign-commands test-databases-conf))

    (catch java.sql.SQLException e
      (doseq [e0 e]
        (errorf e "unable to reassign permissions to ephemeral test role")))))

The following function also exists to forcibly disconnect other connections, because this functionality has the unfortunate property that it will fail if any other connections are already open.

;; Requires account used by the template database to have the
;; superuser privilege in postgres.
(defn disconnect-other-connections []
    (jdbc/db-do-commands test-db/root-postgres-db false 
                         "SELECT pg_terminate_backend(
                      FROM pg_stat_activity
                      WHERE pg_stat_activity.datname = 'my_ephemeral_test'
                      AND pid <> pg_backend_pid()")
    (catch Exception e
      (doseq [e0 e]
       (println (.getMessage e0))))))

All that remains is to wrap this up in a clojure.test fixture. You can use the disconnect-other-connections functionality or you can choose not to. Bear in mind that this will introduce a large amount of complexity into your test environment. Now you have to manage several databases in the test environment, as well as role name/password permissions for each one.

Posted 2017-10-12

Posted 2017-10-06

Log configuration, overall I prefer to use rather than Timbre. No particular reason, only that I feel more comfortable with it.

Here's a really basic logback.xml file that you can put in your resources subdirectory.

<?xml version="1.0" encoding="UTF-8"?>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <!-- encoders are assigned the type
         ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
      <pattern>%d{ISO8601,Europe/London} [%thread] %-5level %logger{36} - %msg</pattern>

  <!-- Show debug logs that originate from our namespace -->
  <property name="level" value="DEBUG"/>
  <logger name="websocket-clj" level="${level}"/>

  <root level="INFO">
    <appender-ref ref="STDOUT"/>

This is generally sensible, make sure that you change websocket-clj to the root of your code. Also note that only INFO or higher messages are shown from any other code. While debugging, it's not unreasonable to change this level to <root level="DEBUG"> or <root level="TRACE">. Or if a library logs too much at INFO, you can add explit exclusions for the package that issues it, as such:

<logger name="org.eclipse.jetty.server" level="WARN"/>
<logger name="org.eclipse.jetty.util.log" level="WARN"/>

The log pattern will produce lines like this, when using debugf:

2017-09-28 15:52:48,457 [nREPL-worker-0] DEBUG websocket-clj.util - foo: 42

[%thread] may be redundant for you, but it can be very useful when you have asynchronous actions occurring.

You also need these lines in project.clj.

[org.clojure/tools.logging "0.4.0"]
[ch.qos.logback/logback-classic "1.1.3"]

Personally I always use logging in every project, because non-log methods of output can sometimes suffer from strange race conditions that are generally avoided by using a logging framework. Don't spend hours debugging a problem that turns out to be an illusory artifact of the output function.

%logger{36} means that the logger will abbreviate package names after 36 characters. This can be useful, or you can just use %logger to disable abbreviation.

Note that in the pattern element, we don't use a \n to give a newline. I don't know why, but in every environment I use this in, log statements automatically receive newline termination. I'm still not entirely clear on why this happens, because it doesn't happen in a pure Java project with the same logback.xml file (although that's using Slf4j). More investigation is needed.

Posted 2017-09-28

Sometimes you want the benefits of a dynamically typed language with some of the benefits of a statically typed one.

Many languages these days encourage the user to use dictionaries or maps as a kind of loosely typed record.

These languages often differ on how they treat the situation where you look up a nonexistent key in the map.

That's because they have to conflate two different purposes.

  1. The traditional data-structurish use of maps, where the keys are usually calculated, and a nonexistent one could conceivably be valid. The classical example is a word count program. If a program looks for an unknown key in the word count map, it's reasonable to just return null, because the result will clearly be identical to nil.

  2. The record-like use of maps, where if you look up :aghe in a map with has keys :age, it's obvious a programming error has occurred.

This distinction is roughly related to the (rather outdated now) Exception/RuntimeException distinction in Java. Although the checked exception feature was such a horrible pain that many now derive from RuntimeException, the previous notion was that you avoided catching RuntimeException. The RuntimeException should kill your program, or at least the handling thread.

In the case of example 2, it's clear that (get mymap :aghe) can kill the program. However, in Clojure that expression will return nil. At some other time your code will get a wrong result. By that time, however, the stack trace may be useless.

strict-get will cause your code to break when you access a nonexistent field. This function is also known as grab in the tupelo library.

(defn grab [key_ map_]
  (let [val_ (get-in map_ [key_] ::not-found)]
    (if (= val_ ::not-found)
        (debugp "input was" map_)
        (throw (IllegalArgumentException. 
                (format "unable to grab key '%s' from map" key_))))

(defn strict-get [map_ key_]
  (grab key_ map_))

(defn strict-get-in [map_ path]
  (have! sequential? path)
  (reduce strict-get map_ path))

debugp is a personal debugging macro, feel free to replace it as you wish. Also, have! is an assertion from the truss library.

Personally, I'd love for this to become a Clojure idiom, I find it incredibly useful, especially when first writing a new piece of functionality. It's important to remember, however, that you always need to think about your intention when you do a map lookup. For me, strict-get is a good default, but I still use get, :foo, and all the others in all their various permutations.

I wrote this macro that's a simplistic version of map destructuring, but using strict-get instead:

(defn generate-strict-get [keyword input-sym]
  `(strict-get ~input-sym ~keyword))

(defn generate-let-pair [binding-sym keyword input-sym]
  `[~binding-sym ~(generate-strict-get keyword input-sym)])

(defn generate-bindings-vector [bindings input-sym]
  (->> (map (fn <span class="createlink">k v</span>
         (generate-let-pair k v input-sym)) bindings)
       (mapcat identity)

;; (strict-ds-bind {foo :bar
;;                  baz :quux} input
;;                 expr)

(defmacro strict-ds-bind [bindings input & expr]
  `(let ~(generate-bindings-vector bindings input)

When you use this form, it's obvious what's happening, and the reader knows that there's a chance that the continuation may throw at this stage. If you want to get this to indent the body properly, you can use this snippet in your .emacs.

  (strict-ds-bind 2))

Thanks to this Stackoverflow question for the main inspiration. Apparently prismatic/plumbing also calls this safe-get.

I find this so useful that I find myself writing it in JavaScript as well, YMMV though. Python is the only mainstream language that works like this by default, as far as I know.

Posted 2017-09-28

I'll do a quick round up of various libraries and implementation options here. This is based on an evaluation from early 2017, but these things aren't changing so much at present.

There are 4 wrapper libraries available on Github for interacting with the Stripe API.

  • clj-stripe
  • elephant
  • prachetasp/stripe-clojure (not evaluated here)
  • racehub/stripe-clj (not evaluated here)


clj-stripe is a library that's done in a slightly different style from many. It features heavy use of multimethods, and wrapping Stripe operations in record types. The operations are rather verbose. To do an operation you first "create" an object representing the operation and then execute it. It has the benefit of not relying on ambient state. In the end I didn't use this library, because it was too cumbersome.

I ran into some problems with old TLS versions when running on Java 7. However, hopefully, Java 7 is a distant memory by the time you read this.


Elephant is a supposedly "modern" library. In practice I found that it was somewhat clumsy to work with. It uses global state, in the form of the set-api-key! function. It delegates to the Java wrapper library, which then wraps the REST API.

There are some weird things in working with the Elephant API. When you submit calls to the API, you often use string keys in the map you are passing:

(ecr/create {"source" token "email" email})

This is a little abnormal for a Clojure API and seems to be an indication of an abstraction leak. (Actually Clojure is full of abstraction leaks, so it wouldn't be alone, but I found this one rather distracting.)

But, when you get results from the Elephant APIs, the keys are automatically "keywordized".

There are also some cases where you seem to need to do unnecessary calls in order to perform certain actions, as in this example:

(defn change-payment-source! [stripe-customer-id token]
  (ecr/update (ecr/retrieve stripe-customer-id) {"source" token}))

Notice that we do two REST operations here. There's surely little point in this network traffic (not that it matters so much in this case). I don't know the REST API well enough to comment on if it's possible to do this in a single network request, but I can't see why it wouldn't be possible? However, Elephant requires a specially-tagged map that was returned from a previous Elephant call as the first argument -- it can't take a plain ID.

The representation of result maps is also slightly confusing in itself -- the maps seem to contain a fully "mapped" keywordized version of the data, as well as a full string copy of the actual response? This is a tad awkward when trying to read the data at the REPL.

Things that it wasn't possible to do with these

  • Neither library has wrapper code for Stripe events, which you are pretty much guaranteed to need if you need to handle subscriptions.
  • There's no way to get the total count of GET-collection operations.
  • There's no way to manually trigger payment of an invoice. ( in the Java API.) This can be useful when testing.
  • There's no automatic paging of results, which can be a touch tricky to implement: for instance it's easy to just block until everything is returned and process everything in a loop. But how long are you willing to block for? Or would you prefer to pass some kind of callback or async action and process results a page at a time? The possibilities are endless.

Lessons learned

Elephant is quite easy to use for basic use cases. I can't remember where I read this before, but some previous author said not to use wrappers when interacting with external REST APIs in Clojure, and I almost tend to agree. Overall, the time I spent dealing with the various quirks and imbrications of these libraries probably outweighed the time it would take to create my own wrapper. And don't forget that you have even more options: as well as the two libraries not surveyed here, you can also use the Java API through introspection, or go directly to REST. If I did it again, I think I'd go directly to REST. And so probably end up creating library number 5...

Posted 2017-09-26

This blog is powered by coffee and ikiwiki.