From bc8444d226e0b82f5a6af165f51b19bdc6df7f5e Mon Sep 17 00:00:00 2001 From: ci-build Date: Mon, 10 Jun 2019 14:59:44 +0000 Subject: [PATCH 001/122] [skip ci] Update site --- .circleci/config.yml | 53 ++ .gitignore | 1 + .nojekyll | 0 CONTRIBUTING.md | 28 + README.adoc | 2168 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 2250 insertions(+) create mode 100644 .circleci/config.yml create mode 100644 .gitignore create mode 100644 .nojekyll create mode 100644 CONTRIBUTING.md create mode 100644 README.adoc diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..c97deb2 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,53 @@ +version: 2 + +jobs: + docs-build: + docker: + - image: ruby:2.6 + steps: + - checkout + - run: + name: Install AsciiDoctor & Rouge + command: | + gem install asciidoctor + gem install rouge + - run: + name: Build Site + command: asciidoctor -a toc="left" -a toclevels=2 README.adoc -o _build/html/index.html + - persist_to_workspace: + root: _build + paths: html + docs-deploy: + docker: + - image: node:8.10.0 + steps: + - checkout + - attach_workspace: + at: _build + - run: + name: Disable jekyll builds + command: touch _build/html/.nojekyll + - run: + name: Install and configure dependencies + command: | + npm install -g --silent gh-pages@2.0.1 + git config user.email "ci-build@clojure.style" + git config user.name "ci-build" + - add_ssh_keys: + fingerprints: + - "31:6a:94:d6:ec:2d:6c:fc:0c:9e:61:8e:49:b2:6f:1e" + - run: + name: Deploy docs to gh-pages branch + command: gh-pages -add --dotfiles --message "[skip ci] Update site" --dist _build/html + +workflows: + version: 2 + build: + jobs: + - docs-build + - docs-deploy: + requires: + - docs-build + filters: + branches: + only: master diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2d19fc7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.html diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..fb98eed --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,28 @@ +# Contributing + +If you discover issues, have ideas for improvements, or +want to contribute new rules, please report them to the +[issue tracker][1] of the repository or submit a pull request. Please, +try to follow these guidelines when you do so. + +## Issue reporting + +* Check that the issue has not already been reported. +* Be clear, concise and precise in your description of the problem. +* Open an issue with a descriptive title and a summary in grammatically correct, + complete sentences. +* Include any relevant code to the issue summary. + +## Pull requests + +* Read [how to properly contribute to open source projects on Github][2]. +* Use a topic branch to easily amend a pull request later, if necessary. +* Write [good commit messages][3]. +* Use the same coding conventions as the rest of the project. +* Open a [pull request][4] that relates to *only* one subject with a clear title + and description in grammatically correct, complete sentences. + +[1]: https://github.com/bbatsov/clojure-style-guide/issues +[2]: http://gun.io/blog/how-to-github-fork-branch-and-pull-request +[3]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html +[4]: https://help.github.com/articles/using-pull-requests diff --git a/README.adoc b/README.adoc new file mode 100644 index 0000000..e17cdd5 --- /dev/null +++ b/README.adoc @@ -0,0 +1,2168 @@ += The Clojure Style Guide +:idprefix: +:idseparator: - +:sectanchors: +:sectlinks: +:toc: preamble +:toclevels: 1 +ifndef::backend-pdf[] +:toc-title: pass:[

Table of Contents

] +endif::[] +:source-highlighter: rouge + +[quote] +____ +Role models are important. + +-- Officer Alex J. Murphy / RoboCop +____ + +This Clojure style guide recommends best practices so that real-world Clojure +programmers can write code that can be maintained by other real-world Clojure +programmers. A style guide that reflects real-world usage gets used, and a +style guide that holds to an ideal that has been rejected by the people it is +supposed to help risks not getting used at all -- no matter how good it is. + +The guide is separated into several sections of related rules. I've +tried to add the rationale behind the rules (if it's omitted, I've +assumed that it's pretty obvious). + +I didn't come up with all the rules out of nowhere; they are mostly +based on my extensive career as a professional software engineer, +feedback and suggestions from members of the Clojure community, and +various highly regarded Clojure programming resources, such as +http://www.clojurebook.com/["Clojure Programming"] +and http://joyofclojure.com/["The Joy of Clojure"]. + +NOTE: The guide is still a work in progress; some sections are missing, +others are incomplete, some rules are lacking examples, some rules +don't have examples that illustrate them clearly enough. In due time +these issues will be addressed -- just keep them in mind for now. +Help us address those shortcomings and make this guide better together! + +Please note, that the Clojure developing community maintains a list of +https://clojure.org/community/contrib_howto#_coding_guidelines[coding standards for libraries], +too. + +You can generate a PDF copy of this guide using https://asciidoctor.org/docs/asciidoctor-pdf/[AsciiDoctor PDF], and an HTML copy https://asciidoctor.org/docs/convert-documents/#converting-a-document-to-html[with] https://asciidoctor.org/#installation[AsciiDoctor] using the following commands: + +[source,shell] +---- +# Generates README.pdf +asciidoctor-pdf -a allow-uri-read README.adoc + +# Generates README.html +asciidoctor +---- + +Translations of the guide are available in the following languages: + +* https://github.com/geekerzp/clojure-style-guide/blob/master/README-zhCN.md[Chinese] +* https://github.com/totakke/clojure-style-guide/blob/ja/README.md[Japanese] +* https://github.com/kwakbab/clojure-style-guide/blob/master/README-koKO.md[Korean] +* https://github.com/theSkilled/clojure-style-guide/blob/pt-BR/README.md[Portuguese] (Under progress) +* https://github.com/Nondv/clojure-style-guide/blob/master/ru/README.md[Russian] +* https://github.com/jeko2000/clojure-style-guide/blob/master/README.md[Spanish] + +== Source Code Layout & Organization + +[quote] +____ +Nearly everybody is convinced that every style but their own is +ugly and unreadable. Leave out the "but their own" and they're +probably right... + +-- Jerry Coffin (on indentation) +____ + +=== Tabs vs Spaces [[spaces]] + +Use *spaces* for indentation. No hard tabs. + +=== Body Indentation [[body-indentation]] + +Use 2 spaces to indent the bodies of +forms that have body parameters. This covers all `def` forms, special +forms and macros that introduce local bindings (e.g. `loop`, `let`, +`when-let`) and many macros like `when`, `cond`, `as->`, `cond->`, `case`, +`with-*`, etc. + +[source,clojure] +---- +;; good +(when something + (something-else)) + +(with-out-str + (println "Hello, ") + (println "world!")) + +;; bad - four spaces +(when something + (something-else)) + +;; bad - one space +(with-out-str + (println "Hello, ") + (println "world!")) +---- + +=== Function Arguments Alignment [[vertically-align-fn-args]] + +Vertically align function (macro) arguments spanning multiple lines. + +[source,clojure] +---- +;; good +(filter even? + (range 1 10)) + +;; bad +(filter even? + (range 1 10)) +---- + +=== Arguments Indentation [[one-space-indent]] + +Use a single space indentation for function (macro) arguments +when there are no arguments on the same line as the function name. + +[source,clojure] +---- +;; good +(filter + even? + (range 1 10)) + +(or + ala + bala + portokala) + +;; bad - two-space indent +(filter + even? + (range 1 10)) + +(or + ala + bala + portokala) +---- + +=== Bindings Alignment [[bindings-alignment]] + +Vertically align `let` (and `let`-like) bindings. + +[source,clojure] +---- +;; good +(let [thing1 "some stuff" + thing2 "other stuff"] + (foo thing1 thing2)) + +;; bad +(let [thing1 "some stuff" + thing2 "other stuff"] + (foo thing1 thing2}) +---- + +=== Map Keys Alignment [[map-keys-alignment]] + +Align vertically map keys. + +[source,clojure] +---- +;; good +{:thing1 thing1 + :thing2 thing2} + +;; bad +{:thing1 thing1 +:thing2 thing2} + +;; bad +{:thing1 thing1 + :thing2 thing2} +---- + +=== Optional New Line After Fn Name [[optional-new-line-after-fn-name]] + +Optionally omit the new line between the function name and argument +vector for `defn` when there is no docstring. + +[source,clojure] +---- +;; good +(defn foo + [x] + (bar x)) + +;; good +(defn foo [x] + (bar x)) + +;; bad +(defn foo + [x] (bar x)) +---- + +=== Multimethod Dispatch Val Placement [[multimethod-dispatch-val-placement]] + +Place the `dispatch-val` of a multimethod on the same line as the +function name. + +[source,clojure] +---- +;; good +(defmethod foo :bar [x] (baz x)) + +(defmethod foo :bar + [x] + (baz x)) + +;; bad +(defmethod foo + :bar + [x] + (baz x)) + +(defmethod foo + :bar [x] + (baz x)) +---- + +=== Oneline Short Fn [[oneline-short-fn]] + +Optionally omit the new line between the argument vector and a short +function body. + +[source,clojure] +---- +;; good +(defn foo [x] + (bar x)) + +;; good for a small function body +(defn foo [x] (bar x)) + +;; good for multi-arity functions +(defn foo + ([x] (bar x)) + ([x y] + (if (predicate? x) + (bar x) + (baz x)))) + +;; bad +(defn foo + [x] (if (predicate? x) + (bar x) + (baz x))) +---- + +=== Multiple Arity Indentation [[multiple-arity-indentation]] + +Indent each arity form of a function definition vertically aligned with its +parameters. + +[source,clojure] +---- +;; good +(defn foo + "I have two arities." + ([x] + (foo x 1)) + ([x y] + (+ x y))) + +;; bad - extra indentation +(defn foo + "I have two arities." + ([x] + (foo x 1)) + ([x y] + (+ x y))) +---- + +=== Multiple Arity Order [[multiple-arity-order]] + +Sort the arities of a function +from fewest to most arguments. The common case of multi-arity +functions is that some K arguments fully specifies the function's +behavior, and that arities N < K partially apply the K arity, and +arities N > K provide a fold of the K arity over varargs. + +[source,clojure] +---- +;; good - it's easy to scan for the nth arity +(defn foo + "I have two arities." + ([x] + (foo x 1)) + ([x y] + (+ x y))) + +;; okay - the other arities are applications of the two-arity +(defn foo + "I have two arities." + ([x y] + (+ x y)) + ([x] + (foo x 1)) + ([x y z & more] + (reduce foo (foo x (foo y z)) more))) + +;; bad - unordered for no apparent reason +(defn foo + ([x] 1) + ([x y z] (foo x (foo y z))) + ([x y] (+ x y)) + ([w x y z & more] (reduce foo (foo w (foo x (foo y z))) more))) +---- + +=== Crlf [[crlf]] + +Use Unix-style line endings.footnote:[*BSD/Solaris/Linux/OSX users are +covered by default, Windows users have to be extra careful.] + +[TIP] +==== +If you're using Git you might want to add the following +configuration setting to protect your project from Windows line +endings creeping in: + +[source,shell] +---- +$ git config --global core.autocrlf true +---- +==== + +=== Bracket Spacing [[bracket-spacing]] + +If any text precedes an opening bracket(`(`, `{` and +`[`) or follows a closing bracket(`)`, `}` and `]`), separate that +text from that bracket with a space. Conversely, leave no space after +an opening bracket and before following text, or after preceding text +and before a closing bracket. + +[source,clojure] +---- +;; good +(foo (bar baz) quux) + +;; bad +(foo(bar baz)quux) +(foo ( bar baz ) quux) +---- + +=== No Commas For Seq Literals [[no-commas-for-seq-literals]] + +[quote] +____ +Syntactic sugar causes semicolon cancer. + +-- Alan Perlis +____ + +Don't use commas between the elements of sequential collection literals. + +[source,clojure] +---- +;; good +[1 2 3] +(1 2 3) + +;; bad +[1, 2, 3] +(1, 2, 3) +---- + +=== Opt Commas In Map Literals [[opt-commas-in-map-literals]] + +Consider enhancing the readability of map literals via judicious use +of commas and line breaks. + +[source,clojure] +---- +;; good +{:name "Bruce Wayne" :alter-ego "Batman"} + +;; good and arguably a bit more readable +{:name "Bruce Wayne" + :alter-ego "Batman"} + +;; good and arguably more compact +{:name "Bruce Wayne", :alter-ego "Batman"} +---- + +=== Gather Trailing Parens [[gather-trailing-parens]] + +Place all trailing parentheses on a single line instead of distinct lines. + +[source,clojure] +---- +;; good; single line +(when something + (something-else)) + +;; bad; distinct lines +(when something + (something-else) +) +---- + +=== Empty Lines Between Top Level Forms [[empty-lines-between-top-level-forms]] + +Use a single empty line between top-level forms. + +[source,clojure] +---- +;; good +(def x ...) + +(defn foo ...) + +;; bad +(def x ...) +(defn foo ...) + +;; bad +(def x ...) + + +(defn foo ...) +---- + +An exception to the rule is the grouping of related ``def``s together. + +[source,clojure] +---- +;; good +(def min-rows 10) +(def max-rows 20) +(def min-cols 15) +(def max-cols 30) +---- + +=== No Blank Lines Within Def Forms [[no-blank-lines-within-def-forms]] + +Do not place blank lines in the middle of a function or +macro definition. An exception can be made to indicate grouping of +pairwise constructs as found in e.g. `let` and `cond`. + +[#80-character-limits] +=== Line Length [[line-length]] + +Where feasible, avoid making lines longer than 80 characters. + +=== No Trailing Whitespace [[no-trailing-whitespace]] + +Avoid trailing whitespace. + +=== One File Per Namespace [[one-file-per-namespace]] + +Use one file per namespace. + +=== Comprehensive Ns Declaration [[comprehensive-ns-declaration]] + +Start every namespace with a comprehensive `ns` form, comprised of +``refer``s, ``require``s, and ``import``s, conventionally in that order. + +[source,clojure] +---- +(ns examples.ns + (:refer-clojure :exclude [next replace remove]) + (:require [clojure.string :as s :refer [blank?]]) + (:import java.util.Date)) +---- + +=== Line Break Ns Declaration [[line-break-ns-declaration]] + +When there are multiple dependencies, you may want to start them on +a new line, then insert line breaks after each one for easier sorting, +readability if it's a long line, and to reduce diffing when only there +is only a change related to one dependency. + +[source,clojure] +---- +;; better +(ns examples.ns + (:require + [clojure.string :as s :refer [blank?]] + [clojure.set :as set] + [clojure.java.shell :as sh]) + (:import + java.util.Date + java.text.SimpleDateFormat + [java.util.concurrent Executors + LinkedBlockingQueue])) + +;; good +(ns examples.ns + (:require [clojure.string :as s :refer [blank?]] + [clojure.set :as set] + [clojure.java.shell :as sh]) + (:import java.util.Date + java.text.SimpleDateFormat + [java.util.concurrent Executors + LinkedBlockingQueue])) + +;; bad +(ns examples.ns + (:require [clojure.string :as s :refer [blank?]] [clojure.set :as set] [clojure.java.shell :as sh]) + (:import java.util.Date java.text.SimpleDateFormat [java.util.concurrent Executors LinkedBlockingQueue])) +---- + +=== Prefer Require Over Use [[prefer-require-over-use]] + +In the `ns` form prefer `:require :as` over `:require :refer` over `:require +:refer :all`. Prefer `:require` over `:use`; the latter form should be +considered deprecated for new code. + +[source,clojure] +---- +;; good +(ns examples.ns + (:require [clojure.zip :as zip])) + +;; good +(ns examples.ns + (:require [clojure.zip :refer [lefts rights]])) + +;; acceptable as warranted +(ns examples.ns + (:require [clojure.zip :refer :all])) + +;; bad +(ns examples.ns + (:use clojure.zip)) +---- + +=== No Single Segment Namespaces [[no-single-segment-namespaces]] + +Avoid single-segment namespaces. + +[source,clojure] +---- +;; good +(ns example.ns) + +;; bad +(ns example) +---- + +=== Namespace Segments Limit [[namespace-segments-limit]] + +Avoid the use of overly long namespaces (i.e., more than 5 segments). + +=== Function Length [[function-length]] + +Avoid functions longer than 10 LOC (lines of code). Ideally, most +functions will be shorter than 5 LOC. + +=== Function Positional Parameters Limit [[function-positional-parameter-limit]] + +Avoid parameter lists with more than three or four positional parameters. + +=== Forward References [[forward-references]] + +Avoid forward references. They are occasionally necessary, but such occasions +are rare in practice. + +== Syntax + +=== Dynamic Namespace Manipulation [[ns-fns-only-in-repl]] + +Avoid the use of namespace-manipulating functions like `require` and +`refer`. They are entirely unnecessary outside of a REPL +environment. + +=== Declare [[declare]] + +Use `declare` to enable forward references when forward references are +necessary. + +=== Higher-order Functions [[higher-order-fns]] + +Prefer higher-order functions like `map` to `loop/recur`. + +=== Pre and Post Conditions [[pre-post-conditions]] + +Prefer function pre and post conditions to checks inside a function's body. + +[source,clojure] +---- +;; good +(defn foo [x] + {:pre [(pos? x)]} + (bar x)) + +;; bad +(defn foo [x] + (if (pos? x) + (bar x) + (throw (IllegalArgumentException. "x must be a positive number!"))) +---- + +=== Vars Inside Functions [[dont-def-vars-inside-fns]] + +Don't define vars inside functions. + +[source,clojure] +---- +;; very bad +(defn foo [] + (def x 5) + ...) +---- + +=== Shadowing `clojure.core` Names [[dont-shadow-clojure-core]] + +Don't shadow `clojure.core` names with local bindings. + +[source,clojure] +---- +;; bad - you're forced to use clojure.core/map fully qualified inside +(defn foo [map] + ...) +---- + +=== Alter Var Binding [[alter-var]] + +Use `alter-var-root` instead of `def` to change the value of a var. + +[source,clojure] +---- +;; good +(def thing 1) ; value of thing is now 1 +; do some stuff with thing +(alter-var-root #'thing (constantly nil)) ; value of thing is now nil + +;; bad +(def thing 1) +; do some stuff with thing +(def thing nil) +; value of thing is now nil +---- + +=== Nil Punning [[nil-punning]] + +Use `seq` as a terminating condition to test whether a sequence is +empty (this technique is sometimes called _nil punning_). + +[source,clojure] +---- +;; good +(defn print-seq [s] + (when (seq s) + (prn (first s)) + (recur (rest s)))) + +;; bad +(defn print-seq [s] + (when-not (empty? s) + (prn (first s)) + (recur (rest s)))) +---- + +=== Converting Sequences to Vectors [[to-vector]] + +Prefer `vec` over `into` when you need to convert a sequence into a vector. + +[source,clojure] +---- +;; good +(vec some-seq) + +;; bad +(into [] some-seq) +---- + +=== `when` vs `if` [[when-instead-of-single-branch-if]] + +Use `when` instead of `(if ... (do ...))`. + +[source,clojure] +---- +;; good +(when pred + (foo) + (bar)) + +;; bad +(if pred + (do + (foo) + (bar))) +---- + +=== `if-let` [[if-let]] + +Use `if-let` instead of `let` + `if`. + +[source,clojure] +---- +;; good +(if-let [result (foo x)] + (something-with result) + (something-else)) + +;; bad +(let [result (foo x)] + (if result + (something-with result) + (something-else))) +---- + +=== `when-let` [[when-let]] + +Use `when-let` instead of `let` + `when`. + +[source,clojure] +---- +;; good +(when-let [result (foo x)] + (do-something-with result) + (do-something-more-with result)) + +;; bad +(let [result (foo x)] + (when result + (do-something-with result) + (do-something-more-with result))) +---- + +=== `if-not` [[if-not]] + +Use `if-not` instead of `(if (not ...) ...)`. + +[source,clojure] +---- +;; good +(if-not pred + (foo)) + +;; bad +(if (not pred) + (foo)) +---- + +=== `when-not` [[when-not]] + +Use `when-not` instead of `(when (not ...) ...)`. + +[source,clojure] +---- +;; good +(when-not pred + (foo) + (bar)) + +;; bad +(when (not pred) + (foo) + (bar)) +---- + +=== `when-not` vs `if-not` [[when-not-instead-of-single-branch-if-not]] + +Use `when-not` instead of `(if-not ... (do ...))`. + +[source,clojure] +---- +;; good +(when-not pred + (foo) + (bar)) + +;; bad +(if-not pred + (do + (foo) + (bar))) +---- + +=== `not=` [[not-equal]] + +Use `not=` instead of `(not (= ...))`. + +[source,clojure] +---- +;; good +(not= foo bar) + +;; bad +(not (= foo bar)) +---- + +=== `printf` [[printf]] + +Use `printf` instead of `(print (format ...))`. + +[source,clojure] +---- +;; good +(printf "Hello, %s!\n" name) + +;; ok +(println (format "Hello, %s!" name)) +---- + +=== Flexible Comparison Functions [[multiple-arity-of-gt-and-ls-fns]] + +When doing comparisons, keep in mind that Clojure's functions `<`, +`>`, etc. accept a variable number of arguments. + +[source,clojure] +---- +;; good +(< 5 x 10) + +;; bad +(and (> x 5) (< x 10)) +---- + +=== Single Param Fn Literal [[single-param-fn-literal]] + +Prefer `%` over `%1` in function literals with only one parameter. + +[source,clojure] +---- +;; good +#(Math/round %) + +;; bad +#(Math/round %1) +---- + +=== Multiple Params Fn Literal [[multiple-params-fn-literal]] + +Prefer `%1` over `%` in function literals with more than one parameter. + +[source,clojure] +---- +;; good +#(Math/pow %1 %2) + +;; bad +#(Math/pow % %2) +---- + +=== No Useless Anonymous Fns [[no-useless-anonymous-fns]] + +Don't wrap functions in anonymous functions when you don't need to. + +[source,clojure] +---- +;; good +(filter even? (range 1 10)) + +;; bad +(filter #(even? %) (range 1 10)) +---- + +=== No Multiple Forms Fn Literals [[no-multiple-forms-fn-literals]] + +Don't use function literals if the function body will consist of +more than one form. + +[source,clojure] +---- +;; good +(fn [x] + (println x) + (* x 2)) + +;; bad (you need an explicit do form) +#(do (println %) + (* % 2)) +---- + +=== `complement` [[complement]] + +Favor the use of `complement` versus the use of an anonymous function. + +[source,clojure] +---- +;; good +(filter (complement some-pred?) coll) + +;; bad +(filter #(not (some-pred? %)) coll) +---- + +This rule should obviously be ignored if the complementing predicate + exists in the form of a separate function (e.g. `even?` and `odd?`). + +=== `comp` [[comp]] + +Leverage `comp` when doing so yields simpler code. + +[source,clojure] +---- +;; Assuming `(:require [clojure.string :as str])`... + +;; good +(map #(str/capitalize (str/trim %)) ["top " " test "]) + +;; better +(map (comp str/capitalize str/trim) ["top " " test "]) +---- + +=== `partial` [[partial]] + +Leverage `partial` when doing so yields simpler code. + +[source,clojure] +---- +;; good +(map #(+ 5 %) (range 1 10)) + +;; (arguably) better +(map (partial + 5) (range 1 10)) +---- + +=== Threading Macros [[threading-macros]] + +Prefer the use of the threading macros `->` (thread-first) and `->>` +(thread-last) to heavy form nesting. + +[source,clojure] +---- +;; good +(-> [1 2 3] + reverse + (conj 4) + prn) + +;; not as good +(prn (conj (reverse [1 2 3]) + 4)) + +;; good +(->> (range 1 10) + (filter even?) + (map (partial * 2))) + +;; not as good +(map (partial * 2) + (filter even? (range 1 10))) +---- + +=== Default `cond` Branch [[else-keyword-in-cond]] + +Use `:else` as the catch-all test expression in `cond`. + +[source,clojure] +---- +;; good +(cond + (neg? n) "negative" + (pos? n) "positive" + :else "zero") + +;; bad +(cond + (neg? n) "negative" + (pos? n) "positive" + true "zero") +---- + +=== `condp` vs `cond` [[condp]] + +Prefer `condp` instead of `cond` when the predicate & expression don't +change. + +[source,clojure] +---- +;; good +(cond + (= x 10) :ten + (= x 20) :twenty + (= x 30) :thirty + :else :dunno) + +;; much better +(condp = x + 10 :ten + 20 :twenty + 30 :thirty + :dunno) +---- + +=== `case` vs `cond/condp` [[case]] + +Prefer `case` instead of `cond` or `condp` when test expressions are +compile-time constants. + +[source,clojure] +---- +;; good +(cond + (= x 10) :ten + (= x 20) :twenty + (= x 30) :forty + :else :dunno) + +;; better +(condp = x + 10 :ten + 20 :twenty + 30 :forty + :dunno) + +;; best +(case x + 10 :ten + 20 :twenty + 30 :forty + :dunno) +---- + +=== Shor Forms In Cond [[shor-forms-in-cond]] + +Use short forms in `cond` and related. If not possible give visual +hints for the pairwise grouping with comments or empty lines. + +[source,clojure] +---- +;; good +(cond + (test1) (action1) + (test2) (action2) + :else (default-action)) + +;; ok-ish +(cond + ;; test case 1 + (test1) + (long-function-name-which-requires-a-new-line + (complicated-sub-form + (-> 'which-spans multiple-lines))) + + ;; test case 2 + (test2) + (another-very-long-function-name + (yet-another-sub-form + (-> 'which-spans multiple-lines))) + + :else + (the-fall-through-default-case + (which-also-spans 'multiple + 'lines))) +---- + +=== Set As Predicate [[set-as-predicate]] + +Use a `set` as a predicate when appropriate. + +[source,clojure] +---- +;; good +(remove #{1} [0 1 2 3 4 5]) + +;; bad +(remove #(= % 1) [0 1 2 3 4 5]) + +;; good +(count (filter #{\a \e \i \o \u} "mary had a little lamb")) + +;; bad +(count (filter #(or (= % \a) + (= % \e) + (= % \i) + (= % \o) + (= % \u)) + "mary had a little lamb")) +---- + +=== `inc` and `dec` [[inc-and-dec]] + +Use `(inc x)` & `(dec x)` instead of `(+ x 1)` and `(- x 1)`. + +=== `pos?` and `neg?` [[pos-and-neg]] + +Use `(pos? x)`, `(neg? x)` & `(zero? x)` instead of `(> x 0)`, +`(< x 0)` & `(= x 0)`. + +=== `list*` vs `cons` [[list-star-instead-of-nested-cons]] + +Use `list*` instead of a series of nested `cons` invocations. + +[source,clojure] +---- +;; good +(list* 1 2 3 [4 5]) + +;; bad +(cons 1 (cons 2 (cons 3 [4 5]))) +---- + +=== Sugared Java Interop [[sugared-java-interop]] + +Use the sugared Java interop forms. + +[source,clojure] +---- +;;; object creation +;; good +(java.util.ArrayList. 100) + +;; bad +(new java.util.ArrayList 100) + +;;; static method invocation +;; good +(Math/pow 2 10) + +;; bad +(. Math pow 2 10) + +;;; instance method invocation +;; good +(.substring "hello" 1 3) + +;; bad +(. "hello" substring 1 3) + +;;; static field access +;; good +Integer/MAX_VALUE + +;; bad +(. Integer MAX_VALUE) + +;;; instance field access +;; good +(.someField some-object) + +;; bad +(. some-object someField) +---- + +=== Compact Metadata Notation For True Flags [[compact-metadata-notation-for-true-flags]] + +Use the compact metadata notation for metadata that contains only +slots whose keys are keywords and whose value is boolean `true`. + +[source,clojure] +---- +;; good +(def ^:private a 5) + +;; bad +(def ^{:private true} a 5) +---- + +=== Private [[private]] + +Denote private parts of your code. + +[source,clojure] +---- +;; good +(defn- private-fun [] ...) + +(def ^:private private-var ...) + +;; bad +(defn private-fun [] ...) ; not private at all + +(defn ^:private private-fun [] ...) ; overly verbose + +(def private-var ...) ; not private at all +---- + +=== Access Private Var [[access-private-var]] + +To access a private var (e.g. for testing), use the `@#'some.ns/var` form. + +=== Attach Metadata Carefully [[attach-metadata-carefully]] + +Be careful regarding what exactly do you attach metadata to. + +[source,clojure] +---- +;; we attach the metadata to the var referenced by `a` +(def ^:private a {}) +(meta a) ;=> nil +(meta #'a) ;=> {:private true} + +;; we attach the metadata to the empty hash-map value +(def a ^:private {}) +(meta a) ;=> {:private true} +(meta #'a) ;=> nil +---- + +== Naming + +[quote] +____ +The only real difficulties in programming are cache invalidation and +naming things. + +-- Phil Karlton +____ + +=== Ns Naming Schemas [[ns-naming-schemas]] + +When naming namespaces favor the following two schemas: + +* `project.module` +* `organization.project.module` + +=== Lisp Case Ns [[lisp-case-ns]] + +Use `lisp-case` in composite namespace segments(e.g. `bruce.project-euler`) + +=== Lisp Case [[lisp-case]] + +Use `lisp-case` for function and variable names. + +[source,clojure] +---- +;; good +(def some-var ...) +(defn some-fun ...) + +;; bad +(def someVar ...) +(defn somefun ...) +(def some_fun ...) +---- + +=== Camelcase For Protocols Records Structs And Types [[CamelCase-for-protocols-records-structs-and-types]] + +Use `CamelCase` for protocols, records, structs, and types. (Keep +acronyms like HTTP, RFC, XML uppercase.) + +=== Pred With Question Mark [[pred-with-question-mark]] + +The names of predicate methods (methods that return a boolean value) +should end in a question mark +(e.g., `even?`). + +[source,clojure] +---- +;; good +(defn palindrome? ...) + +;; bad +(defn palindrome-p ...) ; Common Lisp style +(defn is-palindrome ...) ; Java style +---- + +=== Changing State Fns With Exclamation Mark [[changing-state-fns-with-exclamation-mark]] + +The names of functions/macros that are not safe in STM transactions +should end with an exclamation mark (e.g. `reset!`). + +=== Arrow Instead Of To [[arrow-instead-of-to]] + +Use `->` instead of `to` in the names of conversion functions. + +[source,clojure] +---- +;; good +(defn f->c ...) + +;; not so good +(defn f-to-c ...) +---- + +=== Earmuffs For Dynamic Vars [[earmuffs-for-dynamic-vars]] + +Use `*earmuffs*` for things intended for rebinding (ie. are dynamic). + +[source,clojure] +---- +;; good +(def ^:dynamic *a* 10) + +;; bad +(def ^:dynamic a 10) +---- + +=== Don't Flag Constants [[dont-flag-constants]] + +Don't use a special notation for constants; everything is assumed a constant +unless specified otherwise. + +=== Underscore For Unused Bindings [[underscore-for-unused-bindings]] + +Use `_` for destructuring targets and formal argument names whose +value will be ignored by the code at hand. + +[source,clojure] +---- +;; good +(let [[a b _ c] [1 2 3 4]] + (println a b c)) + +(dotimes [_ 3] + (println "Hello!")) + +;; bad +(let [[a b c d] [1 2 3 4]] + (println a b d)) + +(dotimes [i 3] + (println "Hello!")) +---- + +=== Idiomatic Names [[idiomatic-names]] + +Follow `clojure.core`'s example for idiomatic names like `pred` and `coll`. + +* in functions: + ** `f`, `g`, `h` - function input + ** `n` - integer input usually a size + ** `index`, `i` - integer index + ** `x`, `y` - numbers + ** `xs` - sequence + ** `m` - map + ** `s` - string input + ** `re` - regular expression + ** `coll` - a collection + ** `pred` - a predicate closure + ** `& more` - variadic input + ** `xf` - xform, a transducer +* in macros: + ** `expr` - an expression + ** `body` - a macro body + ** `binding` - a macro binding vector + +== Data Structures + +[quote] +____ +It is better to have 100 functions operate on one data structure +than to have 10 functions operate on 10 data structures. + +-- Alan J. Perlis +____ + +=== Avoid Lists [[avoid-lists]] + +Avoid the use of lists for generic data storage (unless a list is +exactly what you need). + +=== Keywords For Hash Keys [[keywords-for-hash-keys]] + +Prefer the use of keywords for hash keys. + +[source,clojure] +---- +;; good +{:name "Bruce" :age 30} + +;; bad +{"name" "Bruce" "age" 30} +---- + +=== Literal Col Syntax [[literal-col-syntax]] + +Prefer the use of the literal collection syntax where +applicable. However, when defining sets, only use literal syntax +when the values are compile-time constants. + +[source,clojure] +---- +;; good +[1 2 3] +#{1 2 3} +(hash-set (func1) (func2)) ; values determined at runtime + +;; bad +(vector 1 2 3) +(hash-set 1 2 3) +#{(func1) (func2)} ; will throw runtime exception if (func1) = (func2) +---- + +=== Avoid Index Based Coll Access [[avoid-index-based-coll-access]] + +Avoid accessing collection members by index whenever possible. + +=== Keywords As Fn To Get Map Values [[keywords-as-fn-to-get-map-values]] + +Prefer the use of keywords as functions for retrieving values from +maps, where applicable. + +[source,clojure] +---- +(def m {:name "Bruce" :age 30}) + +;; good +(:name m) + +;; more verbose than necessary +(get m :name) + +;; bad - susceptible to NullPointerException +(m :name) +---- + +=== Colls As Fns [[colls-as-fns]] + +Leverage the fact that most collections are functions of their elements. + +[source,clojure] +---- +;; good +(filter #{\a \e \o \i \u} "this is a test") + +;; bad - too ugly to share +---- + +=== Keywords As Fns [[keywords-as-fns]] + +Leverage the fact that keywords can be used as functions of a collection. + +[source,clojure] +---- +((juxt :a :b) {:a "ala" :b "bala"}) +---- + +=== Avoid Transient Colls [[avoid-transient-colls]] + +Avoid the use of transient collections, except for +performance-critical portions of the code. + +=== Avoid Java Colls [[avoid-java-colls]] + +Avoid the use of Java collections. + +=== Avoid Java Arrays [[avoid-java-arrays]] + +Avoid the use of Java arrays, except for interop scenarios and +performance-critical code dealing heavily with primitive types. + +== Types & Records + +=== Record Constructors [[record-constructors]] + +Don't use the interop syntax to +construct type and record instances. `deftype` and `defrecord` +automatically create constructor functions. Use those instead of +the interop syntax, as they make it clear that you're dealing with a +`deftype` or a `defrecord`. See https://stuartsierra.com/2015/05/17/clojure-record-constructors[this +article] +for more details. + +[source,clojure] +---- +(defrecord Foo [a b]) +(deftype Bar [a b]) + +;; good +(->Foo 1 2) +(map->Foo {:b 4 :a 3}) +(->Bar 1 2) + +;; bad +(Foo. 1 2) +(Bar. 1 2) +---- + +Note that `deftype` doesn't define the `map->Type` + constructor. It's available only for records. + +=== Custom Record Constructors [[custom-record-constructors]] + +Add custom type/record constructors when needed (e.g. to validate +properties on record creation). See https://stuartsierra.com/2015/05/17/clojure-record-constructors[this +article] +for more details. + +[source,clojure] +---- +(defrecord Customer [id name phone email]) + +(defn make-customer + "Creates a new customer record." + [{:keys [name phone email]}] + {:pre [(string? name) + (valid-phone? phone) + (valid-email? email)]} + (->Customer (next-id) name phone email)) +---- + +Feel free to adopt whatever naming convention or structure you'd like for such custom constructors. + +=== Custom Record Constructors Naming [[custom-record-constructors-naming]] + +Don't override the auto-generated type/record constructor functions. +People expect them to have a certain behaviour and you changing this behaviour +violates the principle of the least surprise . See https://stuartsierra.com/2015/05/17/clojure-record-constructors[this +article] +for more details. + +[source,clojure] +---- +(defrecord Foo [num]) + +;; good +(defn make-foo + [num] + {:pre [(pos? num)]} + (->Foo num)) + +;; bad +(defn ->Foo + [num] + {:pre [(pos? num)]} + (Foo. num)) +---- + +== Mutation + +=== Refs [[Refs]] + +==== Refs Io Macro [[refs-io-macro]] + +Consider wrapping all I/O calls with the `io!` macro to avoid nasty +surprises if you accidentally end up calling such code in a +transaction. + +==== Refs Avoid Ref Set [[refs-avoid-ref-set]] + +Avoid the use of `ref-set` whenever possible. + +[source,clojure] +---- +(def r (ref 0)) + +;; good +(dosync (alter r + 5)) + +;; bad +(dosync (ref-set r 5)) +---- + +==== Refs Small Transactions [[refs-small-transactions]] + +Try to keep the size of transactions (the amount of work encapsulated in them) +as small as possible. + +==== Refs Avoid Short Long Transactions With Same Ref [[refs-avoid-short-long-transactions-with-same-ref]] + +Avoid having both short- and long-running transactions interacting +with the same Ref. + +=== Agents [[Agents]] + +==== Agents Send [[agents-send]] + +Use `send` only for actions that are CPU bound and don't block on I/O +or other threads. + +==== Agents Send Off [[agents-send-off]] + +Use `send-off` for actions that might block, sleep, or otherwise tie +up the thread. + +=== Atoms [[Atoms]] + +==== Atoms No Update Within Transactions [[atoms-no-update-within-transactions]] + +Avoid atom updates inside STM transactions. + +==== Atoms Prefer Swap Over Reset [[atoms-prefer-swap-over-reset]] + +Try to use `swap!` rather than `reset!`, where possible. + +[source,clojure] +---- +(def a (atom 0)) + +;; good +(swap! a + 5) + +;; not as good +(reset! a 5) +---- + +== Strings + +=== Prefer Clojure String Over Interop [[prefer-clojure-string-over-interop]] + +Prefer string manipulation functions from `clojure.string` over Java interop or rolling your own. + +[source,clojure] +---- +;; good +(clojure.string/upper-case "bruce") + +;; bad +(.toUpperCase "bruce") +---- + +== Exceptions + +=== Reuse Existing Exception Types [[reuse-existing-exception-types]] + +Reuse existing exception types. Idiomatic Clojure code -- when it does +throw an exception -- throws an exception of a standard type +(e.g. `java.lang.IllegalArgumentException`, +`java.lang.UnsupportedOperationException`, +`java.lang.IllegalStateException`, `java.io.IOException`). + +=== Prefer `with-open` Over `finally` [[prefer-with-open-over-finally]] + +Favor `with-open` over `finally`. + +== Macros + +=== Don't Write Macro If Fn Will Do [[dont-write-macro-if-fn-will-do]] + +Don't write a macro if a function will do. + +=== Write Macro Usage Before Writing The Macro [[write-macro-usage-before-writing-the-macro]] + +Create an example of a macro usage first and the macro afterwards. + +=== Break Complicated Macros [[break-complicated-macros]] + +Break complicated macros into smaller functions whenever possible. + +=== Macros As Syntactic Sugar [[macros-as-syntactic-sugar]] + +A macro should usually just provide syntactic sugar and the core of +the macro should be a plain function. Doing so will improve +composability. + +=== Syntax Quoted Forms [[syntax-quoted-forms]] + +Prefer syntax-quoted forms over building lists manually. + +== Comments + +[quote] +____ +Good code is its own best documentation. As you're about to add a +comment, ask yourself, "How can I improve the code so that this +comment isn't needed?" Improve the code and then document it to make +it even clearer. + +-- Steve McConnell +____ + +=== Self Documenting Code [[self-documenting-code]] + +Endeavor to make your code as self-documenting as possible. + +=== Four Semicolons For Heading Comments [[four-semicolons-for-heading-comments]] + +Write heading comments with at least four semicolons. + +=== Three Semicolons For Top Level Comments [[three-semicolons-for-top-level-comments]] + +Write top-level comments with three semicolons. + +=== Two Semicolons For Code Fragment [[two-semicolons-for-code-fragment]] + +Write comments on a particular fragment of code before that fragment +and aligned with it, using two semicolons. + +=== One Semicolon For Margin Comments [[one-semicolon-for-margin-comments]] + +Write margin comments with one semicolon. + +=== Semicolon Space [[semicolon-space]] + +Always have at least one space between the semicolon +and the text that follows it. + +[source,clojure] +---- +;;;; Frob Grovel + +;;; This section of code has some important implications: +;;; 1. Foo. +;;; 2. Bar. +;;; 3. Baz. + +(defn fnord [zarquon] + ;; If zob, then veeblefitz. + (quux zot + mumble ; Zibblefrotz. + frotz)) +---- + +=== English Syntax [[english-syntax]] + +Comments longer than a word begin with a capital letter and use +punctuation. Separate sentences with +http://en.wikipedia.org/wiki/Sentence_spacing[one space]. + +=== No Superfluous Comments [[no-superfluous-comments]] + +Avoid superfluous comments. + +[source,clojure] +---- +;; bad +(inc counter) ; increments counter by one +---- + +=== Comment Upkeep [[comment-upkeep]] + +Keep existing comments up-to-date. An outdated comment is worse than no comment +at all. + +=== Dash Underscore Reader Macro [[dash-underscore-reader-macro]] + +Prefer the use of the `#_` reader macro over a regular comment when +you need to comment out a particular form. + +[source,clojure] +---- +;; good +(+ foo #_(bar x) delta) + +;; bad +(+ foo + ;; (bar x) + delta) +---- + +=== Refactor Don't Comment [[refactor-dont-comment]] + +[quote] +____ +Good code is like a good joke - it needs no explanation. + +-- Russ Olsen +____ + +Avoid writing comments to explain bad code. Refactor the code to +make it self-explanatory. ("Do, or do not. There is no try." --Yoda) + +=== Comment Annotations + +==== Annotate Above [[annotate-above]] + +Annotations should usually be written on the line immediately above +the relevant code. + +[source,clojure] +---- +;; good +(defn some-fun + [] + ;; FIXME: Replace baz with the newer bar. + (baz)) + +;; bad +;; FIXME: Replace baz with the newer bar. +(defn some-fun + [] + (baz)) +---- + +==== Annotate Keywords [[annotate-keywords]] + +The annotation keyword is followed by a colon and a space, then a note +describing the problem. + +[source,clojure] +---- +;; good +(defn some-fun + [] + ;; FIXME: Replace baz with the newer bar. + (baz)) + +;; bad - no colon after annotation +(defn some-fun + [] + ;; FIXME Replace baz with the newer bar. + (baz)) + +;; bad - no space after colon +(defn some-fun + [] + ;; FIXME:Replace baz with the newer bar. + (baz)) +---- + +==== Indent Annotations [[indent-annotations]] + +If multiple lines are required to describe the problem, subsequent +lines should be indented as much as the first one. + +[source,clojure] +---- +;; good +(defn some-fun + [] + ;; FIXME: This has crashed occasionally since v1.2.3. It may + ;; be related to the BarBazUtil upgrade. (xz 13-1-31) + (baz)) + +;; bad +(defn some-fun + [] + ;; FIXME: This has crashed occasionally since v1.2.3. It may + ;; be related to the BarBazUtil upgrade. (xz 13-1-31) + (baz)) +---- + +==== Sign And Date Annotations [[sign-and-date-annotations]] + +Tag the annotation with your initials and a date so its relevance can +be easily verified. + +[source,clojure] +---- +(defn some-fun + [] + ;; FIXME: This has crashed occasionally since v1.2.3. It may + ;; be related to the BarBazUtil upgrade. (xz 13-1-31) + (baz)) +---- + +==== Rare Eol Annotations [[rare-eol-annotations]] + +In cases where the problem is so obvious that any documentation would +be redundant, annotations may be left at the end of the offending line +with no note. This usage should be the exception and not the rule. + +[source,clojure] +---- +(defn bar + [] + (sleep 100)) ; OPTIMIZE +---- + +==== `TODO` [[todo]] + +Use `TODO` to note missing features or functionality that should be +added at a later date. + +==== `FIXME` [[fixme]] + +Use `FIXME` to note broken code that needs to be fixed. + +==== `OPTIMIZE` [[optimize]] + +Use `OPTIMIZE` to note slow or inefficient code that may cause +performance problems. + +==== `HACK` [[hack]] + +Use `HACK` to note "code smells" where questionable coding practices +were used and should be refactored away. + +==== `REVIEW` [[review]] + +Use `REVIEW` to note anything that should be looked at to confirm it +is working as intended. For example: `REVIEW: Are we sure this is how the +client does X currently?` + +==== Document Custom Annotations [[document-annotations]] + +Use other custom annotation keywords if it feels appropriate, but be +sure to document them in your project's `README` or similar. + +== Documentation + +Docstrings are the primary way to document Clojure code. Many definition forms +(e.g. `def`, `defn`, `defmacro`, `ns`) +support docstrings and usually it's a good idea to make good use of them, regardless +of whether the var in question is something public or private. + +If a definition form doesn't support docstrings directly you can still supply them via +the `:doc` metadata attribute. + +This section outlines some of the common conventions and best +practices for documenting Clojure code. + +=== Prefer Docstrings [[prefer-docstrings]] + +If a form supports docstrings directly prefer them over using `:doc` metadata: + +[source,clojure] +---- +;; good +(defn foo + "This function doesn't do much." + [] + ...) + +(ns foo.bar.core + "That's an awesome library.") + +;; bad +(defn foo + ^{:doc "This function doesn't do much."} + [] + ...) + +(ns ^{:doc "That's an awesome library.") + foo.bar.core) +---- + +=== Docstring Summary [[docstring-summary]] + +Let the first line in the doc string be a complete, capitalized +sentence which concisely describes the var in question. This makes it +easy for tooling (Clojure editors and IDEs) to display a short a summary of +the docstring at various places. + +[source,clojure] +---- +;; good +(defn frobnitz + "This function does a frobnitz. + It will do gnorwatz to achieve this, but only under certain + circumstances." + [] + ...) + +;; bad +(defn frobnitz + "This function does a frobnitz. It will do gnorwatz to + achieve this, but only under certain circumstances." + [] + ...) +---- + +=== Document Pos Arguments [[document-pos-arguments]] + +Document all positional arguments, and wrap them them with backticks +(`) so that editors and IDEs can identify them and potentially provide extra +functionality for them. + +[source,clojure] +---- +;; good +(defn watsitz + "Watsitz takes a `frob` and converts it to a znoot. + When the `frob` is negative, the znoot becomes angry." + [frob] + ...) + +;; bad +(defn watsitz + "Watsitz takes a frob and converts it to a znoot. + When the frob is negative, the znoot becomes angry." + [frob] + ...) +---- + +=== Document References [[document-references]] + +Wrap any var references in the docstring with ` so that tooling +can identify them. + +[source,clojure] +---- +;; good +(defn wombat + "Acts much like `clojure.core/identity` except when it doesn't. + Takes `x` as an argument and returns that. If it feels like it." + [x] + ...) + +;; bad +(defn wombat + "Acts much like clojure.core/identity except when it doesn't. + Takes `x` as an argument and returns that. If it feels like it." + [x] + ...) +---- + +=== Docstring Grammar [[docstring-grammar]] + +Docstrings should be comprised from +proper English sentences - this means every sentences should start +with an capitalized word and should end with the proper punctuation. Sentences +should be separated with a single space. + +[source,clojure] +---- +;; good +(def foo + "All sentences should end with a period (or maybe an exclamation mark). + And the period should be followed by a space, unless it's the last sentence.") + +;; bad +(def foo + "all sentences should end with a period (or maybe an exclamation mark). + And the period should be followed by a space, unless it's the last sentence") +---- + +=== Docstring Indentation [[docstring-indentation]] + +Indent multi-line docstrings by two spaces. + +[source,clojure] +---- +;; good +(ns my.ns + "It is actually possible to document a ns. + It's a nice place to describe the purpose of the namespace and maybe even + the overall conventions used. Note how _not_ indenting the doc string makes + it easier for tooling to display it correctly.") + +;; bad +(ns my.ns + "It is actually possible to document a ns. +It's a nice place to describe the purpose of the namespace and maybe even +the overall conventions used. Note how _not_ indenting the doc string makes +it easier for tooling to display it correctly.") +---- + +=== Docstring Leading Trailing Whitespace [[docstring-leading-trailing-whitespace]] + +Neither start nor end your doc strings with any whitespace. + +[source,clojure] +---- +;; good +(def foo + "I'm so awesome." + 42) + +;; bad +(def silly + " It's just silly to start a doc string with spaces. + Just as silly as it is to end it with a bunch of them. " + 42) +---- + +=== Docstring After Fn Name [[docstring-after-fn-name]] + +When adding a docstring -- especially to a function using the above form -- take +care to correctly place the docstring after the function name, not after the +argument vector. The latter is not invalid syntax and won't cause an error, +but includes the string as a form in the function body without attaching it to +the var as documentation. + +[source,clojure] +---- +;; good +(defn foo + "docstring" + [x] + (bar x)) + +;; bad +(defn foo [x] + "docstring" + (bar x)) +---- + +== Existential + +=== Be Functional [[be-functional]] + +Code in a functional way, using mutation only when it makes sense. + +=== Be Consistent [[be-consistent]] + +Be consistent. In an ideal world, be consistent with these guidelines. + +=== Common Sense [[common-sense]] + +Use common sense. + +== Testing + +=== Test Directory Structure [[test-directory-structure]] + +Store your tests in a separate directory, typically `test/yourproject/` (as +opposed to `src/yourproject/`). Your build tool is responsible for making +them available in the contexts where they are necessary; most templates +will do this for you automatically. + +=== Test Ns Naming [[test-ns-naming]] + +Name your ns `yourproject.something-test`, a file which usually lives in +`test/yourproject/something_test.clj` (or `.cljc`, `cljs`). + +=== Test Naming [[test-naming]] + +When using `clojure.test`, define your tests +with `deftest` and name them `something-test`. + +[source,clojure] +---- +;; good +(deftest something-test ...) + +;; bad +(deftest something-tests ...) +(deftest test-something ...) +(deftest something ...) +---- + +== Library Organization + +=== Coordinates [[lib-coordinates]] + +If you are publishing libraries to be used by others, make sure to +follow the http://central.sonatype.org/pages/choosing-your-coordinates.html[Central Repository +guidelines] +for choosing your `groupId` and `artifactId`. This helps to prevent +name conflicts and facilitates the widest possible use. A good +example is https://github.com/stuartsierra/component[Component]. + +=== Minimize Dependencies [[lib-min-dependencies]] + +Avoid unnecessary dependencies. For example, a three-line utility +function copied into a project is usually better than a dependency +that drags in hundreds of vars you do not plan to use. + +=== Tool-agnostic [[lib-core-separate-from-tools]] + +Deliver core functionality and integration points in separate +artifacts. That way, consumers can consume your library without +being constrained by your unrelated tooling prefences. For example, +https://github.com/stuartsierra/component[Component] provides +core functionality, and +https://github.com/stuartsierra/reloaded[reloaded] provides leiningen +integration. + +== Lint Tools + +There are some lint tools created by the Clojure community that might aid you +in your endeavor to write idiomatic Clojure code. + +* https://github.com/technomancy/slamhound[Slamhound] is a tool that will +automatically generate proper `ns` declarations from your existing code. +* https://github.com/jonase/kibit[kibit] is a static code analyzer for +Clojure which uses https://github.com/clojure/core.logic[core.logic] to +search for patterns of code for which there might exist a more idiomatic +function or macro. + +== Contributing + +Nothing written in this guide is set in stone. It's my desire to work +together with everyone interested in Clojure coding style, so that we could +ultimately create a resource that will be beneficial to the entire Clojure +community. + +Feel free to open tickets or send pull requests with improvements. Thanks in +advance for your help! + +You can also support the style guide (and all my Clojure projects like +CIDER, nREPL, orchard, etc) with financial contributions via +https://www.patreon.com/bbatsov[Patreon] and +https://www.paypal.me/bbatsov[PayPal]. + +== License + +image:http://i.creativecommons.org/l/by/3.0/88x31.png[Creative Commons License] +This work is licensed under a +http://creativecommons.org/licenses/by/3.0/deed.en_US[Creative Commons Attribution 3.0 Unported License] + +== Spread the Word + +A community-driven style guide is of little use to a community that +doesn't know about its existence. Tweet about the guide, share it with +your friends and colleagues. Every comment, suggestion or opinion we +get makes the guide just a little bit better. And we want to have the +best possible guide, don't we? From abf5bb1d9b250815aefd6c52b6b06f27cc496de6 Mon Sep 17 00:00:00 2001 From: Bozhidar Batsov Date: Mon, 10 Jun 2019 18:52:44 +0300 Subject: [PATCH 002/122] Fix the CI build I didn't notice that the master branch files ended up on `gh-pages` as well. That way we ended up ignoring index.html. :D --- .gitignore | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .gitignore diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 2d19fc7..0000000 --- a/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.html From 7d8b238b0925c8413c4519853253053c767dfb76 Mon Sep 17 00:00:00 2001 From: ci-build Date: Mon, 10 Jun 2019 15:57:15 +0000 Subject: [PATCH 003/122] [skip ci] Update site --- index.html | 3509 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3509 insertions(+) create mode 100644 index.html diff --git a/index.html b/index.html new file mode 100644 index 0000000..fc79cb6 --- /dev/null +++ b/index.html @@ -0,0 +1,3509 @@ + + + + + + + +Codestin Search App + + + + + +
+
+
+
+
+
+

Role models are important.

+
+
+

 — Officer Alex J. Murphy / RoboCop

+
+
+
+
+

This Clojure style guide recommends best practices so that real-world Clojure +programmers can write code that can be maintained by other real-world Clojure +programmers. A style guide that reflects real-world usage gets used, and a +style guide that holds to an ideal that has been rejected by the people it is +supposed to help risks not getting used at all — no matter how good it is.

+
+
+

The guide is separated into several sections of related rules. I’ve +tried to add the rationale behind the rules (if it’s omitted, I’ve +assumed that it’s pretty obvious).

+
+
+

I didn’t come up with all the rules out of nowhere; they are mostly +based on my extensive career as a professional software engineer, +feedback and suggestions from members of the Clojure community, and +various highly regarded Clojure programming resources, such as +"Clojure Programming" +and "The Joy of Clojure".

+
+
+ + + + + +
+
Note
+
+The guide is still a work in progress; some sections are missing, +others are incomplete, some rules are lacking examples, some rules +don’t have examples that illustrate them clearly enough. In due time +these issues will be addressed — just keep them in mind for now. +Help us address those shortcomings and make this guide better together! +
+
+
+

Please note, that the Clojure developing community maintains a list of +coding standards for libraries, +too.

+
+
+

You can generate a PDF copy of this guide using AsciiDoctor PDF, and an HTML copy with AsciiDoctor using the following commands:

+
+
+
+
# Generates README.pdf
+asciidoctor-pdf -a allow-uri-read README.adoc
+
+# Generates README.html
+asciidoctor
+
+
+
+

Translations of the guide are available in the following languages:

+
+
+ +
+
+
+
+

Source Code Layout & Organization

+
+
+
+
+

Nearly everybody is convinced that every style but their own is +ugly and unreadable. Leave out the "but their own" and they’re +probably right…​

+
+
+

 — Jerry Coffin (on indentation)

+
+
+
+
+

Tabs vs Spaces

+
+

Use spaces for indentation. No hard tabs.

+
+
+
+

Body Indentation

+
+

Use 2 spaces to indent the bodies of +forms that have body parameters. This covers all def forms, special +forms and macros that introduce local bindings (e.g. loop, let, +when-let) and many macros like when, cond, as→, cond→, case, +with-*, etc.

+
+
+
+
;; good
+(when something
+  (something-else))
+
+(with-out-str
+  (println "Hello, ")
+  (println "world!"))
+
+;; bad - four spaces
+(when something
+    (something-else))
+
+;; bad - one space
+(with-out-str
+ (println "Hello, ")
+ (println "world!"))
+
+
+
+
+

Function Arguments Alignment

+
+

Vertically align function (macro) arguments spanning multiple lines.

+
+
+
+
;; good
+(filter even?
+        (range 1 10))
+
+;; bad
+(filter even?
+  (range 1 10))
+
+
+
+
+

Arguments Indentation

+
+

Use a single space indentation for function (macro) arguments +when there are no arguments on the same line as the function name.

+
+
+
+
;; good
+(filter
+ even?
+ (range 1 10))
+
+(or
+ ala
+ bala
+ portokala)
+
+;; bad - two-space indent
+(filter
+  even?
+  (range 1 10))
+
+(or
+  ala
+  bala
+  portokala)
+
+
+
+
+

Bindings Alignment

+
+

Vertically align let (and let-like) bindings.

+
+
+
+
;; good
+(let [thing1 "some stuff"
+      thing2 "other stuff"]
+  (foo thing1 thing2))
+
+;; bad
+(let [thing1 "some stuff"
+  thing2 "other stuff"]
+  (foo thing1 thing2})
+
+
+
+
+

Map Keys Alignment

+
+

Align vertically map keys.

+
+
+
+
;; good
+{:thing1 thing1
+ :thing2 thing2}
+
+;; bad
+{:thing1 thing1
+:thing2 thing2}
+
+;; bad
+{:thing1 thing1
+  :thing2 thing2}
+
+
+
+
+

Optional New Line After Fn Name

+
+

Optionally omit the new line between the function name and argument +vector for defn when there is no docstring.

+
+
+
+
;; good
+(defn foo
+  [x]
+  (bar x))
+
+;; good
+(defn foo [x]
+  (bar x))
+
+;; bad
+(defn foo
+  [x] (bar x))
+
+
+
+
+

Multimethod Dispatch Val Placement

+
+

Place the dispatch-val of a multimethod on the same line as the +function name.

+
+
+
+
;; good
+(defmethod foo :bar [x] (baz x))
+
+(defmethod foo :bar
+  [x]
+  (baz x))
+
+;; bad
+(defmethod foo
+  :bar
+  [x]
+  (baz x))
+
+(defmethod foo
+  :bar [x]
+  (baz x))
+
+
+
+
+

Oneline Short Fn

+
+

Optionally omit the new line between the argument vector and a short +function body.

+
+
+
+
;; good
+(defn foo [x]
+  (bar x))
+
+;; good for a small function body
+(defn foo [x] (bar x))
+
+;; good for multi-arity functions
+(defn foo
+  ([x] (bar x))
+  ([x y]
+   (if (predicate? x)
+     (bar x)
+     (baz x))))
+
+;; bad
+(defn foo
+  [x] (if (predicate? x)
+        (bar x)
+        (baz x)))
+
+
+
+
+

Multiple Arity Indentation

+
+

Indent each arity form of a function definition vertically aligned with its +parameters.

+
+
+
+
;; good
+(defn foo
+  "I have two arities."
+  ([x]
+   (foo x 1))
+  ([x y]
+   (+ x y)))
+
+;; bad - extra indentation
+(defn foo
+  "I have two arities."
+  ([x]
+    (foo x 1))
+  ([x y]
+    (+ x y)))
+
+
+
+
+

Multiple Arity Order

+
+

Sort the arities of a function +from fewest to most arguments. The common case of multi-arity +functions is that some K arguments fully specifies the function’s +behavior, and that arities N < K partially apply the K arity, and +arities N > K provide a fold of the K arity over varargs.

+
+
+
+
;; good - it's easy to scan for the nth arity
+(defn foo
+  "I have two arities."
+  ([x]
+   (foo x 1))
+  ([x y]
+   (+ x y)))
+
+;; okay - the other arities are applications of the two-arity
+(defn foo
+  "I have two arities."
+  ([x y]
+   (+ x y))
+  ([x]
+   (foo x 1))
+  ([x y z & more]
+   (reduce foo (foo x (foo y z)) more)))
+
+;; bad - unordered for no apparent reason
+(defn foo
+  ([x] 1)
+  ([x y z] (foo x (foo y z)))
+  ([x y] (+ x y))
+  ([w x y z & more] (reduce foo (foo w (foo x (foo y z))) more)))
+
+
+
+
+

Crlf

+
+

Use Unix-style line endings.[1]

+
+
+ + + + + +
+
Tip
+
+
+

If you’re using Git you might want to add the following +configuration setting to protect your project from Windows line +endings creeping in:

+
+
+
+
$ git config --global core.autocrlf true
+
+
+
+
+
+
+

Bracket Spacing

+
+

If any text precedes an opening bracket((, { and +[) or follows a closing bracket(), } and ]), separate that +text from that bracket with a space. Conversely, leave no space after +an opening bracket and before following text, or after preceding text +and before a closing bracket.

+
+
+
+
;; good
+(foo (bar baz) quux)
+
+;; bad
+(foo(bar baz)quux)
+(foo ( bar baz ) quux)
+
+
+
+
+

No Commas For Seq Literals

+
+
+
+

Syntactic sugar causes semicolon cancer.

+
+
+

 — Alan Perlis

+
+
+
+
+

Don’t use commas between the elements of sequential collection literals.

+
+
+
+
;; good
+[1 2 3]
+(1 2 3)
+
+;; bad
+[1, 2, 3]
+(1, 2, 3)
+
+
+
+
+

Opt Commas In Map Literals

+
+

Consider enhancing the readability of map literals via judicious use +of commas and line breaks.

+
+
+
+
;; good
+{:name "Bruce Wayne" :alter-ego "Batman"}
+
+;; good and arguably a bit more readable
+{:name "Bruce Wayne"
+ :alter-ego "Batman"}
+
+;; good and arguably more compact
+{:name "Bruce Wayne", :alter-ego "Batman"}
+
+
+
+
+

Gather Trailing Parens

+
+

Place all trailing parentheses on a single line instead of distinct lines.

+
+
+
+
;; good; single line
+(when something
+  (something-else))
+
+;; bad; distinct lines
+(when something
+  (something-else)
+)
+
+
+
+
+

Empty Lines Between Top Level Forms

+
+

Use a single empty line between top-level forms.

+
+
+
+
;; good
+(def x ...)
+
+(defn foo ...)
+
+;; bad
+(def x ...)
+(defn foo ...)
+
+;; bad
+(def x ...)
+
+
+(defn foo ...)
+
+
+
+

An exception to the rule is the grouping of related defs together.

+
+
+
+
;; good
+(def min-rows 10)
+(def max-rows 20)
+(def min-cols 15)
+(def max-cols 30)
+
+
+
+
+

No Blank Lines Within Def Forms

+
+

Do not place blank lines in the middle of a function or +macro definition. An exception can be made to indicate grouping of +pairwise constructs as found in e.g. let and cond.

+
+
+
+

Line Length

+
+

Where feasible, avoid making lines longer than 80 characters.

+
+
+
+

No Trailing Whitespace

+
+

Avoid trailing whitespace.

+
+
+
+

One File Per Namespace

+
+

Use one file per namespace.

+
+
+
+

Comprehensive Ns Declaration

+
+

Start every namespace with a comprehensive ns form, comprised of +refers, requires, and imports, conventionally in that order.

+
+
+
+
(ns examples.ns
+  (:refer-clojure :exclude [next replace remove])
+  (:require [clojure.string :as s :refer [blank?]])
+  (:import java.util.Date))
+
+
+
+
+

Line Break Ns Declaration

+
+

When there are multiple dependencies, you may want to start them on +a new line, then insert line breaks after each one for easier sorting, +readability if it’s a long line, and to reduce diffing when only there +is only a change related to one dependency.

+
+
+
+
;; better
+(ns examples.ns
+  (:require
+   [clojure.string :as s :refer [blank?]]
+   [clojure.set :as set]
+   [clojure.java.shell :as sh])
+  (:import
+   java.util.Date
+   java.text.SimpleDateFormat
+   [java.util.concurrent Executors
+                         LinkedBlockingQueue]))
+
+;; good
+(ns examples.ns
+  (:require [clojure.string :as s :refer [blank?]]
+            [clojure.set :as set]
+            [clojure.java.shell :as sh])
+  (:import java.util.Date
+           java.text.SimpleDateFormat
+           [java.util.concurrent Executors
+                                 LinkedBlockingQueue]))
+
+;; bad
+(ns examples.ns
+  (:require [clojure.string :as s :refer [blank?]] [clojure.set :as set] [clojure.java.shell :as sh])
+  (:import java.util.Date java.text.SimpleDateFormat [java.util.concurrent Executors LinkedBlockingQueue]))
+
+
+
+
+

Prefer Require Over Use

+
+

In the ns form prefer :require :as over :require :refer over :require +:refer :all. Prefer :require over :use; the latter form should be +considered deprecated for new code.

+
+
+
+
;; good
+(ns examples.ns
+  (:require [clojure.zip :as zip]))
+
+;; good
+(ns examples.ns
+  (:require [clojure.zip :refer [lefts rights]]))
+
+;; acceptable as warranted
+(ns examples.ns
+  (:require [clojure.zip :refer :all]))
+
+;; bad
+(ns examples.ns
+  (:use clojure.zip))
+
+
+
+
+

No Single Segment Namespaces

+
+

Avoid single-segment namespaces.

+
+
+
+
;; good
+(ns example.ns)
+
+;; bad
+(ns example)
+
+
+
+
+

Namespace Segments Limit

+
+

Avoid the use of overly long namespaces (i.e., more than 5 segments).

+
+
+
+

Function Length

+
+

Avoid functions longer than 10 LOC (lines of code). Ideally, most +functions will be shorter than 5 LOC.

+
+
+
+

Function Positional Parameters Limit

+
+

Avoid parameter lists with more than three or four positional parameters.

+
+
+
+

Forward References

+
+

Avoid forward references. They are occasionally necessary, but such occasions +are rare in practice.

+
+
+
+
+
+

Syntax

+
+
+

Dynamic Namespace Manipulation

+
+

Avoid the use of namespace-manipulating functions like require and +refer. They are entirely unnecessary outside of a REPL +environment.

+
+
+
+

Declare

+
+

Use declare to enable forward references when forward references are +necessary.

+
+
+
+

Higher-order Functions

+
+

Prefer higher-order functions like map to loop/recur.

+
+
+
+

Pre and Post Conditions

+
+

Prefer function pre and post conditions to checks inside a function’s body.

+
+
+
+
;; good
+(defn foo [x]
+  {:pre [(pos? x)]}
+  (bar x))
+
+;; bad
+(defn foo [x]
+  (if (pos? x)
+    (bar x)
+    (throw (IllegalArgumentException. "x must be a positive number!")))
+
+
+
+
+

Vars Inside Functions

+
+

Don’t define vars inside functions.

+
+
+
+
;; very bad
+(defn foo []
+  (def x 5)
+  ...)
+
+
+
+
+

Shadowing clojure.core Names

+
+

Don’t shadow clojure.core names with local bindings.

+
+
+
+
;; bad - you're forced to use clojure.core/map fully qualified inside
+(defn foo [map]
+  ...)
+
+
+
+
+

Alter Var Binding

+
+

Use alter-var-root instead of def to change the value of a var.

+
+
+
+
;; good
+(def thing 1) ; value of thing is now 1
+; do some stuff with thing
+(alter-var-root #'thing (constantly nil)) ; value of thing is now nil
+
+;; bad
+(def thing 1)
+; do some stuff with thing
+(def thing nil)
+; value of thing is now nil
+
+
+
+
+

Nil Punning

+
+

Use seq as a terminating condition to test whether a sequence is +empty (this technique is sometimes called nil punning).

+
+
+
+
;; good
+(defn print-seq [s]
+  (when (seq s)
+    (prn (first s))
+    (recur (rest s))))
+
+;; bad
+(defn print-seq [s]
+  (when-not (empty? s)
+    (prn (first s))
+    (recur (rest s))))
+
+
+
+
+

Converting Sequences to Vectors

+
+

Prefer vec over into when you need to convert a sequence into a vector.

+
+
+
+
;; good
+(vec some-seq)
+
+;; bad
+(into [] some-seq)
+
+
+
+
+

when vs if

+
+

Use when instead of (if …​ (do …​)).

+
+
+
+
;; good
+(when pred
+  (foo)
+  (bar))
+
+;; bad
+(if pred
+  (do
+    (foo)
+    (bar)))
+
+
+
+
+

if-let

+
+

Use if-let instead of let + if.

+
+
+
+
;; good
+(if-let [result (foo x)]
+  (something-with result)
+  (something-else))
+
+;; bad
+(let [result (foo x)]
+  (if result
+    (something-with result)
+    (something-else)))
+
+
+
+
+

when-let

+
+

Use when-let instead of let + when.

+
+
+
+
;; good
+(when-let [result (foo x)]
+  (do-something-with result)
+  (do-something-more-with result))
+
+;; bad
+(let [result (foo x)]
+  (when result
+    (do-something-with result)
+    (do-something-more-with result)))
+
+
+
+
+

if-not

+
+

Use if-not instead of (if (not …​) …​).

+
+
+
+
;; good
+(if-not pred
+  (foo))
+
+;; bad
+(if (not pred)
+  (foo))
+
+
+
+
+

when-not

+
+

Use when-not instead of (when (not …​) …​).

+
+
+
+
;; good
+(when-not pred
+  (foo)
+  (bar))
+
+;; bad
+(when (not pred)
+  (foo)
+  (bar))
+
+
+
+
+

when-not vs if-not

+
+

Use when-not instead of (if-not …​ (do …​)).

+
+
+
+
;; good
+(when-not pred
+  (foo)
+  (bar))
+
+;; bad
+(if-not pred
+  (do
+    (foo)
+    (bar)))
+
+
+
+
+

not=

+
+

Use not= instead of (not (= …​)).

+
+
+
+
;; good
+(not= foo bar)
+
+;; bad
+(not (= foo bar))
+
+
+
+
+

printf

+
+

Use printf instead of (print (format …​)).

+
+
+
+
;; good
+(printf "Hello, %s!\n" name)
+
+;; ok
+(println (format "Hello, %s!" name))
+
+
+
+
+

Flexible Comparison Functions

+
+

When doing comparisons, keep in mind that Clojure’s functions <, +>, etc. accept a variable number of arguments.

+
+
+
+
;; good
+(< 5 x 10)
+
+;; bad
+(and (> x 5) (< x 10))
+
+
+
+
+

Single Param Fn Literal

+
+

Prefer % over %1 in function literals with only one parameter.

+
+
+
+
;; good
+#(Math/round %)
+
+;; bad
+#(Math/round %1)
+
+
+
+
+

Multiple Params Fn Literal

+
+

Prefer %1 over % in function literals with more than one parameter.

+
+
+
+
;; good
+#(Math/pow %1 %2)
+
+;; bad
+#(Math/pow % %2)
+
+
+
+
+

No Useless Anonymous Fns

+
+

Don’t wrap functions in anonymous functions when you don’t need to.

+
+
+
+
;; good
+(filter even? (range 1 10))
+
+;; bad
+(filter #(even? %) (range 1 10))
+
+
+
+
+

No Multiple Forms Fn Literals

+
+

Don’t use function literals if the function body will consist of +more than one form.

+
+
+
+
;; good
+(fn [x]
+  (println x)
+  (* x 2))
+
+;; bad (you need an explicit do form)
+#(do (println %)
+     (* % 2))
+
+
+
+
+

complement

+
+

Favor the use of complement versus the use of an anonymous function.

+
+
+
+
;; good
+(filter (complement some-pred?) coll)
+
+;; bad
+(filter #(not (some-pred? %)) coll)
+
+
+
+

This rule should obviously be ignored if the complementing predicate + exists in the form of a separate function (e.g. even? and odd?).

+
+
+
+

comp

+
+

Leverage comp when doing so yields simpler code.

+
+
+
+
;; Assuming `(:require [clojure.string :as str])`...
+
+;; good
+(map #(str/capitalize (str/trim %)) ["top " " test "])
+
+;; better
+(map (comp str/capitalize str/trim) ["top " " test "])
+
+
+
+
+

partial

+
+

Leverage partial when doing so yields simpler code.

+
+
+
+
;; good
+(map #(+ 5 %) (range 1 10))
+
+;; (arguably) better
+(map (partial + 5) (range 1 10))
+
+
+
+
+

Threading Macros

+
+

Prefer the use of the threading macros (thread-first) and →> +(thread-last) to heavy form nesting.

+
+
+
+
;; good
+(-> [1 2 3]
+    reverse
+    (conj 4)
+    prn)
+
+;; not as good
+(prn (conj (reverse [1 2 3])
+           4))
+
+;; good
+(->> (range 1 10)
+     (filter even?)
+     (map (partial * 2)))
+
+;; not as good
+(map (partial * 2)
+     (filter even? (range 1 10)))
+
+
+
+
+

Default cond Branch

+
+

Use :else as the catch-all test expression in cond.

+
+
+
+
;; good
+(cond
+  (neg? n) "negative"
+  (pos? n) "positive"
+  :else "zero")
+
+;; bad
+(cond
+  (neg? n) "negative"
+  (pos? n) "positive"
+  true "zero")
+
+
+
+
+

condp vs cond

+
+

Prefer condp instead of cond when the predicate & expression don’t +change.

+
+
+
+
;; good
+(cond
+  (= x 10) :ten
+  (= x 20) :twenty
+  (= x 30) :thirty
+  :else :dunno)
+
+;; much better
+(condp = x
+  10 :ten
+  20 :twenty
+  30 :thirty
+  :dunno)
+
+
+
+
+

case vs cond/condp

+
+

Prefer case instead of cond or condp when test expressions are +compile-time constants.

+
+
+
+
;; good
+(cond
+  (= x 10) :ten
+  (= x 20) :twenty
+  (= x 30) :forty
+  :else :dunno)
+
+;; better
+(condp = x
+  10 :ten
+  20 :twenty
+  30 :forty
+  :dunno)
+
+;; best
+(case x
+  10 :ten
+  20 :twenty
+  30 :forty
+  :dunno)
+
+
+
+
+

Shor Forms In Cond

+
+

Use short forms in cond and related. If not possible give visual +hints for the pairwise grouping with comments or empty lines.

+
+
+
+
;; good
+(cond
+  (test1) (action1)
+  (test2) (action2)
+  :else   (default-action))
+
+;; ok-ish
+(cond
+  ;; test case 1
+  (test1)
+  (long-function-name-which-requires-a-new-line
+    (complicated-sub-form
+      (-> 'which-spans multiple-lines)))
+
+  ;; test case 2
+  (test2)
+  (another-very-long-function-name
+    (yet-another-sub-form
+      (-> 'which-spans multiple-lines)))
+
+  :else
+  (the-fall-through-default-case
+    (which-also-spans 'multiple
+                      'lines)))
+
+
+
+
+

Set As Predicate

+
+

Use a set as a predicate when appropriate.

+
+
+
+
;; good
+(remove #{1} [0 1 2 3 4 5])
+
+;; bad
+(remove #(= % 1) [0 1 2 3 4 5])
+
+;; good
+(count (filter #{\a \e \i \o \u} "mary had a little lamb"))
+
+;; bad
+(count (filter #(or (= % \a)
+                    (= % \e)
+                    (= % \i)
+                    (= % \o)
+                    (= % \u))
+               "mary had a little lamb"))
+
+
+
+
+

inc and dec

+
+

Use (inc x) & (dec x) instead of (+ x 1) and (- x 1).

+
+
+
+

pos? and neg?

+
+

Use (pos? x), (neg? x) & (zero? x) instead of (> x 0), +(< x 0) & (= x 0).

+
+
+
+

list* vs cons

+
+

Use list* instead of a series of nested cons invocations.

+
+
+
+
;; good
+(list* 1 2 3 [4 5])
+
+;; bad
+(cons 1 (cons 2 (cons 3 [4 5])))
+
+
+
+
+

Sugared Java Interop

+
+

Use the sugared Java interop forms.

+
+
+
+
;;; object creation
+;; good
+(java.util.ArrayList. 100)
+
+;; bad
+(new java.util.ArrayList 100)
+
+;;; static method invocation
+;; good
+(Math/pow 2 10)
+
+;; bad
+(. Math pow 2 10)
+
+;;; instance method invocation
+;; good
+(.substring "hello" 1 3)
+
+;; bad
+(. "hello" substring 1 3)
+
+;;; static field access
+;; good
+Integer/MAX_VALUE
+
+;; bad
+(. Integer MAX_VALUE)
+
+;;; instance field access
+;; good
+(.someField some-object)
+
+;; bad
+(. some-object someField)
+
+
+
+
+

Compact Metadata Notation For True Flags

+
+

Use the compact metadata notation for metadata that contains only +slots whose keys are keywords and whose value is boolean true.

+
+
+
+
;; good
+(def ^:private a 5)
+
+;; bad
+(def ^{:private true} a 5)
+
+
+
+
+

Private

+
+

Denote private parts of your code.

+
+
+
+
;; good
+(defn- private-fun [] ...)
+
+(def ^:private private-var ...)
+
+;; bad
+(defn private-fun [] ...) ; not private at all
+
+(defn ^:private private-fun [] ...) ; overly verbose
+
+(def private-var ...) ; not private at all
+
+
+
+
+

Access Private Var

+
+

To access a private var (e.g. for testing), use the @#'some.ns/var form.

+
+
+
+

Attach Metadata Carefully

+
+

Be careful regarding what exactly do you attach metadata to.

+
+
+
+
;; we attach the metadata to the var referenced by `a`
+(def ^:private a {})
+(meta a) ;=> nil
+(meta #'a) ;=> {:private true}
+
+;; we attach the metadata to the empty hash-map value
+(def a ^:private {})
+(meta a) ;=> {:private true}
+(meta #'a) ;=> nil
+
+
+
+
+
+
+

Naming

+
+
+
+
+

The only real difficulties in programming are cache invalidation and +naming things.

+
+
+

 — Phil Karlton

+
+
+
+
+

Ns Naming Schemas

+
+

When naming namespaces favor the following two schemas:

+
+
+
    +
  • +

    project.module

    +
  • +
  • +

    organization.project.module

    +
  • +
+
+
+
+

Lisp Case Ns

+
+

Use lisp-case in composite namespace segments(e.g. bruce.project-euler)

+
+
+
+

Lisp Case

+
+

Use lisp-case for function and variable names.

+
+
+
+
;; good
+(def some-var ...)
+(defn some-fun ...)
+
+;; bad
+(def someVar ...)
+(defn somefun ...)
+(def some_fun ...)
+
+
+
+
+

Camelcase For Protocols Records Structs And Types

+
+

Use CamelCase for protocols, records, structs, and types. (Keep +acronyms like HTTP, RFC, XML uppercase.)

+
+
+
+

Pred With Question Mark

+
+

The names of predicate methods (methods that return a boolean value) +should end in a question mark +(e.g., even?).

+
+
+
+
;; good
+(defn palindrome? ...)
+
+;; bad
+(defn palindrome-p ...) ; Common Lisp style
+(defn is-palindrome ...) ; Java style
+
+
+
+
+

Changing State Fns With Exclamation Mark

+
+

The names of functions/macros that are not safe in STM transactions +should end with an exclamation mark (e.g. reset!).

+
+
+
+

Arrow Instead Of To

+
+

Use instead of to in the names of conversion functions.

+
+
+
+
;; good
+(defn f->c ...)
+
+;; not so good
+(defn f-to-c ...)
+
+
+
+
+

Earmuffs For Dynamic Vars

+
+

Use earmuffs for things intended for rebinding (ie. are dynamic).

+
+
+
+
;; good
+(def ^:dynamic *a* 10)
+
+;; bad
+(def ^:dynamic a 10)
+
+
+
+
+

Don’t Flag Constants

+
+

Don’t use a special notation for constants; everything is assumed a constant +unless specified otherwise.

+
+
+
+

Underscore For Unused Bindings

+
+

Use _ for destructuring targets and formal argument names whose +value will be ignored by the code at hand.

+
+
+
+
;; good
+(let [[a b _ c] [1 2 3 4]]
+  (println a b c))
+
+(dotimes [_ 3]
+  (println "Hello!"))
+
+;; bad
+(let [[a b c d] [1 2 3 4]]
+  (println a b d))
+
+(dotimes [i 3]
+  (println "Hello!"))
+
+
+
+
+

Idiomatic Names

+
+

Follow clojure.core's example for idiomatic names like pred and coll.

+
+
+
    +
  • +

    in functions:

    +
    +
      +
    • +

      f, g, h - function input

      +
    • +
    • +

      n - integer input usually a size

      +
    • +
    • +

      index, i - integer index

      +
    • +
    • +

      x, y - numbers

      +
    • +
    • +

      xs - sequence

      +
    • +
    • +

      m - map

      +
    • +
    • +

      s - string input

      +
    • +
    • +

      re - regular expression

      +
    • +
    • +

      coll - a collection

      +
    • +
    • +

      pred - a predicate closure

      +
    • +
    • +

      & more - variadic input

      +
    • +
    • +

      xf - xform, a transducer

      +
    • +
    +
    +
  • +
  • +

    in macros:

    +
    +
      +
    • +

      expr - an expression

      +
    • +
    • +

      body - a macro body

      +
    • +
    • +

      binding - a macro binding vector

      +
    • +
    +
    +
  • +
+
+
+
+
+
+

Data Structures

+
+
+
+
+

It is better to have 100 functions operate on one data structure +than to have 10 functions operate on 10 data structures.

+
+
+

 — Alan J. Perlis

+
+
+
+
+

Avoid Lists

+
+

Avoid the use of lists for generic data storage (unless a list is +exactly what you need).

+
+
+
+

Keywords For Hash Keys

+
+

Prefer the use of keywords for hash keys.

+
+
+
+
;; good
+{:name "Bruce" :age 30}
+
+;; bad
+{"name" "Bruce" "age" 30}
+
+
+
+
+

Literal Col Syntax

+
+

Prefer the use of the literal collection syntax where +applicable. However, when defining sets, only use literal syntax +when the values are compile-time constants.

+
+
+
+
;; good
+[1 2 3]
+#{1 2 3}
+(hash-set (func1) (func2)) ; values determined at runtime
+
+;; bad
+(vector 1 2 3)
+(hash-set 1 2 3)
+#{(func1) (func2)} ; will throw runtime exception if (func1) = (func2)
+
+
+
+
+

Avoid Index Based Coll Access

+
+

Avoid accessing collection members by index whenever possible.

+
+
+
+

Keywords As Fn To Get Map Values

+
+

Prefer the use of keywords as functions for retrieving values from +maps, where applicable.

+
+
+
+
(def m {:name "Bruce" :age 30})
+
+;; good
+(:name m)
+
+;; more verbose than necessary
+(get m :name)
+
+;; bad - susceptible to NullPointerException
+(m :name)
+
+
+
+
+

Colls As Fns

+
+

Leverage the fact that most collections are functions of their elements.

+
+
+
+
;; good
+(filter #{\a \e \o \i \u} "this is a test")
+
+;; bad - too ugly to share
+
+
+
+
+

Keywords As Fns

+
+

Leverage the fact that keywords can be used as functions of a collection.

+
+
+
+
((juxt :a :b) {:a "ala" :b "bala"})
+
+
+
+
+

Avoid Transient Colls

+
+

Avoid the use of transient collections, except for +performance-critical portions of the code.

+
+
+
+

Avoid Java Colls

+
+

Avoid the use of Java collections.

+
+
+
+

Avoid Java Arrays

+
+

Avoid the use of Java arrays, except for interop scenarios and +performance-critical code dealing heavily with primitive types.

+
+
+
+
+
+

Types & Records

+
+
+

Record Constructors

+
+

Don’t use the interop syntax to +construct type and record instances. deftype and defrecord +automatically create constructor functions. Use those instead of +the interop syntax, as they make it clear that you’re dealing with a +deftype or a defrecord. See this +article +for more details.

+
+
+
+
(defrecord Foo [a b])
+(deftype Bar [a b])
+
+;; good
+(->Foo 1 2)
+(map->Foo {:b 4 :a 3})
+(->Bar 1 2)
+
+;; bad
+(Foo. 1 2)
+(Bar. 1 2)
+
+
+
+

Note that deftype doesn’t define the map→Type + constructor. It’s available only for records.

+
+
+
+

Custom Record Constructors

+
+

Add custom type/record constructors when needed (e.g. to validate +properties on record creation). See this +article +for more details.

+
+
+
+
(defrecord Customer [id name phone email])
+
+(defn make-customer
+  "Creates a new customer record."
+  [{:keys [name phone email]}]
+  {:pre [(string? name)
+         (valid-phone? phone)
+         (valid-email? email)]}
+  (->Customer (next-id) name phone email))
+
+
+
+

Feel free to adopt whatever naming convention or structure you’d like for such custom constructors.

+
+
+
+

Custom Record Constructors Naming

+
+

Don’t override the auto-generated type/record constructor functions. +People expect them to have a certain behaviour and you changing this behaviour +violates the principle of the least surprise . See this +article +for more details.

+
+
+
+
(defrecord Foo [num])
+
+;; good
+(defn make-foo
+  [num]
+  {:pre [(pos? num)]}
+  (->Foo num))
+
+;; bad
+(defn ->Foo
+  [num]
+  {:pre [(pos? num)]}
+  (Foo. num))
+
+
+
+
+
+
+

Mutation

+
+
+

Refs

+
+

Refs Io Macro

+
+

Consider wrapping all I/O calls with the io! macro to avoid nasty +surprises if you accidentally end up calling such code in a +transaction.

+
+
+
+

Refs Avoid Ref Set

+
+

Avoid the use of ref-set whenever possible.

+
+
+
+
(def r (ref 0))
+
+;; good
+(dosync (alter r + 5))
+
+;; bad
+(dosync (ref-set r 5))
+
+
+
+
+

Refs Small Transactions

+
+

Try to keep the size of transactions (the amount of work encapsulated in them) +as small as possible.

+
+
+
+

Refs Avoid Short Long Transactions With Same Ref

+
+

Avoid having both short- and long-running transactions interacting +with the same Ref.

+
+
+
+
+

Agents

+
+

Agents Send

+
+

Use send only for actions that are CPU bound and don’t block on I/O +or other threads.

+
+
+
+

Agents Send Off

+
+

Use send-off for actions that might block, sleep, or otherwise tie +up the thread.

+
+
+
+
+

Atoms

+
+

Atoms No Update Within Transactions

+
+

Avoid atom updates inside STM transactions.

+
+
+
+

Atoms Prefer Swap Over Reset

+
+

Try to use swap! rather than reset!, where possible.

+
+
+
+
(def a (atom 0))
+
+;; good
+(swap! a + 5)
+
+;; not as good
+(reset! a 5)
+
+
+
+
+
+
+
+

Strings

+
+
+

Prefer Clojure String Over Interop

+
+

Prefer string manipulation functions from clojure.string over Java interop or rolling your own.

+
+
+
+
;; good
+(clojure.string/upper-case "bruce")
+
+;; bad
+(.toUpperCase "bruce")
+
+
+
+
+
+
+

Exceptions

+
+
+

Reuse Existing Exception Types

+
+

Reuse existing exception types. Idiomatic Clojure code — when it does +throw an exception — throws an exception of a standard type +(e.g. java.lang.IllegalArgumentException, +java.lang.UnsupportedOperationException, +java.lang.IllegalStateException, java.io.IOException).

+
+
+
+

Prefer with-open Over finally

+
+

Favor with-open over finally.

+
+
+
+
+
+

Macros

+
+
+

Don’t Write Macro If Fn Will Do

+
+

Don’t write a macro if a function will do.

+
+
+
+

Write Macro Usage Before Writing The Macro

+
+

Create an example of a macro usage first and the macro afterwards.

+
+
+
+

Break Complicated Macros

+
+

Break complicated macros into smaller functions whenever possible.

+
+
+
+

Macros As Syntactic Sugar

+
+

A macro should usually just provide syntactic sugar and the core of +the macro should be a plain function. Doing so will improve +composability.

+
+
+
+

Syntax Quoted Forms

+
+

Prefer syntax-quoted forms over building lists manually.

+
+
+
+
+
+

Comments

+
+
+
+
+

Good code is its own best documentation. As you’re about to add a +comment, ask yourself, "How can I improve the code so that this +comment isn’t needed?" Improve the code and then document it to make +it even clearer.

+
+
+

 — Steve McConnell

+
+
+
+
+

Self Documenting Code

+
+

Endeavor to make your code as self-documenting as possible.

+
+
+
+

Four Semicolons For Heading Comments

+
+

Write heading comments with at least four semicolons.

+
+
+
+

Three Semicolons For Top Level Comments

+
+

Write top-level comments with three semicolons.

+
+
+
+

Two Semicolons For Code Fragment

+
+

Write comments on a particular fragment of code before that fragment +and aligned with it, using two semicolons.

+
+
+
+

One Semicolon For Margin Comments

+
+

Write margin comments with one semicolon.

+
+
+
+

Semicolon Space

+
+

Always have at least one space between the semicolon +and the text that follows it.

+
+
+
+
;;;; Frob Grovel
+
+;;; This section of code has some important implications:
+;;;   1. Foo.
+;;;   2. Bar.
+;;;   3. Baz.
+
+(defn fnord [zarquon]
+  ;; If zob, then veeblefitz.
+  (quux zot
+        mumble             ; Zibblefrotz.
+        frotz))
+
+
+
+
+

English Syntax

+
+

Comments longer than a word begin with a capital letter and use +punctuation. Separate sentences with +one space.

+
+
+
+

No Superfluous Comments

+
+

Avoid superfluous comments.

+
+
+
+
;; bad
+(inc counter) ; increments counter by one
+
+
+
+
+

Comment Upkeep

+
+

Keep existing comments up-to-date. An outdated comment is worse than no comment +at all.

+
+
+
+

Dash Underscore Reader Macro

+
+

Prefer the use of the #_ reader macro over a regular comment when +you need to comment out a particular form.

+
+
+
+
;; good
+(+ foo #_(bar x) delta)
+
+;; bad
+(+ foo
+   ;; (bar x)
+   delta)
+
+
+
+
+

Refactor Don’t Comment

+
+
+
+

Good code is like a good joke - it needs no explanation.

+
+
+

 — Russ Olsen

+
+
+
+
+

Avoid writing comments to explain bad code. Refactor the code to +make it self-explanatory. ("Do, or do not. There is no try." --Yoda)

+
+
+
+

Comment Annotations

+
+

Annotate Above

+
+

Annotations should usually be written on the line immediately above +the relevant code.

+
+
+
+
;; good
+(defn some-fun
+  []
+  ;; FIXME: Replace baz with the newer bar.
+  (baz))
+
+;; bad
+;; FIXME: Replace baz with the newer bar.
+(defn some-fun
+  []
+  (baz))
+
+
+
+
+

Annotate Keywords

+
+

The annotation keyword is followed by a colon and a space, then a note +describing the problem.

+
+
+
+
;; good
+(defn some-fun
+  []
+  ;; FIXME: Replace baz with the newer bar.
+  (baz))
+
+;; bad - no colon after annotation
+(defn some-fun
+  []
+  ;; FIXME Replace baz with the newer bar.
+  (baz))
+
+;; bad - no space after colon
+(defn some-fun
+  []
+  ;; FIXME:Replace baz with the newer bar.
+  (baz))
+
+
+
+
+

Indent Annotations

+
+

If multiple lines are required to describe the problem, subsequent +lines should be indented as much as the first one.

+
+
+
+
;; good
+(defn some-fun
+  []
+  ;; FIXME: This has crashed occasionally since v1.2.3. It may
+  ;;        be related to the BarBazUtil upgrade. (xz 13-1-31)
+  (baz))
+
+;; bad
+(defn some-fun
+  []
+  ;; FIXME: This has crashed occasionally since v1.2.3. It may
+  ;; be related to the BarBazUtil upgrade. (xz 13-1-31)
+  (baz))
+
+
+
+
+

Sign And Date Annotations

+
+

Tag the annotation with your initials and a date so its relevance can +be easily verified.

+
+
+
+
(defn some-fun
+  []
+  ;; FIXME: This has crashed occasionally since v1.2.3. It may
+  ;;        be related to the BarBazUtil upgrade. (xz 13-1-31)
+  (baz))
+
+
+
+
+

Rare Eol Annotations

+
+

In cases where the problem is so obvious that any documentation would +be redundant, annotations may be left at the end of the offending line +with no note. This usage should be the exception and not the rule.

+
+
+
+
(defn bar
+  []
+  (sleep 100)) ; OPTIMIZE
+
+
+
+
+

TODO

+
+

Use TODO to note missing features or functionality that should be +added at a later date.

+
+
+
+

FIXME

+
+

Use FIXME to note broken code that needs to be fixed.

+
+
+
+

OPTIMIZE

+
+

Use OPTIMIZE to note slow or inefficient code that may cause +performance problems.

+
+
+
+

HACK

+
+

Use HACK to note "code smells" where questionable coding practices +were used and should be refactored away.

+
+
+
+

REVIEW

+
+

Use REVIEW to note anything that should be looked at to confirm it +is working as intended. For example: REVIEW: Are we sure this is how the +client does X currently?

+
+
+
+

Document Custom Annotations

+
+

Use other custom annotation keywords if it feels appropriate, but be +sure to document them in your project’s README or similar.

+
+
+
+
+
+
+

Documentation

+
+
+

Docstrings are the primary way to document Clojure code. Many definition forms +(e.g. def, defn, defmacro, ns) +support docstrings and usually it’s a good idea to make good use of them, regardless +of whether the var in question is something public or private.

+
+
+

If a definition form doesn’t support docstrings directly you can still supply them via +the :doc metadata attribute.

+
+
+

This section outlines some of the common conventions and best +practices for documenting Clojure code.

+
+
+

Prefer Docstrings

+
+

If a form supports docstrings directly prefer them over using :doc metadata:

+
+
+
+
;; good
+(defn foo
+  "This function doesn't do much."
+  []
+  ...)
+
+(ns foo.bar.core
+  "That's an awesome library.")
+
+;; bad
+(defn foo
+  ^{:doc "This function doesn't do much."}
+  []
+  ...)
+
+(ns ^{:doc "That's an awesome library.")
+  foo.bar.core)
+
+
+
+
+

Docstring Summary

+
+

Let the first line in the doc string be a complete, capitalized +sentence which concisely describes the var in question. This makes it +easy for tooling (Clojure editors and IDEs) to display a short a summary of +the docstring at various places.

+
+
+
+
;; good
+(defn frobnitz
+  "This function does a frobnitz.
+  It will do gnorwatz to achieve this, but only under certain
+  circumstances."
+  []
+  ...)
+
+;; bad
+(defn frobnitz
+  "This function does a frobnitz. It will do gnorwatz to
+  achieve this, but only under certain circumstances."
+  []
+  ...)
+
+
+
+
+

Document Pos Arguments

+
+

Document all positional arguments, and wrap them them with backticks +(`) so that editors and IDEs can identify them and potentially provide extra +functionality for them.

+
+
+
+
;; good
+(defn watsitz
+  "Watsitz takes a `frob` and converts it to a znoot.
+  When the `frob` is negative, the znoot becomes angry."
+  [frob]
+  ...)
+
+;; bad
+(defn watsitz
+  "Watsitz takes a frob and converts it to a znoot.
+  When the frob is negative, the znoot becomes angry."
+  [frob]
+  ...)
+
+
+
+
+

Document References

+
+

Wrap any var references in the docstring with ` so that tooling +can identify them.

+
+
+
+
;; good
+(defn wombat
+  "Acts much like `clojure.core/identity` except when it doesn't.
+  Takes `x` as an argument and returns that. If it feels like it."
+  [x]
+  ...)
+
+;; bad
+(defn wombat
+  "Acts much like clojure.core/identity except when it doesn't.
+  Takes `x` as an argument and returns that. If it feels like it."
+  [x]
+  ...)
+
+
+
+
+

Docstring Grammar

+
+

Docstrings should be comprised from +proper English sentences - this means every sentences should start +with an capitalized word and should end with the proper punctuation. Sentences +should be separated with a single space.

+
+
+
+
;; good
+(def foo
+  "All sentences should end with a period (or maybe an exclamation mark).
+  And the period should be followed by a space, unless it's the last sentence.")
+
+;; bad
+(def foo
+  "all sentences should end with a period (or maybe an exclamation mark).
+  And the period should be followed by a space, unless it's the last sentence")
+
+
+
+
+

Docstring Indentation

+
+

Indent multi-line docstrings by two spaces.

+
+
+
+
;; good
+(ns my.ns
+  "It is actually possible to document a ns.
+  It's a nice place to describe the purpose of the namespace and maybe even
+  the overall conventions used. Note how _not_ indenting the doc string makes
+  it easier for tooling to display it correctly.")
+
+;; bad
+(ns my.ns
+  "It is actually possible to document a ns.
+It's a nice place to describe the purpose of the namespace and maybe even
+the overall conventions used. Note how _not_ indenting the doc string makes
+it easier for tooling to display it correctly.")
+
+
+
+
+

Docstring Leading Trailing Whitespace

+
+

Neither start nor end your doc strings with any whitespace.

+
+
+
+
;; good
+(def foo
+  "I'm so awesome."
+  42)
+
+;; bad
+(def silly
+  "    It's just silly to start a doc string with spaces.
+  Just as silly as it is to end it with a bunch of them.      "
+  42)
+
+
+
+
+

Docstring After Fn Name

+
+

When adding a docstring — especially to a function using the above form — take +care to correctly place the docstring after the function name, not after the +argument vector. The latter is not invalid syntax and won’t cause an error, +but includes the string as a form in the function body without attaching it to +the var as documentation.

+
+
+
+
;; good
+(defn foo
+  "docstring"
+  [x]
+  (bar x))
+
+;; bad
+(defn foo [x]
+  "docstring"
+  (bar x))
+
+
+
+
+
+
+

Existential

+
+
+

Be Functional

+
+

Code in a functional way, using mutation only when it makes sense.

+
+
+
+

Be Consistent

+
+

Be consistent. In an ideal world, be consistent with these guidelines.

+
+
+
+

Common Sense

+
+

Use common sense.

+
+
+
+
+
+

Testing

+
+
+

Test Directory Structure

+
+

Store your tests in a separate directory, typically test/yourproject/ (as +opposed to src/yourproject/). Your build tool is responsible for making +them available in the contexts where they are necessary; most templates +will do this for you automatically.

+
+
+
+

Test Ns Naming

+
+

Name your ns yourproject.something-test, a file which usually lives in +test/yourproject/something_test.clj (or .cljc, cljs).

+
+
+
+

Test Naming

+
+

When using clojure.test, define your tests +with deftest and name them something-test.

+
+
+
+
;; good
+(deftest something-test ...)
+
+;; bad
+(deftest something-tests ...)
+(deftest test-something ...)
+(deftest something ...)
+
+
+
+
+
+
+

Library Organization

+
+
+

Coordinates

+
+

If you are publishing libraries to be used by others, make sure to +follow the Central Repository +guidelines +for choosing your groupId and artifactId. This helps to prevent +name conflicts and facilitates the widest possible use. A good +example is Component.

+
+
+
+

Minimize Dependencies

+
+

Avoid unnecessary dependencies. For example, a three-line utility +function copied into a project is usually better than a dependency +that drags in hundreds of vars you do not plan to use.

+
+
+
+

Tool-agnostic

+
+

Deliver core functionality and integration points in separate +artifacts. That way, consumers can consume your library without +being constrained by your unrelated tooling prefences. For example, +Component provides +core functionality, and +reloaded provides leiningen +integration.

+
+
+
+
+
+

Lint Tools

+
+
+

There are some lint tools created by the Clojure community that might aid you +in your endeavor to write idiomatic Clojure code.

+
+
+
    +
  • +

    Slamhound is a tool that will +automatically generate proper ns declarations from your existing code.

    +
  • +
  • +

    kibit is a static code analyzer for +Clojure which uses core.logic to +search for patterns of code for which there might exist a more idiomatic +function or macro.

    +
  • +
+
+
+
+
+

Contributing

+
+
+

Nothing written in this guide is set in stone. It’s my desire to work +together with everyone interested in Clojure coding style, so that we could +ultimately create a resource that will be beneficial to the entire Clojure +community.

+
+
+

Feel free to open tickets or send pull requests with improvements. Thanks in +advance for your help!

+
+
+

You can also support the style guide (and all my Clojure projects like +CIDER, nREPL, orchard, etc) with financial contributions via +Patreon and +PayPal.

+
+
+
+
+

License

+
+
+

Creative Commons License +This work is licensed under a +Creative Commons Attribution 3.0 Unported License

+
+
+
+
+

Spread the Word

+
+
+

A community-driven style guide is of little use to a community that +doesn’t know about its existence. Tweet about the guide, share it with +your friends and colleagues. Every comment, suggestion or opinion we +get makes the guide just a little bit better. And we want to have the +best possible guide, don’t we?

+
+
+
+
+
+
+
+1. *BSD/Solaris/Linux/OSX users are covered by default, Windows users have to be extra careful. +
+
+ + + + \ No newline at end of file From 5336e5b2ea88f84a876ee6c03e5d36dd5ec76ef5 Mon Sep 17 00:00:00 2001 From: Bozhidar Batsov Date: Mon, 10 Jun 2019 19:03:24 +0300 Subject: [PATCH 004/122] Create CNAME --- CNAME | 1 + 1 file changed, 1 insertion(+) create mode 100644 CNAME diff --git a/CNAME b/CNAME new file mode 100644 index 0000000..b6a7da0 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +guide.clojure.style \ No newline at end of file From f9de48b8d9e1f3790fb43db150407f5ae682ed67 Mon Sep 17 00:00:00 2001 From: ci-build Date: Tue, 11 Jun 2019 07:04:50 +0000 Subject: [PATCH 005/122] [skip ci] Update site --- index.html | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index fc79cb6..63be3d3 100644 --- a/index.html +++ b/index.html @@ -703,6 +703,25 @@

The Clojure Style Guide

asciidoctor +
+ + + + + +
+
Tip
+
+
+

Install the rouge gem to get nice syntax highlighting in the generated document.

+
+
+
+
gem install rouge
+
+
+
+

Translations of the guide are available in the following languages:

@@ -3291,7 +3310,7 @@

+
-

Lisp Case Ns

+

Composite Word Namespace Segments

Use lisp-case in composite namespace segments (e.g. bruce.project-euler).

-

Lisp Case

+

Functions and Variables

Use lisp-case for function and variable names.

@@ -2200,14 +2413,14 @@

-

Camelcase For Protocols Records Structs And Types

+

Protocols, Records, Structs And Types

Use CamelCase for protocols, records, structs, and types. (Keep acronyms like HTTP, RFC, XML uppercase.)

-

Pred With Question Mark

+

Predicate Methods

The names of predicate methods (methods that return a boolean value) should end in a question mark @@ -2225,14 +2438,14 @@

-

Changing State Fns With Exclamation Mark

+

Unsafe Functions

The names of functions/macros that are not safe in STM transactions should end with an exclamation mark (e.g. reset!).

-

Arrow Instead Of To

+

Conversion Functions

Use -> instead of to in the names of conversion functions.

@@ -2247,7 +2460,7 @@

<

-

Earmuffs For Dynamic Vars

+

Dynamic Vars

Use earmuffs for things intended for rebinding (ie. are dynamic).

@@ -2262,14 +2475,14 @@

-

Don’t Flag Constants

+

Constants

Don’t use a special notation for constants; everything is assumed a constant unless specified otherwise.

-

Underscore For Unused Bindings

+

Unused Bindings

Use _ for destructuring targets and formal argument names whose value will be ignored by the code at hand.

@@ -3493,219 +3706,8 @@

- \ No newline at end of file From 54e516d91d79588bd45b661f54ddb8111af600ab Mon Sep 17 00:00:00 2001 From: ci-build Date: Mon, 30 Nov 2020 11:06:14 +0000 Subject: [PATCH 041/122] [skip ci] Update site --- index.html | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index 5398063..d86c0ed 100644 --- a/index.html +++ b/index.html @@ -2399,6 +2399,20 @@

Use lisp-case for function and variable names.

+
+ + + + + +
+
Note
+
+Many non-Lisp programming communities refer to lisp-case as +kebab-case, but we all know that Lisp has existed way before kebab +was invented. +
+
;; good
@@ -2415,9 +2429,22 @@ 

Protocols, Records, Structs And Types

-

Use CamelCase for protocols, records, structs, and types. (Keep +

Use CapitalCase for protocols, records, structs, and types. (Keep acronyms like HTTP, RFC, XML uppercase.)

+
+ + + + + +
+
Note
+
+CapitalCase is also known as UpperCamelCase, `CapitalWords +and PascalCase. +
+

-

Literal Col Syntax

+

Literal Collection Syntax

Prefer the use of the literal collection syntax where applicable. However, when defining sets, only use literal syntax @@ -2681,13 +2681,13 @@

-

Avoid Index Based Coll Access

+

Avoid Index Based Collection Access

Avoid accessing collection members by index whenever possible.

-

Keywords As Fn To Get Map Values

+

Keywords as Functions for Map Values Retrieval

Prefer the use of keywords as functions for retrieving values from maps, where applicable.

@@ -2708,7 +2708,7 @@

-

Colls As Fns

+

Collections as Functions

Leverage the fact that most collections are functions of their elements.

@@ -2722,7 +2722,7 @@

-

Keywords As Fns

+

Keywords as Functions

Leverage the fact that keywords can be used as functions of a collection.

@@ -2733,14 +2733,14 @@

-

Avoid Transient Colls

+

Avoid Transient Collections

Avoid the use of transient collections, except for performance-critical portions of the code.

@@ -3733,7 +3748,7 @@

From 5da3b7fab30459fa43b3bf4d30ebbe932bd7ceef Mon Sep 17 00:00:00 2001 From: ci-build Date: Mon, 30 Nov 2020 11:47:10 +0000 Subject: [PATCH 044/122] [skip ci] Update site --- index.html | 68 +++++++++++++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/index.html b/index.html index 8889e78..4418d95 100644 --- a/index.html +++ b/index.html @@ -689,9 +689,9 @@

The Clojure Style Guide

  • Functions
  • Lint Tools
  • -
  • Contributing
  • +
  • History
  • +
  • Sources of Inspiration
  • +
  • Contributing + +
  • +
  • Colophon
  • License
  • Spread the Word
  • @@ -894,8 +901,8 @@

    "Clojure Programming" -and "The Joy of Clojure".

    +"Clojure Programming" +and "The Joy of Clojure".

    @@ -3697,6 +3704,67 @@

    +

    History

    +
    +
    +

    This guide was started in 2013 by Bozhidar Batsov, following the +success of a similar project he had created in the Ruby community.

    +
    +
    +

    Bozhidar was very passionate about both Clojure and good programming style and he wanted to bridge the between what was +covered by the Clojure library coding guidelines and what the style guides for languages like Java, Python and Ruby would typically cover. +Bozhidar still serves as the guide’s primary editor, but he definitely wouldn’t mind enlisting a few more editors to help with the +maintenance work.

    +
    +
    +

    Since the inception of the guide we’ve received a lot of feedback from members of the exceptional Clojure community around the world. +Thanks for all the suggestions and the support! Together we can make a resource beneficial to each and every Clojure developer out there.

    +
    +
    +
    +
    +

    Sources of Inspiration

    +
    +
    +

    Many people, books, presentations, articles and other style guides influenced the community Clojure style guide. Here are some of them:

    +
    + +
    +
    +

    Contributing

    @@ -3729,6 +3797,43 @@

    +
    +

    How to Contribute?

    +
    +

    It’s easy, just follow the contribution guidelines below:

    +
    +
    + +
    +
    +
    +
    +
    +

    Colophon

    +
    +
    +

    This guide is written in AsciiDoc and is published as HTML using AsciiDoctor. +The HTML version of the guide is hosted on GitHub Pages.

    +
    +
    +

    Originally the guide was written in Markdown, but was converted to AsciiDoc in 2019.

    +
    +
    +
    +
    ;; This is a good comment.
    +
    +;; this is a bad comment
    +
    +
    +
    +

    Obviously punctuation is not the most important thing about +a comment, but a bit of extra effort results in better experience +for the readers of our comments.

    +
    -

    Four Semicolons for Heading Comments

    +

    Heading Comments

    -

    Write heading comments with at least four semicolons.

    +

    Write heading comments with at least four semicolons. Those typically serve to outline/separate +major section of code, or to describe important ideas. Often you’d have a section comment followed +by a bunch of top-level comments.

    +
    +
    +
    +
    ;;;; Section Comment/Heading
    +
    +;;; Foo...
    +;;; Bar...
    +;;; Baz...
    +
    -

    Three Semicolons for Top Level Comments

    +

    Top-Level Comments

    Write top-level comments with three semicolons.

    +
    +
    +
    ;;; I'm a top-level comment.
    +;;; I live outside any definition.
    +
    +(defn foo [])
    +
    +
    +
    +

    + + + + +
    +
    Note
    +
    +While the classic Lisp tradition dictates the use of ;;; for +top-level comments, you’ll find plenty of Clojure code in the wild +that’s using ;; or even ;. +
    +
    -

    Two Semicolons for Code Fragment

    +

    Code Fragment (Line) Comments

    Write comments on a particular fragment of code before that fragment and aligned with it, using two semicolons.

    +
    +
    +
    (defn foo [x]
    +  ;; I'm a line/code fragment comment.
    +  x)
    +
    +
    +
    + + + + + +
    +
    Note
    +
    +While the classic Lisp tradition dictates the use of ;; for +line comments, you’ll find plenty of Clojure code in the wild +that’s using only ;. +
    +
    -

    One Semicolon for Margin Comments

    +

    Margin (Inline) Comments

    Write margin comments with one semicolon.

    +
    +
    +
    (defn foo [x]
    +  x ; I'm a line/code fragment comment.
    +  )
    +
    +
    +
    +

    Avoid using those in situation that would result in hanging closing parentheses.

    +
    + + +
    @@ -3943,7 +3963,7 @@

    From 8ce9e037c4148bc92efe336e33960207067ca582 Mon Sep 17 00:00:00 2001 From: ci-build Date: Tue, 1 Dec 2020 08:34:09 +0000 Subject: [PATCH 051/122] [skip ci] Update site --- index.html | 114 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 107 insertions(+), 7 deletions(-) diff --git a/index.html b/index.html index 9dd04b4..0ac577b 100644 --- a/index.html +++ b/index.html @@ -655,8 +655,13 @@

    The Clojure Style Guide

    +
    +

    This style guide evolves over time as additional conventions are identified and past conventions are rendered obsolete by changes in Clojure itself.

    +
    @@ -926,11 +934,93 @@

    coding standards for libraries, too.

    +
    +

    Guiding Principles

    +
    +
    +
    +

    Programs must be written for people to read, and only incidentally for machines to execute.

    +
    +
    +— Harold Abelson
    +Structure and Interpretation of Computer Programs +
    +
    +
    +

    It’s common knowledge that code is read much more often than it is written. +The guidelines provided here are intended to improve the readability of code and make it consistent across the wide spectrum of Clojure code. +They are also meant to reflect real-world usage of Clojure instead of a random ideal. When I had to choose between a very established practice +and a subjectively better alternative I’ve opted to recommend the established practice.[1]

    +
    +
    +

    There are some areas in which there is no clear consensus in the Clojure community regarding a particular style (like semantic indentation vs fixed indentation, semantic comments vs uniform comments, etc). +In such scenarios all popular styles are acknowledged and it’s up to you to pick one and apply it consistently.

    +
    +
    +

    Fortunately Clojure is a Lisp, and Lisps are fundamentally +simple. Even though this guide was created a few years after Clojure +(I published the first version in early 2013), you could see that most +Clojure code in the wild was fairly uniform. I attribute this to +both the simplicity I already mentioned and to the fact that since day +1 Clojurists adopted many of the style conventions of other +established Lisp dialects (e.g. Common Lisp and Scheme). This made +the work on this guide fairly easy and straight-forward, especially compared to +the massive exercise in frustration that was the +Community Ruby Style Guide.[2]

    +
    +
    +

    Clojure is famously optimized for simplicity and clarity. I’d like to believe that this guide is going to help you optimize for maximum +simplicity and clarity.

    +
    +
    +
    +

    A Note about Consistency

    +
    +
    +
    +

    A foolish consistency is the hobgoblin of little minds, adored by little statesmen and philosophers and divines.

    +
    +
    +
    +— Ralph Waldo Emerson +
    +
    +
    +

    A style guide is about consistency.[3] +Consistency with this style guide is important. +Consistency within a project is more important. +Consistency within one class or method is the most important.

    +
    +
    +

    However, know when to be inconsistent — sometimes style guide recommendations just aren’t applicable. When in doubt, use your best judgment. +Look at other examples and decide what looks best. And don’t hesitate to ask!

    -
    -

    Translations

    -
    +
    +

    In particular: do not break backwards compatibility just to comply with this guide!

    +
    +
    +

    Some other good reasons to ignore a particular guideline:

    +
    +
    +
      +
    • +

      When applying the guideline would make the code less readable, even for someone who is used to reading code that follows this style guide.

      +
    • +
    • +

      To be consistent with surrounding code that also breaks it (maybe for historic reasons) — although this is also an opportunity to clean up someone else’s mess (in true XP style).

      +
    • +
    • +

      Because the code in question predates the introduction of the guideline and there is no other reason to be modifying that code.

      +
    • +
    • +

      When the code needs to remain compatible with older versions of Clojure that don’t support the feature recommended by the style guide.

      +
    • +
    +
    +
    +
    +

    Translations

    Translations of the guide are available in the following languages:

    @@ -972,6 +1062,7 @@

    +

    Source Code Layout & Organization

    @@ -1154,7 +1245,7 @@

    Line Endings

    -

    Use Unix-style line endings.[1]

    +

    Use Unix-style line endings.[4]

    @@ -3958,12 +4049,21 @@


    -1. *BSD/Solaris/Linux/OSX users are covered by default, Windows users have to be extra careful. +1. Occasionally I might suggest to the reader to consider some alternatives, though. +
    +
    +2. You’ll notice that the Clojure style guide is pretty similar in structure to the Ruby style guide, which served as its main source of inspiration. +
    +
    +3. This section is heavily inspired by Python’s PEP-8 +
    +
    +4. *BSD/Solaris/Linux/OSX users are covered by default, Windows users have to be extra careful.
    From 7c8b608299dfa2523ee515cbaa8fd62e57885218 Mon Sep 17 00:00:00 2001 From: ci-build Date: Tue, 1 Dec 2020 08:37:20 +0000 Subject: [PATCH 052/122] [skip ci] Update site --- index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index 0ac577b..1bc6236 100644 --- a/index.html +++ b/index.html @@ -4052,7 +4052,7 @@

    1. Occasionally I might suggest to the reader to consider some alternatives, though.
    -2. You’ll notice that the Clojure style guide is pretty similar in structure to the Ruby style guide, which served as its main source of inspiration. +2. You’ll notice that the Clojure style guide is pretty similar in structure to the Ruby style guide, which served as its main source of inspiration. You’ll also notice that the Ruby style guide is much longer, mostly because of the complexity of the Ruby language.
    3. This section is heavily inspired by Python’s PEP-8 @@ -4063,7 +4063,7 @@

    From b592b074f5f58646713d240821ae025271402219 Mon Sep 17 00:00:00 2001 From: ci-build Date: Tue, 1 Dec 2020 08:44:59 +0000 Subject: [PATCH 053/122] [skip ci] Update site --- index.html | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/index.html b/index.html index 1bc6236..65520f6 100644 --- a/index.html +++ b/index.html @@ -904,14 +904,18 @@

    -

    This style guide evolves over time as additional conventions are identified and past conventions are rendered obsolete by changes in Clojure itself.

    +

    Nothing written here is set in stone. +This style guide evolves over time as additional conventions are +identified and past conventions are rendered obsolete by changes in +Clojure itself.

    @@ -951,7 +955,7 @@

    It’s common knowledge that code is read much more often than it is written. The guidelines provided here are intended to improve the readability of code and make it consistent across the wide spectrum of Clojure code. They are also meant to reflect real-world usage of Clojure instead of a random ideal. When I had to choose between a very established practice -and a subjectively better alternative I’ve opted to recommend the established practice.[1]

    +and a subjectively better alternative I’ve opted to recommend the established practice.[2]

    There are some areas in which there is no clear consensus in the Clojure community regarding a particular style (like semantic indentation vs fixed indentation, semantic comments vs uniform comments, etc). @@ -967,7 +971,7 @@

    Community Ruby Style Guide.[2]

    +Community Ruby Style Guide.[3]

    Clojure is famously optimized for simplicity and clarity. I’d like to believe that this guide is going to help you optimize for maximum @@ -987,7 +991,7 @@

    -

    A style guide is about consistency.[3] +

    A style guide is about consistency.[4] Consistency with this style guide is important. Consistency within a project is more important. Consistency within one class or method is the most important.

    @@ -1245,7 +1249,7 @@

    Line Endings

    -

    Use Unix-style line endings.[4]

    +

    Use Unix-style line endings.[5]

    @@ -4049,21 +4053,24 @@


    -1. Occasionally I might suggest to the reader to consider some alternatives, though. +1. CIDER, nREPL, Orchard, etc.
    -2. You’ll notice that the Clojure style guide is pretty similar in structure to the Ruby style guide, which served as its main source of inspiration. You’ll also notice that the Ruby style guide is much longer, mostly because of the complexity of the Ruby language. +2. Occasionally I might suggest to the reader to consider some alternatives, though.
    -3. This section is heavily inspired by Python’s PEP-8 +3. You’ll notice that the Clojure style guide is pretty similar in structure to the Ruby style guide, which served as its main source of inspiration. You’ll also notice that the Ruby style guide is much longer, mostly because of the complexity of the Ruby language.
    -4. *BSD/Solaris/Linux/OSX users are covered by default, Windows users have to be extra careful. +4. This section is heavily inspired by Python’s PEP-8 +
    +
    +5. *BSD/Solaris/Linux/OSX users are covered by default, Windows users have to be extra careful.
    From 6e3b1bb6615480c0ec447087474d35a14dce620b Mon Sep 17 00:00:00 2001 From: ci-build Date: Tue, 1 Dec 2020 09:02:08 +0000 Subject: [PATCH 054/122] [skip ci] Update site --- index.html | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index 65520f6..30df1e1 100644 --- a/index.html +++ b/index.html @@ -1417,7 +1417,46 @@

    Do not place blank lines in the middle of a function or macro definition. An exception can be made to indicate grouping of -pairwise constructs as found in e.g. let and cond.

    +pairwise constructs as found in e.g. let and cond, in case those don’t +fit on the same line.

    + +
    +
    +
    ;; good
    +(defn fibo-iter
    +  ([n] (fibo-iter 0 1 n))
    +  ([curr nxt n]
    +   (cond
    +     (zero? n) curr
    +     :else (recur nxt (+' curr nxt) (dec n)))))
    +
    +;; okay - the line break delimits a cond pair
    +(defn fibo-iter
    +  ([n] (fibo-iter 0 1 n))
    +  ([curr nxt n]
    +   (cond
    +     (zero? n)
    +     curr
    +
    +     :else
    +     (recur nxt (+' curr nxt) (dec n)))))
    +
    +;; bad
    +(defn fibo-iter
    +  ([n] (fibo-iter 0 1 n))
    +
    +  ([curr nxt n]
    +   (cond
    +     (zero? n) curr
    +
    +     :else (recur nxt (+' curr nxt) (dec n)))))
    +
    +
    +
    +

    Occasionally, it might seem like a good idea to add a blank line +here and there in a longer function definition, but if you get to this +point you should also consider whether this long function isn’t doing +too much and could potentially be broken down.

    @@ -4104,12 +4104,12 @@

    4. This section is heavily inspired by Python’s PEP-8

    -5. *BSD/Solaris/Linux/OSX users are covered by default, Windows users have to be extra careful. +5. *BSD/Solaris/Linux/macOS users are covered by default, Windows users have to be extra careful.
    From e5fa54d6efa709d65f462373e303c9be256f7eb9 Mon Sep 17 00:00:00 2001 From: ci-build Date: Tue, 1 Dec 2020 09:18:35 +0000 Subject: [PATCH 056/122] [skip ci] Update site --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index ddb80f5..1b45660 100644 --- a/index.html +++ b/index.html @@ -3294,7 +3294,7 @@

    -

    Avoid using those in situations that would result in hanging closing parentheses.

    +

    Avoid using those in situation that would result in hanging closing parentheses.

    @@ -3961,10 +3961,10 @@

    + + + + +
    +
    Tip
    +
    +It’s a great idea run such tools as part of your continuous integration (CI). +This ensure that all the code in one project is consistent with the style you’re +aiming for. +
    +
    +
    +

    Lint Tools

    +

    There are some lint tools created by the Clojure community that might aid you in your endeavor to write idiomatic Clojure code.

    @@ -3935,6 +3961,39 @@

    +
    +

    Code Formatters

    +
    +

    While most Clojure editors and IDEs can format the code, according to the layout guidelines +outlined here, it’s always handy to have some command-line code formatting tools. There are +a couple of options for Clojure that do a great job when it comes to formatting the code +as suggested in this guide:

    +
    +
    +
      +
    • +

      cljfmt

      +
    • +
    • +

      zprint (the documentation for configuring it to use the community formatting rules is here)

      +
    • +
    +
    +
    + + + + + +
    +
    Note
    +
    +When it comes to editors - Emacs’s clojure-mode by default will format the code exactly as outlined in the guide. +Other editors might require some configuration tweaking to produce the same results. +
    +
    +
    +
    +

    Threading Macros and Optional Parentheses

    +
    +

    Parentheses are not required when using the threading macros for functions having no argument specified, so use them only when necessary.

    +
    +
    +
    +
    ;; good
    +(-> x fizz :foo first frob)
    +
    +;; bad; parens add clutter and are not needed
    +(-> x (fizz) (:foo) (first) (frob))
    +
    +;; good, parens are necessary with an arg
    +(-> x
    +    (fizz a b)
    +    :foo
    +    first
    +    (frob x y))
    +
    +
    +
    +
    +

    Common Metadata

    +
    +
    +

    In this section we’ll go over some common metadata for namespaces and +vars that Clojure development tools can leverage.

    +
    +
    +

    :deprecated

    +
    +

    The most common way to mark deprecated public APIs is via the :deprecated +metadata. Normally you’d use as the value the version in which something +was deprecated in case of versioned software (e.g. a library) or simply +true in the case of unversioned software (e.g. some web application).

    +
    +
    +
    +
    (def ^{:deprecated "0.5"} foo
    +  "Use `bar` instead.
    +  42)
    +
    +(ns foo.bar
    +  "A deprecated ns."
    +  {:deprecated "0.8"})
    +
    +(defn ^{:deprecated "0.5"} foo
    +  (bar))
    +
    +
    +
    + + + + + +
    +
    Tip
    +
    +If you’re into SemVer, it’s a good idea to omit the patch version. +This means you should use 0.5 instead of 0.5.0. +
    +
    +
    +
    +
    +
    +

    :superseded-by

    +
    +

    Often you’d combine :deprecated with :superseded-by, as there would be +some newer API that supersedes whatever got deprecated.

    +
    +
    +

    Typically for vars you’ll use a non-qualified name if the replacement lives +in the same namespace, and a fully-qualified name otherwise.

    +
    +
    +
    +
    ;; in case we have a version
    +(def ^{:deprecated "0.5"
    +       :superseded-by "bar"} foo
    +  "Use `bar` instead.
    +  42)
    +
    +(ns foo.bar
    +  "A deprecated ns."
    +  {:deprecated "0.8"
    +   :superseded-by "foo.baz"})
    +
    +(defn ^{:deprecated "0.5"
    +        :superseded-by "bar"} foo
    +  (bar))
    +
    +;; otherwise
    +(defn ^{:deprecated true
    +        :superseded-by "bar"} foo
    +  (bar))
    +
    +
    +
    +
    +
    + + + + + +
    +
    Tip
    +
    +You can also consider adding :supersedes metadata to the newer APIs, basically the inverse of :superseded-by. +
    +

    :added

    @@ -4307,7 +4319,7 @@

    From 447a513e5734ef301e857aae277ef196e2a9a81d Mon Sep 17 00:00:00 2001 From: ci-build Date: Sat, 5 Dec 2020 09:47:50 +0000 Subject: [PATCH 069/122] [skip ci] Update site --- index.html | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/index.html b/index.html index 0bf7a67..54976b8 100644 --- a/index.html +++ b/index.html @@ -3241,7 +3241,9 @@

    +

    :added

    +
    +

    The most common way to document when a public API was added to a +library is via the :added metadata.

    +
    +
    +
    +
    (def ^{:added "0.5"} foo
    +  42)
    +
    +(ns foo.bar
    +  "A very useful ns."
    +  {:added "0.8"})
    +
    +(defn ^{:added "0.5"} foo
    +  (bar))
    +
    +
    +
    + + + + + +
    +
    Tip
    +
    +If you’re into SemVer, it’s a good idea to omit the patch version. +This means you should use 0.5 instead of 0.5.0. This applies +for all metadata data that’s version related. +
    +
    +
    +
    +

    :changed

    +
    +

    The most common way to document when a public API was changed in a +library is via the :changed metadata. This metadata makes sense only for +vars and you should be using it sparingly, as changing the behavior of +a public API is generally a bad idea.

    +
    +
    +

    Still, if you decide to do it, it’s best to make that clear to the API +users.

    +
    +
    +
    +
    (def ^{:added "0.5"
    +       :changed "0.6"} foo
    +  43)
    +
    +
    +
    +

    :deprecated

    The most common way to mark deprecated public APIs is via the :deprecated @@ -3270,20 +3325,6 @@

    "DEPRECATED: A deprecated ns.")

    -
    - - - - - -
    -
    Tip
    -
    -If you’re into SemVer, it’s a good idea to omit the patch version. -This means you should use 0.5 instead of 0.5.0. This applies -for all metadata data that’s version related. -
    -

    :superseded-by

    @@ -3331,26 +3372,6 @@

    -

    :added

    -
    -

    The most common way to document when a public API was added to a -library is via the :added metadata.

    -
    -
    -
    -
    (def ^{:added "0.5"} foo
    -  42)
    -
    -(ns foo.bar
    -  "A very useful ns."
    -  {:added "0.8"})
    -
    -(defn ^{:added "0.5"} foo
    -  (bar))
    -
    -
    -

    @@ -4331,7 +4352,7 @@

    From 34666e491fbe3f1434a8267644eb70ca43e779c2 Mon Sep 17 00:00:00 2001 From: ci-build Date: Sat, 5 Dec 2020 10:23:58 +0000 Subject: [PATCH 071/122] [skip ci] Update site --- index.html | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index c3d9adc..dacc3c2 100644 --- a/index.html +++ b/index.html @@ -819,6 +819,8 @@

    The Clojure Style Guide

  • :changed
  • :deprecated
  • :superseded-by
  • +
  • :see-also
  • +
  • Indentation Metadata
  • Comments @@ -3372,6 +3374,93 @@

    +

    :see-also

    +
    +

    From time to time you might want to point out some related vars/namespaces that the users of your library might be interested in. +The most common way to do so would be via the :see-also metadata, which takes a vector of related items. +When talking about vars - items in the same namespace don’t need to fully qualified.

    +
    +
    +
    +
    ;; refers to vars in the same ns
    +(def ^{:see-also ["bar" "baz"]} foo
    +  "A very useful var."
    +  42)
    +
    +;; refers to vars in some other ns
    +(defn ^{:see-also ["top.bar" "top.baz"]} foo
    +  (bar))
    +
    +
    +
    + + + + + +
    +
    Note
    +
    +Many Clojure programming tools will also try to extract references to other vars from the docstring, but it’s both +simpler and more explicit to use the :see-also metadata instead. +
    +
    +

  • +
    +

    Indentation Metadata

    +
    +

    Unlike other Lisp dialects, Clojure doesn’t have a standard metadata format to specify the indentation of macros. +CIDER proposed a tool-agnostic indentation specification based on metadata in 2015.[6] Here’s a simple example:

    +
    +
    +
    +
    ;; refers to vars in the same ns
    +(defmacro with-in-str
    +  "[DOCSTRING]"
    +  {:style/indent 1}
    +  [s & body]
    +  ...cut for brevity...)
    +
    +
    +
    +

    This instructs the indentation engine that this is a macro with one ordinary parameter and a body after it.

    +
    +
    +
    +
    ;; without metadata (indented as a regular function)
    +(dop-iin-str some-string
    +             foo
    +             bar
    +             baz)
    +
    +;; with metadata (indented as macro with one special param and a body)
    +(with-in-str some-string
    +  foo
    +  bar
    +  baz)
    +
    +
    +
    +

    Unfortunately, as of 2020 there’s still no widespread adoption of :style/indent and many editors and IDEs would just +hardcode the indentation rules for common macros.

    +
    +
    + + + + + +
    +
    Note
    +
    +This approach to indentation ("semantic indentation") is a contested topic in the Clojure community, due to the +need for the additional metadata and tooling support. Despite the long tradition of that approach in the Lisp community +in general, some people argue to just stop treating functions and macros differently and simply indent everything with a fixed +indentation. This article is one popular presentation of that alternative approach. +
    +
    +
    @@ -4349,10 +4438,13 @@

    5. *BSD/Solaris/Linux/macOS users are covered by default, Windows users have to be extra careful.

    +
    +6. This was first introduced in CIDER 0.10 +
    From c4c11fcaa48af0b3cfb7413ca68fb31acd184d53 Mon Sep 17 00:00:00 2001 From: ci-build Date: Sat, 5 Dec 2020 16:19:12 +0000 Subject: [PATCH 072/122] [skip ci] Update site --- index.html | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 136 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index dacc3c2..d0b5d11 100644 --- a/index.html +++ b/index.html @@ -691,6 +691,8 @@

    The Clojure Style Guide

  • Line Breaks in ns
  • Prefer :require Over :use
  • Sort requirements and imports
  • +
  • Use Idiomatic Namespace Aliases
  • +
  • Use Consistent Namespace Aliases
  • Functions @@ -1639,6 +1641,139 @@

    +

    Use Idiomatic Namespace Aliases

    +
    +

    Many core Clojure namespaces have idiomatic aliases that you’re +encouraged to use within your projects - e.g. the most common way to +require clojure.string is: [clojure.string :as str].

    +
    +
    + + + + + +
    +
    Note
    +
    +This may appear to mask +clojure.core.str, but it doesn’t. It’s expected that +clojure.core/str and clojure.string/* to be used in a namespace as +str and str/whatever without conflict. +
    +
    +
    +
    +
    ;; good
    +(ns ... (:require [clojure.string :as str] ...)
    +
    +(str/join ...)
    +
    +;; not as good - just be idiomatic and use as `str/`
    +(ns ... (:require [clojure.string :as string] ...)
    +
    +(string/join ...)
    +
    +
    +
    +

    Bellow are some common idiomatic aliases:

    +
    + ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Namespace

    Idiomatic Alias

    io

    clojure.java.io

    set

    clojure.set

    str

    clojure.string

    walk

    clojure.walk

    zip

    clojure.zip

    xml

    clojure.data.xml

    as

    clojure.core.async

    mat

    clojure.core.matrix

    edn

    clojure.edn

    pp

    clojure.pprint

    spec

    clojure.spec.alpha

    csv

    clojure.data.csv

    json

    cheshire.core

    time

    java-time

    http

    clj-http.client

    log

    clojure.tools.logging

    sql

    hugsql.core

    yaml

    clj-yaml.core

    sh

    clojure.java.shell

    + +
    +

    Use Consistent Namespace Aliases

    +
    +

    Across a project, it’s good to be consistent with namespace aliases; e.g., don’t require clojure.string as str in one namespace but string in another.

    +
    +

  • @@ -1769,9 +1770,96 @@

    +

    A Recipe for Good Namespace Aliases

    +
    +

    Above we covered a handful of popular namespaces and their idiomatic aliases. +You might have noticed that those are a bit inconsistent:

    +
    +
    +
      +
    • +

      clojure.string becomes str

      +
    • +
    • +

      clojure.pprint becomes pp

      +
    • +
    • +

      clojure.walk becomes walk

      +
    • +
    • +

      clojure.spec.alpha becomes spec

      +
    • +
    +
    +
    +

    I guess it’s clear that the one thing they have in common is that they aim to be concise, but still carry some meaning (aliasing clojure.walk to w would +be concise, but won’t carry much meaning).

    +
    +
    +

    But what to do about all the other namespaces out there that don’t have idiomatic aliases? Well, you better be consistent in your approach to deriving aliases for them, +otherwise the people working on a shared Clojure codebase are going to experience a great deal of confusion. Here are a few rules that you should follow.[6]

    +
    +
    +
      +
    1. +

      Make the alias the same as the namespace name with the leading parts removed.

      +
    2. +
    +
    +
    +
    +
    (ns com.example.application
    +  (:require
    +   [clojure.java.io :as io]
    +   [clojure.string :as string]))
    +
    +
    +
    +
      +
    1. +

      Keep enough trailing parts to make each alias unique.

      +
    2. +
    +
    +
    +
    +
    [clojure.data.xml :as data.xml]
    +[clojure.xml :as xml]
    +
    +
    +
    + + + + + +
    +
    Tip
    +
    +Yes, namespace aliases can have dots in them. Make good use of them. +
    +
    +
    +
      +
    1. +

      Eliminate redundant words such as "core" and "clj" in aliases.

      +
    2. +
    +
    +
    +
    +
    [clj-http :as http]
    +[clj-time.core :as time]
    +[clj-time.format :as time.format]
    +
    +
    + +

    Use Consistent Namespace Aliases

    -

    Across a project, it’s good to be consistent with namespace aliases; e.g., don’t require clojure.string as str in one namespace but string in another.

    +

    Across a project, it’s good to be consistent with namespace aliases; e.g., don’t require clojure.string as str in one namespace but string in another. +If you follow the previous two guidelines you’re basically covered, but if you opt for custom namespace aliasing scheme it’s still important to apply it +consistently within your projects.

    @@ -3546,7 +3634,7 @@

    Indentation Metadata

    Unlike other Lisp dialects, Clojure doesn’t have a standard metadata format to specify the indentation of macros. -CIDER proposed a tool-agnostic indentation specification based on metadata in 2015.[6] Here’s a simple example:

    +CIDER proposed a tool-agnostic indentation specification based on metadata in 2015.[7] Here’s a simple example:

    @@ -4574,12 +4662,15 @@

    5. *BSD/Solaris/Linux/macOS users are covered by default, Windows users have to be extra careful.

    -6. This was first introduced in CIDER 0.10 +6. These guidelines are based on a blog post by Stuart Sierra. +
    +
    +7. This was first introduced in CIDER 0.10
    From ffc90c57543fb80aec6ea09aaf95081efef73ee1 Mon Sep 17 00:00:00 2001 From: ci-build Date: Sat, 5 Dec 2020 16:41:45 +0000 Subject: [PATCH 074/122] [skip ci] Update site --- index.html | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/index.html b/index.html index 52fe785..4cfaf19 100644 --- a/index.html +++ b/index.html @@ -1691,80 +1691,80 @@

    Idiomatic Alias

    -

    io

    clojure.java.io

    +

    io

    -

    set

    clojure.set

    +

    set

    -

    str

    clojure.string

    +

    str

    -

    walk

    clojure.walk

    +

    walk

    -

    zip

    clojure.zip

    +

    zip

    -

    xml

    clojure.data.xml

    +

    xml

    -

    as

    clojure.core.async

    +

    as

    -

    mat

    clojure.core.matrix

    +

    mat

    -

    edn

    clojure.edn

    +

    edn

    -

    pp

    clojure.pprint

    +

    pp

    -

    spec

    clojure.spec.alpha

    +

    spec

    -

    csv

    clojure.data.csv

    +

    csv

    -

    json

    cheshire.core

    +

    json

    -

    time

    java-time

    +

    time

    -

    http

    clj-http.client

    +

    http

    -

    log

    clojure.tools.logging

    +

    log

    -

    sql

    hugsql.core

    +

    sql

    -

    yaml

    clj-yaml.core

    +

    yaml

    -

    sh

    clojure.java.shell

    +

    sh

    @@ -4670,7 +4670,7 @@

    From 40e6cb755f938a82cb33d16978f47eacb0154492 Mon Sep 17 00:00:00 2001 From: ci-build Date: Sat, 5 Dec 2020 21:32:07 +0000 Subject: [PATCH 075/122] [skip ci] Update site --- index.html | 1312 ++++++++++++++++++++++++++-------------------------- 1 file changed, 656 insertions(+), 656 deletions(-) diff --git a/index.html b/index.html index 4cfaf19..609ed28 100644 --- a/index.html +++ b/index.html @@ -696,6 +696,21 @@

    The Clojure Style Guide

  • Use Consistent Namespace Aliases
  • +
  • Naming + +
  • Functions
  • -
  • Naming - -
  • Data Structures
    • Avoid Lists
    • @@ -1865,201 +1865,466 @@

      -

      Functions

      +

      Naming

      -
      -

      Optional New Line After Function Name

      +
      +
      -

      Optionally omit the new line between the function name and argument -vector for defn when there is no docstring.

      -
      -
      -
      -
      ;; good
      -(defn foo
      -  [x]
      -  (bar x))
      -
      -;; good
      -(defn foo [x]
      -  (bar x))
      -
      -;; bad
      -(defn foo
      -  [x] (bar x))
      +

      The only real difficulties in programming are cache invalidation and +naming things.

      +
      +
      +— Phil Karlton
      -

      Multimethod Dispatch Val Placement

      +

      Namespace Naming Schemas

      -

      Place the dispatch-val of a multimethod on the same line as the -function name.

      +

      When naming namespaces favor the following two schemas:

      -
      -
      -
      ;; good
      -(defmethod foo :bar [x] (baz x))
      -
      -(defmethod foo :bar
      -  [x]
      -  (baz x))
      -
      -;; bad
      -(defmethod foo
      -  :bar
      -  [x]
      -  (baz x))
      -
      -(defmethod foo
      -  :bar [x]
      -  (baz x))
      +
      +
        +
      • +

        project.module

        +
      • +
      • +

        organization.project.module

        +
      • +
      +
      +

      Composite Word Namespace Segments

      +
      +

      Use lisp-case in composite namespace segments (e.g. bruce.project-euler).

      +
      -

      Oneline Short Function

      +

      Functions and Variables

      -

      Optionally omit the new line between the argument vector and a short -function body.

      +

      Use lisp-case for function and variable names.

      +
      +
      + + + + + +
      +
      Note
      +
      +Many non-Lisp programming communities refer to lisp-case as +kebab-case, but we all know that Lisp has existed way before kebab +was invented. +
      ;; good
      -(defn foo [x]
      -  (bar x))
      -
      -;; good for a small function body
      -(defn foo [x] (bar x))
      -
      -;; good for multi-arity functions
      -(defn foo
      -  ([x] (bar x))
      -  ([x y]
      -   (if (predicate? x)
      -     (bar x)
      -     (baz x))))
      +(def some-var ...)
      +(defn some-fun ...)
       
       ;; bad
      -(defn foo
      -  [x] (if (predicate? x)
      -        (bar x)
      -        (baz x)))
      +(def someVar ...) +(defn somefun ...) +(def some_fun ...)
      -

      Multiple Arity Indentation

      +

      Protocols, Records, Structs And Types

      -

      Indent each arity form of a function definition vertically aligned with its -parameters.

      -
      -
      -
      -
      ;; good
      -(defn foo
      -  "I have two arities."
      -  ([x]
      -   (foo x 1))
      -  ([x y]
      -   (+ x y)))
      -
      -;; bad - extra indentation
      -(defn foo
      -  "I have two arities."
      -  ([x]
      -    (foo x 1))
      -  ([x y]
      -    (+ x y)))
      +

      Use CapitalCase for protocols, records, structs, and types. (Keep +acronyms like HTTP, RFC, XML uppercase.)

      +
      + + + + + +
      +
      Note
      +
      +CapitalCase is also known as UpperCamelCase, `CapitalWords +and PascalCase. +
      -

      Multiple Arity Order

      +

      Predicate Methods

      -

      Sort the arities of a function -from fewest to most arguments. The common case of multi-arity -functions is that some K arguments fully specifies the function’s -behavior, and that arities N < K partially apply the K arity, and -arities N > K provide a fold of the K arity over varargs.

      +

      The names of predicate methods (methods that return a boolean value) +should end in a question mark +(e.g., even?).

      -
      ;; good - it's easy to scan for the nth arity
      -(defn foo
      -  "I have two arities."
      -  ([x]
      -   (foo x 1))
      -  ([x y]
      -   (+ x y)))
      -
      -;; okay - the other arities are applications of the two-arity
      -(defn foo
      -  "I have two arities."
      -  ([x y]
      -   (+ x y))
      -  ([x]
      -   (foo x 1))
      -  ([x y z & more]
      -   (reduce foo (foo x (foo y z)) more)))
      +
      ;; good
      +(defn palindrome? ...)
       
      -;; bad - unordered for no apparent reason
      -(defn foo
      -  ([x] 1)
      -  ([x y z] (foo x (foo y z)))
      -  ([x y] (+ x y))
      -  ([w x y z & more] (reduce foo (foo w (foo x (foo y z))) more)))
      +
      ;; bad +(defn palindrome-p ...) ; Common Lisp style +(defn is-palindrome ...) ; Java style
      -

      Function Length

      +

      Unsafe Functions

      -

      Avoid functions longer than 10 LOC (lines of code). Ideally, most -functions will be shorter than 5 LOC.

      +

      The names of functions/macros that are not safe in STM transactions +should end with an exclamation mark (e.g. reset!).

      -

      Function Positional Parameters Limit

      +

      Conversion Functions

      -

      Avoid parameter lists with more than three or four positional parameters.

      +

      Use -> instead of to in the names of conversion functions.

      +
      +
      +
      +
      ;; good
      +(defn f->c ...)
      +
      +;; not so good
      +(defn f-to-c ...)
      +
      -

      Pre and Post Conditions

      +

      Dynamic Vars

      -

      Prefer function pre and post conditions to checks inside a function’s body.

      +

      Use earmuffs for things intended for rebinding (ie. are dynamic).

      ;; good
      -(defn foo [x]
      -  {:pre [(pos? x)]}
      -  (bar x))
      +(def ^:dynamic *a* 10)
       
       ;; bad
      -(defn foo [x]
      -  (if (pos? x)
      -    (bar x)
      -    (throw (IllegalArgumentException. "x must be a positive number!")))
      -
      -
      +(def ^:dynamic a 10)
      -
      -

      Idioms

      -
      -

      Dynamic Namespace Manipulation

      +

      Constants

      -

      Avoid the use of namespace-manipulating functions like require and -refer. They are entirely unnecessary outside of a REPL -environment.

      +

      Don’t use a special notation for constants; everything is assumed a constant +unless specified otherwise.

      -

      Forward References

      +

      Unused Bindings

      +
      +

      Use _ for destructuring targets and formal argument names whose +value will be ignored by the code at hand.

      +
      +
      +
      +
      ;; good
      +(let [[a b _ c] [1 2 3 4]]
      +  (println a b c))
      +
      +(dotimes [_ 3]
      +  (println "Hello!"))
      +
      +;; bad
      +(let [[a b c d] [1 2 3 4]]
      +  (println a b d))
      +
      +(dotimes [i 3]
      +  (println "Hello!"))
      +
      +
      +
      +

      However, when it can help the understanding of your code, it can be useful to explicitly name unused arguments or maps you’re destructuring from. In this case, prepend the name with an underscore to explicitly signal that the variable is supposed to be unused.

      +
      +
      +
      +
      ;; good
      +(defn myfun1 [context _]
      + (assoc context :foo "bar"))
      +
      +(defn myfun2 [context {:keys [id]}]
      + (assoc context :user-id id))
      +
      +;; better
      +(defn myfun1 [context _user]
      + (assoc context :foo "bar"))
      +
      +(defn myfun2 [context {:keys [id] :as _user}]
      + (assoc context :user-id id))
      +
      +
      +
      +
      +

      Idiomatic Names

      +
      +

      Follow clojure.core's example for idiomatic names like pred and coll.

      +
      +
      +
        +
      • +

        in functions:

        +
        +
          +
        • +

          f, g, h - function input

          +
        • +
        • +

          n - integer input usually a size

          +
        • +
        • +

          index, i - integer index

          +
        • +
        • +

          x, y - numbers

          +
        • +
        • +

          xs - sequence

          +
        • +
        • +

          m - map

          +
        • +
        • +

          s - string input

          +
        • +
        • +

          re - regular expression

          +
        • +
        • +

          coll - a collection

          +
        • +
        • +

          pred - a predicate closure

          +
        • +
        • +

          & more - variadic input

          +
        • +
        • +

          xf - xform, a transducer

          +
        • +
        +
        +
      • +
      • +

        in macros:

        +
        +
          +
        • +

          expr - an expression

          +
        • +
        • +

          body - a macro body

          +
        • +
        • +

          binding - a macro binding vector

          +
        • +
        +
        +
      • +
      +
      +
      +
      +
      +
      +

      Functions

      +
      +
      +

      Optional New Line After Function Name

      +
      +

      Optionally omit the new line between the function name and argument +vector for defn when there is no docstring.

      +
      +
      +
      +
      ;; good
      +(defn foo
      +  [x]
      +  (bar x))
      +
      +;; good
      +(defn foo [x]
      +  (bar x))
      +
      +;; bad
      +(defn foo
      +  [x] (bar x))
      +
      +
      +
      +
      +

      Multimethod Dispatch Val Placement

      +
      +

      Place the dispatch-val of a multimethod on the same line as the +function name.

      +
      +
      +
      +
      ;; good
      +(defmethod foo :bar [x] (baz x))
      +
      +(defmethod foo :bar
      +  [x]
      +  (baz x))
      +
      +;; bad
      +(defmethod foo
      +  :bar
      +  [x]
      +  (baz x))
      +
      +(defmethod foo
      +  :bar [x]
      +  (baz x))
      +
      +
      +
      +
      +

      Oneline Short Function

      +
      +

      Optionally omit the new line between the argument vector and a short +function body.

      +
      +
      +
      +
      ;; good
      +(defn foo [x]
      +  (bar x))
      +
      +;; good for a small function body
      +(defn foo [x] (bar x))
      +
      +;; good for multi-arity functions
      +(defn foo
      +  ([x] (bar x))
      +  ([x y]
      +   (if (predicate? x)
      +     (bar x)
      +     (baz x))))
      +
      +;; bad
      +(defn foo
      +  [x] (if (predicate? x)
      +        (bar x)
      +        (baz x)))
      +
      +
      +
      +
      +

      Multiple Arity Indentation

      +
      +

      Indent each arity form of a function definition vertically aligned with its +parameters.

      +
      +
      +
      +
      ;; good
      +(defn foo
      +  "I have two arities."
      +  ([x]
      +   (foo x 1))
      +  ([x y]
      +   (+ x y)))
      +
      +;; bad - extra indentation
      +(defn foo
      +  "I have two arities."
      +  ([x]
      +    (foo x 1))
      +  ([x y]
      +    (+ x y)))
      +
      +
      +
      +
      +

      Multiple Arity Order

      +
      +

      Sort the arities of a function +from fewest to most arguments. The common case of multi-arity +functions is that some K arguments fully specifies the function’s +behavior, and that arities N < K partially apply the K arity, and +arities N > K provide a fold of the K arity over varargs.

      +
      +
      +
      +
      ;; good - it's easy to scan for the nth arity
      +(defn foo
      +  "I have two arities."
      +  ([x]
      +   (foo x 1))
      +  ([x y]
      +   (+ x y)))
      +
      +;; okay - the other arities are applications of the two-arity
      +(defn foo
      +  "I have two arities."
      +  ([x y]
      +   (+ x y))
      +  ([x]
      +   (foo x 1))
      +  ([x y z & more]
      +   (reduce foo (foo x (foo y z)) more)))
      +
      +;; bad - unordered for no apparent reason
      +(defn foo
      +  ([x] 1)
      +  ([x y z] (foo x (foo y z)))
      +  ([x y] (+ x y))
      +  ([w x y z & more] (reduce foo (foo w (foo x (foo y z))) more)))
      +
      +
      +
      +
      +

      Function Length

      +
      +

      Avoid functions longer than 10 LOC (lines of code). Ideally, most +functions will be shorter than 5 LOC.

      +
      +
      +
      +

      Function Positional Parameters Limit

      +
      +

      Avoid parameter lists with more than three or four positional parameters.

      +
      +
      +
      +

      Pre and Post Conditions

      +
      +

      Prefer function pre and post conditions to checks inside a function’s body.

      +
      +
      +
      +
      ;; good
      +(defn foo [x]
      +  {:pre [(pos? x)]}
      +  (bar x))
      +
      +;; bad
      +(defn foo [x]
      +  (if (pos? x)
      +    (bar x)
      +    (throw (IllegalArgumentException. "x must be a positive number!")))
      +
      +
      +
      +
      +
      +
      +

      Idioms

      +
      +
      +

      Dynamic Namespace Manipulation

      +
      +

      Avoid the use of namespace-manipulating functions like require and +refer. They are entirely unnecessary outside of a REPL +environment.

      +
      +
      +
      +

      Forward References

      Avoid forward references. They are occasionally necessary, but such occasions are rare in practice.

      @@ -2389,661 +2654,396 @@

      -

      complement

      -
      -

      Favor the use of complement versus the use of an anonymous function.

      -
      -
      -
      -
      ;; good
      -(filter (complement some-pred?) coll)
      -
      -;; bad
      -(filter #(not (some-pred? %)) coll)
      -
      -
      -
      -

      This rule should obviously be ignored if the complementing predicate -exists in the form of a separate function (e.g. even? and odd?).

      -
      -

      -
      -

      comp

      -
      -

      Favor comp over anonymous functions for function composition.

      -
      -
      -
      -
      ;; Assuming `(:require [clojure.string :as str])`...
      -
      -;; good
      -(map #(str/capitalize (str/trim %)) ["top " " test "])
      -
      -;; better
      -(map (comp str/capitalize str/trim) ["top " " test "])
      -
      -
      -
      -
      -

      partial

      -
      -

      Favor partial over anonymous functions for currying.

      -
      -
      -
      -
      ;; good
      -(map #(+ 5 %) (range 1 10))
      -
      -;; (arguably) better
      -(map (partial + 5) (range 1 10))
      -
      -
      -
      -
      -

      Threading Macros

      -
      -

      Prefer the use of the threading macros -> (thread-first) and ->> -(thread-last) to heavy form nesting.

      -
      -
      -
      -
      ;; good
      -(-> [1 2 3]
      -    reverse
      -    (conj 4)
      -    prn)
      -
      -;; not as good
      -(prn (conj (reverse [1 2 3])
      -           4))
      -
      -;; good
      -(->> (range 1 10)
      -     (filter even?)
      -     (map (partial * 2)))
      -
      -;; not as good
      -(map (partial * 2)
      -     (filter even? (range 1 10)))
      -
      -
      -
      -
      -

      Threading Macros and Optional Parentheses

      -
      -

      Parentheses are not required when using the threading macros for functions having no argument specified, so use them only when necessary.

      -
      -
      -
      -
      ;; good
      -(-> x fizz :foo first frob)
      -
      -;; bad; parens add clutter and are not needed
      -(-> x (fizz) (:foo) (first) (frob))
      -
      -;; good, parens are necessary with an arg
      -(-> x
      -    (fizz a b)
      -    :foo
      -    first
      -    (frob x y))
      -
      -
      -
      -
      -

      Threading Macros Alignment

      -
      -

      The arguments to the threading macros -> (thread-first) and ->> -(thread-last) should line up.

      -
      -
      -
      -
      ;; good
      -(->> (range)
      -     (filter even?)
      -     (take 5))
      -
      -;; bad
      -(->> (range)
      -  (filter even?)
      -  (take 5))
      -
      -
      -
      -
      -

      Default cond Branch

      -
      -

      Use :else as the catch-all test expression in cond.

      -
      -
      -
      -
      ;; good
      -(cond
      -  (neg? n) "negative"
      -  (pos? n) "positive"
      -  :else "zero")
      -
      -;; bad
      -(cond
      -  (neg? n) "negative"
      -  (pos? n) "positive"
      -  true "zero")
      -
      -
      -
      -
      -

      condp vs cond

      -
      -

      Prefer condp instead of cond when the predicate & expression don’t -change.

      -
      -
      -
      -
      ;; good
      -(cond
      -  (= x 10) :ten
      -  (= x 20) :twenty
      -  (= x 30) :thirty
      -  :else :dunno)
      -
      -;; much better
      -(condp = x
      -  10 :ten
      -  20 :twenty
      -  30 :thirty
      -  :dunno)
      -
      -
      -
      -
      -

      case vs cond/condp

      -
      -

      Prefer case instead of cond or condp when test expressions are -compile-time constants.

      -
      -
      -
      -
      ;; good
      -(cond
      -  (= x 10) :ten
      -  (= x 20) :twenty
      -  (= x 30) :forty
      -  :else :dunno)
      -
      -;; better
      -(condp = x
      -  10 :ten
      -  20 :twenty
      -  30 :forty
      -  :dunno)
      -
      -;; best
      -(case x
      -  10 :ten
      -  20 :twenty
      -  30 :forty
      -  :dunno)
      -
      -
      -
      -
      -

      Short Forms In Cond

      -
      -

      Use short forms in cond and related. If not possible give visual -hints for the pairwise grouping with comments or empty lines.

      -
      -
      -
      -
      ;; good
      -(cond
      -  (test1) (action1)
      -  (test2) (action2)
      -  :else   (default-action))
      -
      -;; ok-ish
      -(cond
      -  ;; test case 1
      -  (test1)
      -  (long-function-name-which-requires-a-new-line
      -    (complicated-sub-form
      -      (-> 'which-spans multiple-lines)))
      -
      -  ;; test case 2
      -  (test2)
      -  (another-very-long-function-name
      -    (yet-another-sub-form
      -      (-> 'which-spans multiple-lines)))
      -
      -  :else
      -  (the-fall-through-default-case
      -    (which-also-spans 'multiple
      -                      'lines)))
      -
      -
      -
      -
      -

      Set As Predicate

      +

      complement

      -

      Use a set as a predicate when appropriate.

      +

      Favor the use of complement versus the use of an anonymous function.

      ;; good
      -(remove #{1} [0 1 2 3 4 5])
      -
      -;; bad
      -(remove #(= % 1) [0 1 2 3 4 5])
      -
      -;; good
      -(count (filter #{\a \e \i \o \u} "mary had a little lamb"))
      +(filter (complement some-pred?) coll)
       
       ;; bad
      -(count (filter #(or (= % \a)
      -                    (= % \e)
      -                    (= % \i)
      -                    (= % \o)
      -                    (= % \u))
      -               "mary had a little lamb"))
      -
      +(filter #(not (some-pred? %)) coll)
      -
      -

      inc and dec

      -

      Use (inc x) & (dec x) instead of (+ x 1) and (- x 1).

      +

      This rule should obviously be ignored if the complementing predicate +exists in the form of a separate function (e.g. even? and odd?).

      -

      pos? and neg?

      +

      comp

      -

      Use (pos? x), (neg? x) & (zero? x) instead of (> x 0), -(< x 0) & (= x 0).

      +

      Favor comp over anonymous functions for function composition.

      +
      +
      +
      +
      ;; Assuming `(:require [clojure.string :as str])`...
      +
      +;; good
      +(map #(str/capitalize (str/trim %)) ["top " " test "])
      +
      +;; better
      +(map (comp str/capitalize str/trim) ["top " " test "])
      +
      -

      list* vs cons

      +

      partial

      -

      Use list* instead of a series of nested cons invocations.

      +

      Favor partial over anonymous functions for currying.

      ;; good
      -(list* 1 2 3 [4 5])
      +(map #(+ 5 %) (range 1 10))
       
      -;; bad
      -(cons 1 (cons 2 (cons 3 [4 5])))
      +;; (arguably) better +(map (partial + 5) (range 1 10))
      -

      Sugared Java Interop

      +

      Threading Macros

      -

      Use the sugared Java interop forms.

      +

      Prefer the use of the threading macros -> (thread-first) and ->> +(thread-last) to heavy form nesting.

      -
      ;;; object creation
      -;; good
      -(java.util.ArrayList. 100)
      -
      -;; bad
      -(new java.util.ArrayList 100)
      -
      -;;; static method invocation
      -;; good
      -(Math/pow 2 10)
      -
      -;; bad
      -(. Math pow 2 10)
      -
      -;;; instance method invocation
      -;; good
      -(.substring "hello" 1 3)
      -
      -;; bad
      -(. "hello" substring 1 3)
      -
      -;;; static field access
      -;; good
      -Integer/MAX_VALUE
      +
      ;; good
      +(-> [1 2 3]
      +    reverse
      +    (conj 4)
      +    prn)
       
      -;; bad
      -(. Integer MAX_VALUE)
      +;; not as good
      +(prn (conj (reverse [1 2 3])
      +           4))
       
      -;;; instance field access
       ;; good
      -(.someField some-object)
      +(->> (range 1 10)
      +     (filter even?)
      +     (map (partial * 2)))
       
      -;; bad
      -(. some-object someField)
      +
      ;; not as good +(map (partial * 2) + (filter even? (range 1 10)))
      -

      Compact Metadata Notation For True Flags

      +

      Threading Macros and Optional Parentheses

      -

      Use the compact metadata notation for metadata that contains only -slots whose keys are keywords and whose value is boolean true.

      +

      Parentheses are not required when using the threading macros for functions having no argument specified, so use them only when necessary.

      ;; good
      -(def ^:private a 5)
      +(-> x fizz :foo first frob)
       
      -;; bad
      -(def ^{:private true} a 5)
      +;; bad; parens add clutter and are not needed +(-> x (fizz) (:foo) (first) (frob)) + +;; good, parens are necessary with an arg +(-> x + (fizz a b) + :foo + first + (frob x y))
      -

      Private

      +

      Threading Macros Alignment

      -

      Denote private parts of your code.

      +

      The arguments to the threading macros -> (thread-first) and ->> +(thread-last) should line up.

      ;; good
      -(defn- private-fun [] ...)
      -
      -(def ^:private private-var ...)
      +(->> (range)
      +     (filter even?)
      +     (take 5))
       
       ;; bad
      -(defn private-fun [] ...) ; not private at all
      -
      -(defn ^:private private-fun [] ...) ; overly verbose
      -
      -(def private-var ...) ; not private at all
      -
      -
      +(->> (range) + (filter even?) + (take 5))
      -
      -

      Access Private Var

      -
      -

      To access a private var (e.g. for testing), use the @#'some.ns/var form.

      -

      Attach Metadata Carefully

      +

      Default cond Branch

      -

      Be careful regarding what exactly you attach metadata to.

      +

      Use :else as the catch-all test expression in cond.

      -
      ;; we attach the metadata to the var referenced by `a`
      -(def ^:private a {})
      -(meta a) ;=> nil
      -(meta #'a) ;=> {:private true}
      +
      ;; good
      +(cond
      +  (neg? n) "negative"
      +  (pos? n) "positive"
      +  :else "zero")
       
      -;; we attach the metadata to the empty hash-map value
      -(def a ^:private {})
      -(meta a) ;=> {:private true}
      -(meta #'a) ;=> nil
      -
      -
      -
      -
      -
      -
      -

      Naming

      -
      -
      -
      -
      -

      The only real difficulties in programming are cache invalidation and -naming things.

      +;; bad +(cond + (neg? n) "negative" + (pos? n) "positive" + true "zero")
      -
      -
      -— Phil Karlton
      -

      Namespace Naming Schemas

      +

      condp vs cond

      -

      When naming namespaces favor the following two schemas:

      -
      -
      -
        -
      • -

        project.module

        -
      • -
      • -

        organization.project.module

        -
      • -
      +

      Prefer condp instead of cond when the predicate & expression don’t +change.

      +
      +
      +
      ;; good
      +(cond
      +  (= x 10) :ten
      +  (= x 20) :twenty
      +  (= x 30) :thirty
      +  :else :dunno)
      +
      +;; much better
      +(condp = x
      +  10 :ten
      +  20 :twenty
      +  30 :thirty
      +  :dunno)
      -
      -

      Composite Word Namespace Segments

      -
      -

      Use lisp-case in composite namespace segments (e.g. bruce.project-euler).

      -

      Functions and Variables

      +

      case vs cond/condp

      -

      Use lisp-case for function and variable names.

      -
      -
      - - - - - -
      -
      Note
      -
      -Many non-Lisp programming communities refer to lisp-case as -kebab-case, but we all know that Lisp has existed way before kebab -was invented. -
      +

      Prefer case instead of cond or condp when test expressions are +compile-time constants.

      ;; good
      -(def some-var ...)
      -(defn some-fun ...)
      +(cond
      +  (= x 10) :ten
      +  (= x 20) :twenty
      +  (= x 30) :forty
      +  :else :dunno)
       
      -;; bad
      -(def someVar ...)
      -(defn somefun ...)
      -(def some_fun ...)
      +;; better +(condp = x + 10 :ten + 20 :twenty + 30 :forty + :dunno) + +;; best +(case x + 10 :ten + 20 :twenty + 30 :forty + :dunno)
      -

      Protocols, Records, Structs And Types

      +

      Short Forms In Cond

      -

      Use CapitalCase for protocols, records, structs, and types. (Keep -acronyms like HTTP, RFC, XML uppercase.)

      +

      Use short forms in cond and related. If not possible give visual +hints for the pairwise grouping with comments or empty lines.

      +
      +
      +
      +
      ;; good
      +(cond
      +  (test1) (action1)
      +  (test2) (action2)
      +  :else   (default-action))
      +
      +;; ok-ish
      +(cond
      +  ;; test case 1
      +  (test1)
      +  (long-function-name-which-requires-a-new-line
      +    (complicated-sub-form
      +      (-> 'which-spans multiple-lines)))
      +
      +  ;; test case 2
      +  (test2)
      +  (another-very-long-function-name
      +    (yet-another-sub-form
      +      (-> 'which-spans multiple-lines)))
      +
      +  :else
      +  (the-fall-through-default-case
      +    (which-also-spans 'multiple
      +                      'lines)))
      -
      - - - - - -
      -
      Note
      -
      -CapitalCase is also known as UpperCamelCase, `CapitalWords -and PascalCase. -
      -

      Predicate Methods

      +

      Set As Predicate

      -

      The names of predicate methods (methods that return a boolean value) -should end in a question mark -(e.g., even?).

      +

      Use a set as a predicate when appropriate.

      ;; good
      -(defn palindrome? ...)
      +(remove #{1} [0 1 2 3 4 5])
       
       ;; bad
      -(defn palindrome-p ...) ; Common Lisp style
      -(defn is-palindrome ...) ; Java style
      +(remove #(= % 1) [0 1 2 3 4 5]) + +;; good +(count (filter #{\a \e \i \o \u} "mary had a little lamb")) + +;; bad +(count (filter #(or (= % \a) + (= % \e) + (= % \i) + (= % \o) + (= % \u)) + "mary had a little lamb"))
      -

      Unsafe Functions

      +

      inc and dec

      -

      The names of functions/macros that are not safe in STM transactions -should end with an exclamation mark (e.g. reset!).

      +

      Use (inc x) & (dec x) instead of (+ x 1) and (- x 1).

      -

      Conversion Functions

      +

      pos? and neg?

      -

      Use -> instead of to in the names of conversion functions.

      +

      Use (pos? x), (neg? x) & (zero? x) instead of (> x 0), +(< x 0) & (= x 0).

      +
      +
      +
      +

      list* vs cons

      +
      +

      Use list* instead of a series of nested cons invocations.

      ;; good
      -(defn f->c ...)
      +(list* 1 2 3 [4 5])
       
      -;; not so good
      -(defn f-to-c ...)
      +;; bad +(cons 1 (cons 2 (cons 3 [4 5])))
      -

      Dynamic Vars

      +

      Sugared Java Interop

      -

      Use earmuffs for things intended for rebinding (ie. are dynamic).

      +

      Use the sugared Java interop forms.

      -
      ;; good
      -(def ^:dynamic *a* 10)
      +
      ;;; object creation
      +;; good
      +(java.util.ArrayList. 100)
       
       ;; bad
      -(def ^:dynamic a 10)
      -
      -
      +(new java.util.ArrayList 100) + +;;; static method invocation +;; good +(Math/pow 2 10) + +;; bad +(. Math pow 2 10) + +;;; instance method invocation +;; good +(.substring "hello" 1 3) + +;; bad +(. "hello" substring 1 3) + +;;; static field access +;; good +Integer/MAX_VALUE + +;; bad +(. Integer MAX_VALUE) + +;;; instance field access +;; good +(.someField some-object) + +;; bad +(. some-object someField)
      -
      -

      Constants

      -
      -

      Don’t use a special notation for constants; everything is assumed a constant -unless specified otherwise.

      -

      Unused Bindings

      +

      Compact Metadata Notation For True Flags

      -

      Use _ for destructuring targets and formal argument names whose -value will be ignored by the code at hand.

      +

      Use the compact metadata notation for metadata that contains only +slots whose keys are keywords and whose value is boolean true.

      ;; good
      -(let [[a b _ c] [1 2 3 4]]
      -  (println a b c))
      -
      -(dotimes [_ 3]
      -  (println "Hello!"))
      +(def ^:private a 5)
       
       ;; bad
      -(let [[a b c d] [1 2 3 4]]
      -  (println a b d))
      -
      -(dotimes [i 3]
      -  (println "Hello!"))
      +(def ^{:private true} a 5) +
      +
      +

      Private

      -

      However, when it can help the understanding of your code, it can be useful to explicitly name unused arguments or maps you’re destructuring from. In this case, prepend the name with an underscore to explicitly signal that the variable is supposed to be unused.

      +

      Denote private parts of your code.

      ;; good
      -(defn myfun1 [context _]
      - (assoc context :foo "bar"))
      +(defn- private-fun [] ...)
       
      -(defn myfun2 [context {:keys [id]}]
      - (assoc context :user-id id))
      +(def ^:private private-var ...)
       
      -;; better
      -(defn myfun1 [context _user]
      - (assoc context :foo "bar"))
      +;; bad
      +(defn private-fun [] ...) ; not private at all
       
      -(defn myfun2 [context {:keys [id] :as _user}]
      - (assoc context :user-id id))
      +(defn ^:private private-fun [] ...) ; overly verbose + +(def private-var ...) ; not private at all
      -

      Idiomatic Names

      +

      Access Private Var

      -

      Follow clojure.core's example for idiomatic names like pred and coll.

      +

      To access a private var (e.g. for testing), use the @#'some.ns/var form.

      -
      -
        -
      • -

        in functions:

        -
        -
          -
        • -

          f, g, h - function input

          -
        • -
        • -

          n - integer input usually a size

          -
        • -
        • -

          index, i - integer index

          -
        • -
        • -

          x, y - numbers

          -
        • -
        • -

          xs - sequence

          -
        • -
        • -

          m - map

          -
        • -
        • -

          s - string input

          -
        • -
        • -

          re - regular expression

          -
        • -
        • -

          coll - a collection

          -
        • -
        • -

          pred - a predicate closure

          -
        • -
        • -

          & more - variadic input

          -
        • -
        • -

          xf - xform, a transducer

          -
        • -
        -
      • -
      • -

        in macros:

        -
        -
          -
        • -

          expr - an expression

          -
        • -
        • -

          body - a macro body

          -
        • -
        • -

          binding - a macro binding vector

          -
        • -
        +
        +

        Attach Metadata Carefully

        +
        +

        Be careful regarding what exactly you attach metadata to.

        +
        +
        +
        +
        ;; we attach the metadata to the var referenced by `a`
        +(def ^:private a {})
        +(meta a) ;=> nil
        +(meta #'a) ;=> {:private true}
        +
        +;; we attach the metadata to the empty hash-map value
        +(def a ^:private {})
        +(meta a) ;=> {:private true}
        +(meta #'a) ;=> nil
        -
      • -
      @@ -4670,7 +4670,7 @@

      From e06a9f9b5342a52b88d45a12e8648051d1958757 Mon Sep 17 00:00:00 2001 From: ci-build Date: Sat, 5 Dec 2020 21:34:43 +0000 Subject: [PATCH 076/122] [skip ci] Update site --- index.html | 62 +++++++++++++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/index.html b/index.html index 609ed28..c30afaa 100644 --- a/index.html +++ b/index.html @@ -855,13 +855,6 @@

      The Clojure Style Guide

    • Docstring After Fn Name
  • -
  • Existential - -
  • Testing
  • +
  • Existential + +
  • Tools
  • @@ -3634,7 +3637,7 @@

    Indentation Metadata

    Unlike other Lisp dialects, Clojure doesn’t have a standard metadata format to specify the indentation of macros. -CIDER proposed a tool-agnostic indentation specification based on metadata in 2015.[7] Here’s a simple example:

    +CIDER proposed a tool-agnostic indentation specification based on metadata in 2015.[8] Here’s a simple example:

    @@ -4665,12 +4668,15 @@

    6. These guidelines are based on a blog post by Stuart Sierra.

    -7. This was first introduced in CIDER 0.10 +7. Technically this will shadow the ns macro, but it’s extremely unlikely you’ll ever need it in the body of a function. +
    +
    +8. This was first introduced in CIDER 0.10
    From c66dee689ac74b098d219c780d1cef6ea65c4a5a Mon Sep 17 00:00:00 2001 From: ci-build Date: Sat, 5 Dec 2020 21:43:52 +0000 Subject: [PATCH 078/122] [skip ci] Update site --- index.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index 604be17..67fcee9 100644 --- a/index.html +++ b/index.html @@ -2094,6 +2094,9 @@

    re - regular expression

  • +

    sym - symbol

    +
  • +
  • coll - a collection

  • @@ -4676,7 +4679,7 @@

    From 2a72ecaf32e37b0e8e06f3a60ea47d14ffc58956 Mon Sep 17 00:00:00 2001 From: ci-build Date: Sat, 5 Dec 2020 22:02:26 +0000 Subject: [PATCH 079/122] [skip ci] Update site --- index.html | 48 +++++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/index.html b/index.html index 67fcee9..d6727c9 100644 --- a/index.html +++ b/index.html @@ -943,20 +943,15 @@

    Note -The guide is still a work in progress; some sections are missing, -others are incomplete, some rules are lacking examples, some rules -don’t have examples that illustrate them clearly enough. In due time -these issues will be addressed — just keep them in mind for now. -Help us address those shortcomings and make this guide better together! +Clojure’s developers also maintain a list of +coding +guidelines for libraries.[2] +They were one of the sources of inspiration for the document, you’re +currently reading. -
    -

    Please note, that the Clojure developing community maintains a list of -coding standards for libraries, -too.

    -

    Guiding Principles

    There are some areas in which there is no clear consensus in the Clojure community regarding a particular style (like semantic indentation vs fixed indentation, semantic comments vs uniform comments, etc). @@ -990,7 +985,7 @@

    Community Ruby Style Guide.[3]

    +Community Ruby Style Guide.[4]

    Clojure is famously optimized for simplicity and clarity. I’d like to believe that this guide is going to help you optimize for maximum @@ -1010,7 +1005,7 @@

    -

    A style guide is about consistency.[4] +

    A style guide is about consistency.[5] Consistency with this style guide is important. Consistency within a project is more important. Consistency within one class or method is the most important.

    @@ -1271,7 +1266,7 @@

    Line Endings

    -

    Use Unix-style line endings.[5]

    +

    Use Unix-style line endings.[6]

    @@ -1797,7 +1792,7 @@

    But what to do about all the other namespaces out there that don’t have idiomatic aliases? Well, you better be consistent in your approach to deriving aliases for them, -otherwise the people working on a shared Clojure codebase are going to experience a great deal of confusion. Here are a few rules that you should follow.[6]

    +otherwise the people working on a shared Clojure codebase are going to experience a great deal of confusion. Here are a few rules that you should follow.[7]

      @@ -2109,7 +2104,7 @@

      xf - xform, a transducer

    1. -

      ns - namespace[7]

      +

      ns - namespace[8]

    @@ -3640,7 +3635,7 @@

    Indentation Metadata

    Unlike other Lisp dialects, Clojure doesn’t have a standard metadata format to specify the indentation of macros. -CIDER proposed a tool-agnostic indentation specification based on metadata in 2015.[8] Here’s a simple example:

    +CIDER proposed a tool-agnostic indentation specification based on metadata in 2015.[9] Here’s a simple example:

    @@ -4656,30 +4651,33 @@

    1. CIDER, nREPL, Orchard, etc.

    -2. Occasionally I might suggest to the reader to consider some alternatives, though. +2. Those guidelines are meant to be applied to Clojure itself and to all the Clojure Contrib libraries.
    -3. You’ll notice that the Clojure style guide is pretty similar in structure to the Ruby style guide, which served as its main source of inspiration. You’ll also notice that the Ruby style guide is much longer, mostly because of the complexity of the Ruby language. +3. Occasionally I might suggest to the reader to consider some alternatives, though.
    -4. This section is heavily inspired by Python’s PEP-8 +4. You’ll notice that the Clojure style guide is pretty similar in structure to the Ruby style guide, which served as its main source of inspiration. You’ll also notice that the Ruby style guide is much longer, mostly because of the complexity of the Ruby language.
    -5. *BSD/Solaris/Linux/macOS users are covered by default, Windows users have to be extra careful. +5. This section is heavily inspired by Python’s PEP-8
    -6. These guidelines are based on a blog post by Stuart Sierra. +6. *BSD/Solaris/Linux/macOS users are covered by default, Windows users have to be extra careful.
    -7. Technically this will shadow the ns macro, but it’s extremely unlikely you’ll ever need it in the body of a function. +7. These guidelines are based on a blog post by Stuart Sierra.
    -8. This was first introduced in CIDER 0.10 +8. Technically this will shadow the ns macro, but it’s extremely unlikely you’ll ever need it in the body of a function. +
    +
    +9. This was first introduced in CIDER 0.10
    From b7182b7c1f3863eb7c0c626244f3bebfa1574620 Mon Sep 17 00:00:00 2001 From: ci-build Date: Sat, 5 Dec 2020 22:40:28 +0000 Subject: [PATCH 080/122] [skip ci] Update site --- index.html | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/index.html b/index.html index d6727c9..b852822 100644 --- a/index.html +++ b/index.html @@ -828,7 +828,7 @@

    The Clojure Style Guide

  • Comments
  • Testing @@ -3704,9 +3704,10 @@

    -

    Self-Documenting Code

    +

    Self-Explanatory Code

    -

    Endeavor to make your code as self-documenting as possible.

    +

    Endeavor to make your code as self-explanatory as possible. +If you fail to achieve this follow the rest of the guidelines in this section.

    +
    +

    The reasoning behind this guideline is pretty simple - the arguments are +easier to process by the human brain if they stand out and stick together.

    +
  • + + + + +
    +
    Note
    +
    +Generally, you should stick to the formatting outlined in the previous +guideline, unless you’re limited by the available horizonal space. +
    +

    Use a single space indentation for function (macro) arguments when there are no arguments on the same line as the function name.

    @@ -1222,6 +1239,113 @@

    portokala)

    +
    +

    This may appear like some weird special rule to people without Lisp background, but the +reasoning behind it is quite simple. Function calls are +nothing but regular list literals and normally those are aligned in the same way as +other collection type literals when spanning multiple lines:

    +
    +
    +
    +
    ;; list literal
    +(1
    + 2
    + 3)
    +
    +;; vector literal
    +[1
    + 2
    + 3]
    +
    +;; set literal
    +#{1
    +  2
    +  3}
    +
    +
    +
    +

    Admittedly, list literals are not very common in Clojure, that’s why it’s understandable +that for many people lists are nothing but an invocation syntax.

    +
    +
    +

    As a side benefit, function arguments are still aligned in this scenario as well. They +just happen to accidentally be aligned with the function name as well.

    +
    +
    +
    +
    Semantic Indentation vs Fixed Indentation
    +
    +

    The guidelines to indent differently macros with body forms from +all other macro and function calls are collectively known as +"semantic indentation". Simply put, this means that the code +is indented differently, so that the indentation would give the +reader of the code some hints about its meaning.

    +
    +
    +

    The downside of this approach is that requires Clojure code formatters to be +smarter. They either need to process macro arglists and rely on the fact +that people named their parameters consistently, or process some additional +indentation metadata.

    +
    +
    +

    Some people in the Clojure community have argued that’s not worth it and +that everything should simply be indented in the same fashion. Here are +a few examples:

    +
    +
    +
    +
    ;;; Fixed Indentation
    +;;
    +;; macros
    +(when something
    +  (something-else))
    +
    +(with-out-str
    +  (println "Hello, ")
    +  (println "world!"))
    +
    +;; function call spanning two lines
    +(filter even?
    +  (range 1 10))
    +
    +;; function call spanning three lines
    +(filter
    +  even?
    +  (range 1 10))
    +
    +
    +
    +

    This suggestion has certainly gotten some ground in the community, but it also +goes against the entire Lisp tradition and the primary goal of this style guide - +namely to optimize code for human consumption.

    +
    +
    +

    There’s also one small caveat with fixed indentation that’s rarely discussed and that’s +how to indent list literals, as function calls are simply list literals. As those +are not very common in Clojure, outside the context of providing structure for the Clojure +code itself, that matter is usually omitted from consideration:

    +
    +
    +
    +
    ;;; Fixed Indentation
    +;;
    +;; list literals
    +(1 2 3
    +  4 5 6)
    +
    +(1
    +  2
    +  3
    +  4
    +  5
    +  6)
    +
    +
    +
    +

    That looks a bit weird and happens to be inconsistent with how other collection types are normally indented.

    +
    +
    +

  • +

    Google’s Common Lisp Style Guide

    +
  • +
  • +

    scheme-style

    +
  • +
  • Clojure Library Coding Guidelines

  • @@ -4802,7 +4808,7 @@

    From e08d0f76c6c5fdb51cf0a2ff8886e27f87a4edec Mon Sep 17 00:00:00 2001 From: ci-build Date: Mon, 7 Dec 2020 07:37:38 +0000 Subject: [PATCH 083/122] [skip ci] Update site --- index.html | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index 28b1114..4c80369 100644 --- a/index.html +++ b/index.html @@ -2012,6 +2012,12 @@

    +

    When you’re following the project.module naming scheme and your project +has a single (implementation) namespace it’s common to name it project.core. +Avoid the project.core name in all other cases, as more informative names +are always a better idea.

    +
    - -
    -

    Functions and Variables

    -
    -

    Use lisp-case for function and variable names.

    -
    @@ -2044,6 +2038,12 @@

    +

    Functions and Variables

    +
    +

    Use lisp-case for function and variable names.

    +

    + + + + +
    +
    Note
    +
    +Famously clojure-version defies this convention, but you should +treat this naming choice is a historical oddity and not as an example to +follow. +
    +

    Unused Bindings

    @@ -4814,7 +4839,7 @@

    From 670e02c8ae33a7c4482b865270594d759da43808 Mon Sep 17 00:00:00 2001 From: ci-build Date: Sat, 12 Dec 2020 16:52:07 +0000 Subject: [PATCH 085/122] [skip ci] Update site --- index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index e20827d..a1ce983 100644 --- a/index.html +++ b/index.html @@ -2848,7 +2848,7 @@

    partial

    -

    Favor partial over anonymous functions for currying.

    +

    Favor partial over anonymous functions.

    +
    +

    Namespaces exist to disambiguate names. Using a single segment +namespace puts you in direct conflict with everyone else using single +segment namespaces, thus making it more likely you will conflict with +another code base.

    +
    +
    +

    In practice this means that libraries should never use single-segment +namespace to avoid namespace conflicts with other libraries. +Within your own private app of course, you can do whatever you like.

    +
    +
    + + + + + +
    +
    Tip
    +
    +It’s common practice to use the convention domain.library-name +or library-name.core for libraries with a single namespace in them. +Read on for more coverage of the namespace naming topic. +
    +
    +
    +

    There are other reasons +why might want to avoid single-segment namespaces, so you should +think long and hard before making any use of them.

    +

    +

    Converting Something to Boolean

    +
    +

    Use the boolean function if you need to convert something to an actual boolean value (true or false).

    +
    +
    +
    +
    ;; good
    +(boolean (foo bar))
    +
    +;; bad
    +(if (foo bar) true false)
    +
    +
    +
    + + + + + +
    +
    Note
    +
    +Don’t forget that the only values in Clojure that are "falsey" are false and nil. Everything else +will evaluate to true when passed to the boolean function. +
    +
    +
    +

    You’ll rarely need an actual boolean value in Clojure, but it’s useful to know how to obtain one when you do.

    +
    +
    +

    when vs if

    Use when instead of (if …​ (do …​)).

    @@ -4869,7 +4901,7 @@

    From ccadb761ae2b1adf2571e0f436792b2afc2c2365 Mon Sep 17 00:00:00 2001 From: ci-build Date: Sat, 12 Dec 2020 22:21:18 +0000 Subject: [PATCH 088/122] [skip ci] Update site --- index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index 00b3a5c..2c16cfd 100644 --- a/index.html +++ b/index.html @@ -2779,7 +2779,7 @@

    printf

    -

    Use printf instead of (print (format …​)).

    +

    Prefer printf over (print (format …​)).

    @@ -4901,7 +4901,7 @@

    From 8abc3e9dc0a2a3f2fabf24b4d7f29bced82d2f4c Mon Sep 17 00:00:00 2001 From: ci-build Date: Sat, 12 Dec 2020 22:22:20 +0000 Subject: [PATCH 089/122] [skip ci] Update site --- index.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/index.html b/index.html index 2c16cfd..bbdc1ae 100644 --- a/index.html +++ b/index.html @@ -743,7 +743,7 @@

    The Clojure Style Guide

  • when-not vs if-not
  • not=
  • printf
  • -
  • Flexible Comparison Functions
  • +
  • Flexible Comparison Functions
  • Single Parameter Function Literal
  • Multiple Parameters Function Literal
  • No Useless Anonymous Functions
  • @@ -2792,9 +2792,9 @@

    -

    Flexible Comparison Functions

    +

    Flexible Comparison Functions

    -

    When doing comparisons, keep in mind that Clojure’s functions <, +

    When doing comparisons, leverage the fact that Clojure’s functions <, >, etc. accept a variable number of arguments.

    @@ -4901,7 +4901,7 @@

    From 5aef9a6e68ff32bdf732ec31d6fce6f64ec9da4a Mon Sep 17 00:00:00 2001 From: ci-build Date: Wed, 16 Dec 2020 21:45:28 +0000 Subject: [PATCH 091/122] [skip ci] Update site --- index.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/index.html b/index.html index a00bab1..e35dc85 100644 --- a/index.html +++ b/index.html @@ -3761,11 +3761,11 @@

    ;; ;; using the docstring to signal deprecation (def foo - "DEPRECATED: Use `bar` instead. - 42) + "DEPRECATED: Use `bar` instead." + 42) -(ns foo.bar - "DEPRECATED: A deprecated ns.") +(ns foo.bar + "DEPRECATED: A deprecated ns.")

    @@ -4901,7 +4901,7 @@

    From 90106f1cfe9336b6cfdb6dbab2d0c25fec05f87b Mon Sep 17 00:00:00 2001 From: ci-build Date: Mon, 21 Dec 2020 07:23:56 +0000 Subject: [PATCH 092/122] [skip ci] Update site --- index.html | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index e35dc85..c405726 100644 --- a/index.html +++ b/index.html @@ -885,6 +885,7 @@

    The Clojure Style Guide

  • History
  • Sources of Inspiration
  • +
  • Editor Team
  • Contributing
  • @@ -3850,6 +3851,46 @@

    +

    :no-doc

    +
    +

    Documentation tools like Codox like cljdoc recognize :no-doc metadata. +When a var or a namespace has :no-doc metadata, it indicates to these tools that it should be excluded from generated API docs.

    +
    +
    +

    To exclude an entire namespace from API docs:

    +
    +
    +
    +
    (ns ^:no-doc my-library.impl
    +  "Internal implementation details")
    +
    +...
    +
    +
    +
    +

    To exclude vars within a documented namespace:

    +
    +
    +
    +
    (ns my-library.api)
    +
    +;; private functions do not get documented
    +(defn- clearly-private []
    +  ...)
    +
    +;; nor do public functions with :no-doc metadata
    +(defn ^:no-doc shared-helper []
    +  ...)
    +
    +;; this function will be documented
    +(defn api-fn1
    +  "I am useful to the public"
    +  []
    +  ...)
    +
    +
    + + @@ -4968,7 +4968,7 @@

    From 79b8ee9b20b3bf8abaf08790c09c1435875e1056 Mon Sep 17 00:00:00 2001 From: ci-build Date: Thu, 18 Mar 2021 15:54:57 +0000 Subject: [PATCH 097/122] [skip ci] Update site --- index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index 8f1855d..9d32fde 100644 --- a/index.html +++ b/index.html @@ -1210,7 +1210,7 @@

    Generally, you should stick to the formatting outlined in the previous -guideline, unless you’re limited by the available horizonal space. +guideline, unless you’re limited by the available horizontal space. @@ -4968,7 +4968,7 @@

    From fb2d208dd195a64864c50a14c83ecdbed1650532 Mon Sep 17 00:00:00 2001 From: ci-build Date: Fri, 19 Mar 2021 20:40:17 +0000 Subject: [PATCH 098/122] [skip ci] Update site --- index.html | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index 9d32fde..3d0bbd2 100644 --- a/index.html +++ b/index.html @@ -2313,6 +2313,16 @@

    +
  • +

    in methods (when specified in defprotocol, deftype, defrecord, reify, etc):

    +
    +
      +
    • +

      this - for the first argument, indicating a reference to the object - or alternatively, a consistent name which describes the object

      +
    • +
    +
    +
  • @@ -4544,6 +4554,30 @@

    (bar x)) +
    + + + + + +
    +
    Note
    +
    +
    +

    Place docstrings for defprotocol methods after the argument vector:

    +
    +
    +
    +
    (defprotocol MyProtocol
    +  "MyProtocol docstring"
    +  (foo [this x y z]
    +    "foo docstring")
    +  (bar [this]
    +    "bar docstring"))
    +
    +
    +
    +
    @@ -4968,7 +5002,7 @@

    From bc009b0cc070a4145650d2c12544594550fa15ac Mon Sep 17 00:00:00 2001 From: ci-build Date: Sat, 17 Apr 2021 18:05:10 +0000 Subject: [PATCH 099/122] [skip ci] Update site --- index.html | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/index.html b/index.html index 3d0bbd2..b41d830 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ - + Codestin Search App