Clean Clojure: Meaningful Names
I came to 8th Light for a chance to write Clojure, and in the last few weeks, the lofty dream of slinging s-expressions during my day job has finally come true. (Apprentices are compensated at a flat rate of $0.002 per parenthesis). After spending three months learning rules and practices for writing clean object-oriented code, I’m now mapping them to functional programming. Over the next few posts, I’ll try translating some of the guidelines for clean code to Clojure. Like any style guide, there will be room for opinion, so don’t hesitate to leave comments or offer suggestions.
Clean Code is worth the cover price for Chapter 2 alone. Its advice is simple: use meaningful, clear names that reveal intent. This rule probably seems obvious, but the value is in its side effects. Taking the time to scrutinize every name requires the sort of mindfulness and thought that produces clean code. In addition to Uncle Bob’s general guidelines for good names, here are a few Clojure-specific rules on naming.
Clojure’s categorical imperative: act in the Kingdom of
Functions do things, and their names should describe the things they
do. This is usually an easy rule to follow, but functions that build
or return data structures can be tricky.
Make-user-map is better
Render-footer is better than
But nouns are useful
Verbs are great, but they’re even greater when they have objects. A name like
remove-temporary-files is much clearer than
Nouns are also useful inside functions. I find my tolerance for
repetition far lower in Clojure than in other languages: if I use an expression more
than once, I’ll almost always put it in a
let binding and give it a
name. Inside functions that compose multiple transformations on some
data structure, extracting intermediate steps into values in a
binding can be very helpful.
1 2 3 4 5
Good nouns are also helpful when destructuring
values, which is awesomely useful but sometimes hard to read. Prefer
putting them in
let bindings to cramming them in the argument list,
except for very simple cases.
1 2 3 4 5 6 7 8 9
And okay fine, also adjectives
The one first-class exception to verbs everywhere is adjectives for
predicates (functions that return
seq?). These should always end in question marks and always return
Use the best name…
Clojure has a large set of core functions, and sometimes the clearest name for a function will collide with one of them. Use it anyways! This is why namespaces are useful. Similarly, don’t worry if the best name is a long one–it’s easy to rebind it to a new name when required.
…But don’t mislead
That said, make sure it really is the best name. Long names often
indicate functions that can be split:
find-and-replace should probably be split in two. (Hint:
and is a
great clue). If a function’s name collides with a core function or
incorporates a common name, it should act the same way: if
doesn’t apply a function to every cell in a table, it has the wrong name.
Use idiomatic vocabulary
expr is usually used for a single expression and
for a longer form.
“Collection” is often shortened to
Bundling up extra arguments is almost always done with
1 2 3
Like in middle school math,
n is usually an integer,
default numerical inputs, and
h are often functions.
1 2 3 4
Dynamic vars wear
*earmuffs*. Try not to use them.
Simple format transformations often use an arrow, e.g.:
Make side effects explicit
Clojure does a great job separating value, state, and
Clojure programmers should, too. If a function changes state or has
side effects, its name should reflect it. Functions that mutate
reset! end with a bang. Side effects hiding
elsewhere should also be explicit: if
format-page saves a file to
disk, it should be
format-and-save-page (or even better, two
UPDATE: See also the Clojure Style Guide, a concise, comprehensive community-driven document with many more guidelines on clean Clojure.