Describe Your Data Transformation
Sep 16 2016
One of my favorite features of Clojure is the thread macro. I think there are two reasons I continue to reach for it over and over again.
- It promotes the idea of “data transformation”.
- I find it can be extremely readable.
This post is focused on #2.
Let’s look at an example. Below is a function that transforms a string into a slugified keyword.
(defn slugify-title [title]
(keyword
(string-lower-case
(string/replace
(string/replace title #"[^\w\s]" "")
#"\s+" "-"))))
I find this to be quite difficult to decipher. I have to search for the inner most function call and then work my way out while keeping the track of the context.
A more intuitive way to represent this is with using the thread macro.
(defn slugify-title [title]
(-> title
(string/replace #"[^\w\s]" "")
(string/replace #"\s+" "-")
string/lower-case
keyword))
While the function is semantically equivalent, the implication is different. The visual representation here implies a data transformation. When we reorganize our function to use the thread macro, our data transformation becomes obvious.
However, we can still do more to describe our transformation.
(defn strip-punctuation [title]
(string/replace title #"[^\w\s]"))
(defn delimit-words-with-dashes [title]
(string/replace title #"\s+" "-"))
(defn slugify-title [title]
(-> title
strip-punctuation
delimit-words-with-dashes
string/lower-case
keyword))
This is much more descriptive. Each function describes its own roll in the transformation, and the overall transformation become much more transparent.
My own rule of thumb is that if a function call in a thread macro is not totally obvious, then it should be wrapped in a named function.
Thread macro can make your data transformations extremely readable, especially when the extra step is taken to give the transformations a meaningful name.
Recent Articles
- Apprenticeship Retro Oct 14 2016
- What the hell is CORS Oct 13 2016
- Cross-site Tracing Oct 11 2016
- Learning Testing Tools First Oct 7 2016