(elegant coding from a more civilized age)

Lisp++

Emacs and GChat

| Comments

I was chatting with a friend on GChat today. I found having to context switch to my browser so much to be distracting, and half-jokingly and off-handedly said: “I should setup my Emacs with GChat”.

A little Googling led me to Emacs Wiki: GoogleTalk.

These are the steps I used to get GChat running pretty quickly:

  • M-x package-list-packages, installing ‘jabber’
  • add the below to my init.el
1
2
3
4
(setq jabber-account-list
  '(("my.email@gmail.com"
     (:network-server . "talk.google.com")
     (:connection-type . ssl))))

  • brew install gnutls since I’m on OSX
  • M-x jabber-connect-all, entering in my password at the prompt
  • Then I can switch to the *-jabber-roster-* buffer, search for my friend’s name in the list, and hit RET to start a chat with them.

Mass Clojure File Formatting With Emacs Batch Mode

| Comments

I do not profess to be a master of Emacs Lisp. But after some time googling I figured out how I can mass code-format the code on some of our large projects at work.

It is pretty likely that you may need to tweak this to get it to work on your machine. Specifically, you’ll have to point the script to the correct location of you clojure-mode installation.

This script calls emacs in Emacs in —batch mode, which causes Emacs to run non-interacively. We can use --batch to allow us to write scripts using Emacs. Awesome, I know. :–)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash

find "/path/to/your/project/." | while read file
do
    if [[ "$file" =~ ^.*\.clj$ ]]; then
        emacs "$file" \
              --batch \
              --eval="(progn 
                        (load \"~/.emacs.d/elpa/clojure-mode-2.0.0/clojure-mode\")
                        (require 'clojure-mode) 
                        (clojure-mode) 
                        (indent-region (point-min) (point-max)) 
                        (save-buffer))"
    fi
done

ShellCheck

I recently discovered ShellCheck, a static analysis and linting tool for sh/bash scripts. When I ran it on the original version of my above script it found a number of issues. I really recommend you use it on your own scripts.

Original Script

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/sh # bad, because I was using features on ly available in bash

## can cause unexpected behavior
for file in `find /path/to/your/project/.` ## `'s deprecated
do
    if [[ $file =~ ^.*\.clj$ ]]; then ## [[ ]] only works in bash
        emacs $file \                 ## ... surround $file with "'s
              --batch \
              --eval="(progn 
                        (load \"~/.emacs.d/elpa/clojure-mode-2.0.0/clojure-mode\")
                        (require 'clojure-mode) 
                        (clojure-mode) 
                        (indent-region (point-min) (point-max)) 
                        (save-buffer))"
    fi
done

A Mathematical Jaunt via San Mateo Parking Meters

| Comments

Theeee other day some colleagues and I drove into downtown San Mateo for lunch. An interesting decision had to be made: how many quarters to pay the meter.

The price for parking is $0.25 per half hour. Your penny-pinching instincts suggest to only put in 2 quarters. Let’s say that a parking ticket for going over the meter is $40.

Breaking Down the Scenario

Let’s apply a little reasoning and mathematics to this, situation and see what’s the right amount of quarters to put into the meter.

There are 5 possible outcomes:

  1. pay $0.50, go under one hour, no ticket: total price $0.50
  2. pay $0.50, go over one hour, no ticket: total price $0.50
  3. pay $0.50, go over one hour, get ticket: total price $40.50
  4. pay $0.75, go under one hour, no ticket: total price $0.75
  5. pay $0.75, go over one hour, no ticket: total price $0.75

Conservative Guesstimates

Now the fun part. Let’s assign rough guesstimates of likelihood for each outcome.

Let’s be generous and say that you only go over one hour 20% of the time, and only 20% of the times you go over do you get a ticket.

Let’s also say that you pay $0.50 half the time and $0.75 half the time.

  1. 40% probability x $0.50 = $0.20
  2. 8% probability x $0.50 = $0.04
  3. 2% probability x $40.50 = $0.81
  4. 40% probability x $0.75 = $0.30
  5. 10% probability x $0.75 = $0.075

Computed average cost: $1.425

Even at the conservative rate of ticketing of 20% of time you go over an hour, you still increase your expected rate of pay to almost double, by choosing to pay $0.50 half the time!

With Vigilant Meter Maids

If instead you think you’ll get a ticket 75% of the time you go over, the average cost per park becomes a whopping $3.625

  1. 40% probability x $0.50 = $0.20
  2. 2.5% probability x $0.50 = $0.0125
  3. 7.5% probability x $40.50 = $3.0375
  4. 40% probability x $0.75 = $0.30
  5. 10% probability x $0.75 = $0.075

Computed average cost: $3.625

So it looks like in general it pays to be safe and pay the extra quarter when parking in downtown San Mateo.

Further Precision

We could expand this further, by considering likelihoods of lunch going over 1.5 hours. I didn’t because I think there’s diminishing returns on investment because the odds of going over 1.5 hours are probably only like 20% of 20% => 4%… I’ll leave that as an exercise for the reader :)

IO as Data

| Comments

One way to make your Clojure code easier to test and to reason about is to quarantine your IO. Amongst your team decide where you think the acceptable boundaries for IO are, and then don’t do any IO except in those layers. In my opinion the place to do IO is in the service layer, as described in Amit Rathore’s talk at Clojure/West, Domain-Driven Design With Clojure.

What this can lead to is code patterned where instead of executing IO straight away, you instead compute IO IOUs: a pure function determines that some piece of IO should occur, and returns that fact encoded in some form of data.

A Basic Example

Say we have a map that tracks the inventory changes at a warehouse. It typically looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
(def an-example-inventory
  {:items {12345
           {:product-id 12345
            :product-name ""
            :quantity 300
            ;; ...
            }}
   :actions {:order-from-factory []}}) ;; this is where the IO data goes

(defn remove-item-from-inventory
  [inventory {:keys [product-id] :as item}]
  (if (some-> inventory :items product-id :quantity count (> 0))
    (update-in inventory [:items product-id :quantity] dec)
    (update-in inventory [:actions :order-from-factory] conj product-id)))

Then at a later stage of processing this code, at an outer layer that deals with IO, we can look over the actions on the inventory map and processes them accordingly.

Ramifications of This Style

A cool side effect of this is that if you want to change how your IO gets evaluated it will all be in a handful of well-defined places. This makes switching out implementation details easier. Also, it makes converting to asynchronous IO more straightforward if the IO becomes a blocker to the performance of the system.

Your code becomes less coupled to implementation details of your IO, and instead talks more about the computed intended effects. Unit testability of the system goes up, because everything except the service layer, is just pure functions and data.

The Evolution of a Macro

| Comments

At Runa, where I work, I work on a very large Clojure application which we service online merchants with in order to deliver real-time promotions to the browser. The runtime promotion determination core of the application is quite intricate and has both stateful and immutable parts. If not tested properly, you can make the mistake of letting any setup mutable state effect tests other than the intended test case.

I thought it’d be fun to walk you through how I developed a macro to handle this type of situation at work. I think it is a pretty interesting example of how macros can evolve and what considerations might go into how you architect a meaty macro.

NOTE: The code has been simplified from the production code to better emphasize the important points.

First Stab At a Stateful Test Macro

Our first stab at this problem solves the basic initial version of the problem. Often this would be all you need to get the job done. This approach enables us to evaluate our test assertion from within a stateful scope, and we use the finally block of the try-catch to ensure that the rules are always set back to their original state when the test is done.

1
2
3
4
5
6
7
8
9
10
11
(defmacro with-rules [rules & body]
  `(let [old-rules# @rules]
     (try
       (reset! rules (evaluate-rules ~rules))
       ~@body
       (finally
         (reset! rules old-rules#)))))

(deftest test-priority-level
 (with-rules (def-rule priority-level 5)
  (is (= true (priority-level 5)))))

Then if we have some other sort of state, for example machine learning models, we can write another with-models macro and combine the macros in a test.

1
2
3
4
5
6
7
8
9
10
11
12
13
(defmacro with-models [models & body]
 `(let [old-models# @models]
  (try
   (reset! models ~models)
   ~@body
   (finally
    (reset! models old-models#)))))

(deftest test-model-and-level
 (with-rules (def-rule priority-level 5)
  (with-models {:a [1 2 3 4 5 6]
                :b [7 8 9 10 11 12]} ;; insert fancy math stuff here ;)
   (is (= true (found-promotion? (legal-customer-session)))))))

Before I make a serious change to the approach we use for this kind of macro, let’s remove the bloat from these macros and make them lean mean macros with beefier functions to go with them.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
(defn with-rules* [rules body-fn]
 (let [old-rules @rules]
  (try
   (reset! rules (evaluate-rules rules))
   (body-fn)
   (finally
    (reset! rules old-rules)))))

(defmacro with-rules [rules & body]
 `(with-rules* ~rules (fn [] ~@body)))

(defn with-models* [models body-fn]
 (let [old-models @models]
  (try
   (reset! models models)
   (body-fn)
   (finally
    (reset! models old-models)))))

(defmacro with-models [models & body]
 `(with-models* ~models (fn [] ~@body)))

Why? Because macros are harder to read, and not composable.

This way of approaching the stateful setup and teardown in our tests gets the job done, but has a couple issues. As soon as we have another source of state we need another with-x macro, and when we combine these together we end up over time with code that looks like this.

1
2
3
4
5
6
7
(deftest test-motherload
 (with-x X
  (with-y Y
   (with-z Z
    (with-a A
     (with-b B
       (is (= 42 (evaluate)))))))))

What I really want here is one macro not 5! I’d like something I can easily extend as new forms of state come up.

Composing Functions For A More Extensible Approach

What if we could write test-motherload like this:

1
2
3
(deftest test-motherload
 (with-runtime-state {:x X :y Y :z Z :a A :b B}
  (is (= 42 (evaluate)))))

And ideally if a C type of state comes up down the line, it’ll be straightforward to extend this macro to accomodate it without pulling your hair out dealing with #’s, ~’s, @’s, ‘’s and `’s.

With a minor change to with-rules and with-models we can enable them to be used to compose 0-arity functions into other 0-arity functions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(defn rules-setup-and-teardown [rules body-fn]
 (fn []
  (let [old-rules @rules]
   (try
    (reset! rules (evaluate-rules rules))
    (body-fn)
    (finally
     (reset! rules old-rules))))))

(defn models-setup-and-teardown [models body-fn]
 (fn []
  (let [old-models @models]
   (try
    (reset! models models)
    (body-fn)
    (finally
      (reset! models old-models)))))

We can take the testcase evaluation function and transform it into a function that when called will wrap the evaluate-test-case function in setup and teardown of the rules state.

1
2
3
(rules-setup-and-teardown
  '(def-rule priority-level 5)
  (fn [] (evalute-test-case)))

And we can chain these function compositions together, to incorporate more varieties of setup and teardown as necessary. Note we don’t need no fancy macros for this (yet).

1
2
3
4
5
6
7
8
9
10
(deftest test-model-and-level
 (let [testcase-fn (fn []
                     (is (= true (found-promotion?
                                   (legal-customer-session)))))
       wrapped-testcase-fn
         (->> testcase-fn
              (rules-setup-and-teardown '(def-rule priority-level 5))
              (models-setup-and-teardown {:a [1 2 3 4 5 6]
                                          :b [7 8 9 10 11 12]}))]
   (wrapped-testcase-fn)))

Remember what we’re aiming for is something more like this:

1
2
3
(deftest test-motherload
 (with-runtime-state {:x X :y Y :z Z :a A :b B}
   (is (= 42 (evaluate)))))

This is going to require us to convert the state map, {:x X :y Y :z Z :a A :b B}, into the appropriate setup-and-teardown wrapper functions, and do the wrapping of the body of the macro as well.

The first definition option->setup-and-teardown-fn, maps keys from the state map to its corresponding setup-and-teardown function.

1
2
3
4
5
(def ^:private option->setup-and-teardown-fn
 "Add new setup and teardown wrappers here, and the `with-runtime-state`
  macro automatically gets a new functionality"
 {:rules #'rules-setup-and-teardown
  :models #'models-setup-and-teardown})

Finally the macro that makes it all fit together. If you look closely, it macro expands into something very similar to the composed function solution above.

1
2
3
4
5
6
7
8
9
10
(defmacro with-runtime-state [options & body]
 (let [setup-and-teardowns
    ;; 1. map each key of the state-map to its a setup-and-teardown fn
    (for [[k state-value] options]
     `((fn [f#]
       (let [setup-and-teardown# (get ~option->setup-and-teardown-fn ~k)]
        (setup-and-teardown# ~state-value f#)))))]
  ;; 2. thread the testcase body fn through each wrapper fn, and eval it
  `((-> (fn [] ~@body)
     ~@setup-and-teardowns))))

We can make the macro more user friendly with a couple of asserts on the args passed to it. These kinds of assertions are especially nice in macros, because they help make the macro’s unique syntax easier to use for your teammates without them pulling their hair out.

Also, we can be improve it one step further. We’ll use clojure.core/partial to create the 1-arity setup-and-teardown functions, rather than wrapping each of them within the for expression.

1
2
3
4
5
6
7
8
9
10
11
12
(def ^:private runtime-test-option-set (set (keys option->setup-and-teardown-fn)))

(defmacro with-runtime-state [options & body]
 (assert (map? options)
     "Options should be a map.")
 (assert (every? runtime-test-option-set (keys options))
     "Options should have :rules and/or :feature-bits keys")
 (let [setup-and-teardowns
    (for [[k state-value] options]
     `((partial (get ~option->setup-and-teardown-fn ~k) ~state-value)))]
  `((-> (fn [] ~@body)
     ~@setup-and-teardowns))))

Refactoring Addendum

I thought a little more about this and realized that even this macro is doing too much. We can actually extract the code that wraps a 0-arity function f in setup-and-teardown functions. In the process we end up with a macro with one line of code that does the heavy lifting and a few more lines of asserts.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(defn wrap-in-setups-and-tear-downs [options f]
  (let [setup-and-teardown-fns (for [[k state-value] options]
                                 (partial (get option->setup-and-teardown-fn k)
                                          state-value))]
    (reduce (fn [f' setup-and-teardown-fn]
              (setup-and-teardown-fn f'))
            f
            setup-and-teardown-fns)))

(defmacro with-runtime-state [options & body]
  (assert (map? options)
          "Options should be a map.")
  (assert (every? runtime-test-option-set (keys options))
          "Options should have :rules and/or :feature-bits keys")
  `((wrap-in-setups-and-tear-downs ~options (fn [] ~@body))))

This is a useful step because now we have another higher order function with which to build useful state-management tooling, and we’ve eliminated more of the potentially confusing macro code.

Takeaways

So why go to all this trouble?

  • We’ve written a macro that is extensible.
  • We’ve minimized actual lines of macro code. Yay!
  • We get validation of the state-map keys for free, anytime we extend this with a new setup-and-teardown function.
  • Our tests have a clean, uniform, minimal DSL for expressing pre-requisite mutable state.

How did we do it?

  • We took an essentially functional compositional approach.
  • We wrapped it in a layer of syntactic sugar.

Hope you enjoyed this little code walk through.

Comments or questions?

Slamhound 1.3.0 - Cleaning Up All Your Namespaces

| Comments

Cleaning up namespaces in Clojure is a chore. So noone does it, and the namespaces get worse.

Enter Slamhound. Slamhound’s a library by Phil Hagelberg (the Leiningen guy) that attempts to reconstruct a namespace for a file.

For a while now Slamhound has been pretty unusable, do to it not having a good heuristic for figuring out which namespace to use for a require/as clause. For me, it would fail on most real-world namespaces I tried it on.

Over Christmas break I decided to get it working again, because I was pretty sick of fixing up legacy namespaces by hand. It now works, and also, as an added bonus, converts all your uses to requires, as per the Clojure 1.4 good practice.

The original Slamhound reconstruct function returned a string representing the new namespace, but it was still tedious to run it on 50+ namespaces and copy-n-paste the new namespaces in.

For this reason, I decided to automate the process. Long story short, the slam.hound namespace in version 1.3.0 now also has a -main function that takes a file or directory and replaces the namespace and writes it back to the file, or to all the files in the directory. Like magic.

Also, if you’re on Leiningen 2 you can define a partial alias:

1
:aliases {"slamhound" ["run" "-m" "slam.hound"]}

and then call it from within your project’s root directory:

1
$ lein slamhound .

Then take a look at the diff for your repo. You’ll see a lot of files have been altered.

Caveats: Slamhound is still not perfect. It can lose metadata, or comments in the namespace form, and sometimes it picks the wrong dependencies to use in a namespace.

Reducing Complexity

| Comments

I had written some complicated looking code at work recently (shhh, let’s keep that between us ok?). Something about it didn’t seem right to me, but I was busy at the time so I wrote a TODO to come back and find a way to make it simpler.

Since the code is so confusing it is virtually impossible to read at a glance and understand its intent, I will explain what it does. It takes in a map where the keys are numbers of days over a given SLA, and the values are the number of shipments that were over the SLA by that amount of days. The map actually can and does have more keys on it than that, but for the purposes of this article we can ignore them. The function takes that map and converts it to a version where the values are not counts of the individual SLA, but instead the current running percentage totals.

An example:

1
2
3
4
5
(cumulative-percentage-past-SLA-map
  {:past-SLA-1 2 :past-SLA-2 1 :past-SLA-3 3}
  4
  10)
;; => {:past-SLA-1 0.60 :past-SLA-2 0.70 :past-SLA-3 100.0}

What makes this code end up so complicated is that it is complecting three things: generating the series of sums, dividing them, and creating a new map to return.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
(def all-past-SLA-x-keys [:past-SLA-1 :past-SLA-2 :past-SLA-3])

(defn- cumulative-percentage-past-SLA-map
  "Takes a count-based report and generates percents that accumulate."
  [count-based-past-SLA-map met-SLA total-shipments]
  (-> (reduce (fn [[past-SLA-map total-past-SLA-so-far] days-past-key]
                (let [updated-past-SLA-map
                       (update-in past-SLA-map
                                  [days-past-key]
                                  #(/ (+ total-past-SLA-so-far %)
                                      total-shipments))
                      updated-total-past-SLA
                        (+ total-past-SLA-so-far
                           (get past-SLA-map days-past-key))]
                  [updated-past-SLA-map updated-total-past-SLA]))
              [count-based-past-SLA-map met-SLA]
              all-past-SLA-x-keys)
      first))

The solution is to break those 3 parts up.

First we generate the series of sums using reductions.

Second, we divide each by the total to convert them to percentages.

Thirdly, we create a new map with percents as the values instead of counts.

1
2
3
4
5
6
7
8
(defn- cumulative-percentage-past-SLA-map
  "Takes a count-based report and generates percentages that accumulate."
  [count-based-past-SLA-map num-met-SLA total-shipments]
  (let [counts (map #(get count-based-past-SLA-map %) all-past-SLA-x-keys)
        running-totals (rest (reductions + num-met-SLA counts))
        percents (map #(/ % total-shipments) running-totals)]
    (zipmap all-past-SLA-x-keys
            percents)))

Another thing you might notice in this code is that I purposely used the more verbose #(get count-based-past-SLA-map %) when I could have just used count-based-past-SLA-map, as it is already a function! I prefer to err on the side of making my code as obvious as possible, so I try to avoid using data structures as functions except under a few special cases. But I guess that would be a different topic for a different blog.

The Many Faces of Midje Fakes

| Comments

The Midje Clojure testing library enables top-down development, and the primary tool it has for enabling it is the fake.

In Midje, you don’t have mock objects like you do in object-oriented languages, instead you fake out functions. The simplest way you can fake out functions is by using the provided form within your fact.

Fakes

1
2
3
4
5
6
7
8
9
(unfinished doubler)

(defn six-times [x]
  (* 3 (doubler x)))

(fact
  (six-times ..n..) => 12
  (provided
    (doubler ..n..) => 4))

(Things that look like ..x.. are called Midje metaconstants. For now just pretend they are constants, or skip to the end of this article for a link to the wiki.)

In the above example we’ve managed to define six-times in terms of a function, doubler, that is not yet defined (it is unfinished).

Presumably the next thing we’d do when designing a piece of software like this is to write the fact for doubler.

1
2
3
4
(fact
  (doubler 2) => 4)

(defn doubler [n] (* 2 n))

Or perhaps write a more thorough test:

1
2
3
4
5
6
7
8
9
10
(tabular
  (fact (doubler n) => result)

  n    result
  -2   -4
  -1   -2
  0    0
  1    2
  2    4
  100  200  )

(Tabular is a way to write one fact that runs against multiple input sets.)

The Myriad Uses of Fakes

Fakes have other uses besides simple stubbing.

They can also be used to verify call counts. Imagine that you want to check that when some data is not valid there are no calls to send-email, but otherwise there will be 1 call sent to each recipient?

We can write this kind of test using the :times n prerequisite option. (where n is some non-negative integer)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
(fact "don't send emails when data is invalid"
  (email-job :alex :brian) => irrelevant
  (provided
    (valid-data?) => false
    (email anything) => nil :times 0 ))

(fact "when data is valid send one email to each recipient"
  (email-job :alex :brian) => irrelevant
  (provided
    (valid-data?) => true
    (email :alex) => nil :times 1
    (email :brian) => nil :times 1 ))

;; The implementation

(unfinished valid-data? email)

(defn email-job [& dudes]
  (when (valid-data?)
    (doseq [d dudes]
      (email d))))

Checkers

Using checkers we can even expand on the idea of what can be checked by a provided. In the above examples first we used the anything checker to check that the email function was never called with anything. Then we simply checked that the email function was called with :alex and :brian once each.

In this example we want to check that the query function is called with 10 things that look like query maps. To do that we first need to create our own checker that checks whether the parameter looks like a query.

1
2
(defchecker a-query [actual]
  (and (:target-db actual) (:query-plan actual)))

Midje will say that any arg matches this checker if it has a non-false/non-nil :target-db and :query-plan.

Let’s confirm query is called 10 times with params that look like queries.

1
2
3
4
5
6
7
8
9
10
11
12
13
(fact "always sends 10 queries"
  (execute-queries) => irrelevant
  (provided
    (query a-query) => irrelevant :times 10))

;; The implementation

(unfinished query)

(defn execute-queries []
  (dotimes [_ 10]
    (query {:target-db :foo       ;; this will pass because it looks like a-query
            :query-plan :bar})))  ;; but (query {:another "map"}) would not pass

The Fake Chain Gang

If you’ve ever violated The Law of Demeter in an object-oriented language and then tried to use mock objects with the offending class, you may have experienced a chain of mocks.

A chain of mocks is when you mock a method on a mock object that itself returns another mock object, that has a method on it mocked to finally return the value you want.

1
2
3
when(mockA.call()).thenReturn(mockB);
when(mockB.call()).thenReturn(mockC);
when(mockC.call()).thenReturn(42);

In Midje the naive approach might be to write something like:

1
2
3
4
5
6
7
8
9
10
11
12
13
(fact
  (foo) => 42
  (provided
    (baz) => ..a.. ;; remember, just pretend they're constants
    (bar ..a..) => ..b..
    (qux ..b..) => 42))

;; The implementation

(unfinished baz bar qux)

(defn foo []
  (qux (bar (baz))))

Midje supplies a feature called Folded Prerequisites that enable a nice condensed syntax for this, though it is probably a code smell if you are doing this too often.

1
2
3
4
(fact
  (foo) => 42
  (provided
    (qux (bar (baz))) => 42))

Fakes That Cover Multiple Facts

There are other ways to make fakes in Midje as well, by using the background macro and the against-background macros. These give you the ability to write fakes that cover a group of fakes. I think I’ll talk about them in another blog though time permitting.

Wiki Links

TDD in Midje in a Nutshell

| Comments

Midje is a Clojure testing library supporting a top-down mock function style of development, but also equally well supports a bottom-up style.

This is an introductory article, and depending on the response, there will be more articles about some of the intermediate and advanced features.

Elegant Examples

Midje starts with a simple premise: that tests should be elegant and readable.

When was the last time you saw code samples like this in somebody’s blog, gist, or book?

EXAMPLE:

As you can see the foo function always returns: a-ham-sandwich

1
2
(foo :bar :baz)
;; => :a-ham-sandwich

As developers, I think we write examples like this, because it reads well to us. We’re used to this sort of pseudo-code example style, and so we can all tell at a glance what’s happening.

This is where Midje enters. The below is executable Clojure Midje code:

1
2
(fact "the foo function always returns :a-ham-sandwich"
  (foo :bar :baz) => :a-ham-sandwich)

You can take that code, and run it, now, and if you’ve defined foo, then you can run lein midje or use midje-mode in Emacs to confirm that foo does in fact always return :a-ham-sandwich. (Forget for now that this particular fact doesn’t very well cover every possible input. Using a generated test input style of testing could be very useful here, but that is for another blog.)

Describing Code That Doesn’t Exist – Yet

Let’s try describing some code that doesn’t yet exist with these kinds of examples. I think if we jot down some example cases, it will help us think more clearly about what we’re trying to get our code doing.

1
2
3
4
5
(fact "doubles odd numbers"
  (my-func 3) => 6)

(fact "triples even numbers"
  (my-func 4) => 12)

We can run these examples now. First thing you’ll notice is that we’re getting errors; that’s of course because we have not yet written any code. Let’s add the my-func function.

1
(defn my-func [n] )

Let’s be cautious and just try to get one of these facts working first.

1
2
(defn my-func [n]
  (* 2 n))

This seems to work… but for only the first fact. (There’s a lot to be said for how effectively TDD can help you to stay focused on the task at hand.)

So let’s get my-func to pass the second fact as well.

1
2
3
4
(defn my-func [n]
  (if (odd? n)
    (* 2 n)
    (* 3 n))

Running those examples again with lein midje or midje mode, we see that they do indeed pass.

But there’s one more thing. There is a little bit of duplication left in my-func. Let’s take a second, and refactor this a little.

1
2
3
(defn my-func [n]
  (let [multiplier (if (odd? n) 2 3)]
    (* multiplier n))

Now that we’ve revealed a new concept of a multiplier in our code, it looks like we are done. Our code works as advertised.

TDD Recap

You just learned:

  • how to use Midje facts as a form of executable examples
  • how to do TDD. Nice.

I was sneaky just then. Without letting you know what I was doing, I’ve walked you through the 4 steps of TDD. Decide what you are testing, write a failing test, make that test pass, refactor the code to have a good design.

TDD Steps:

  1. We chose a new piece of functionality we wanted the code to have.
  2. We wrote a failing test. We ran it. We saw it fail. In Midje, we like to think of this step as taking some time to describe the facts of the future version of the code.
  3. We wrote as little code as possible to make the test pass. In Midje, we think of this step as bringing the code up to date with the new facts.
  4. We took some time to reorganize the code – giving it better structure, removing duplication, adjusting the naming, etc. Repeat.

That’s TDD in Midje in a nutshell.

What did you think? Interested in hearing some more intermediate or advanced TDD and Midje concepts and exercises?

Technicalities

1
2
3
4
5
6
7
8
9
10
11
12
;; project.clj  
(defproject my-project "0.1.0"
  :dev-dependencies [[lein-midje "1.0.8"]
                     [midje "1.4.0-SNAPSHOT"]])

;; example with ns macro  
(ns my-ns.t-core
  (:use my-ns.core
        midje.sweet))

(fact
  (foo :bar :baz) => :a-ham-sandwich)