Clojure 代碼規(guī)范

Clojure 代碼規(guī)范 | Ji ZHANG's Blog
http://shzhangji.com/blog/2013/01/04/clojure-style-guide/

原文地址:https://github.com/bbatsov/clojure-style-guide
這份Clojure代碼規(guī)范旨在提供一系列的最佳實(shí)踐展懈,讓現(xiàn)實(shí)工作中的Clojure程序員能夠?qū)懗鲆子诰S護(hù)的代碼,并能與他人協(xié)作和共享优幸。一份反應(yīng)真實(shí)需求的代碼規(guī)范才能被人接收栈拖,而那些理想化的铐姚、甚至部分觀點(diǎn)遭到程序員拒絕的代碼規(guī)范注定不會(huì)長(zhǎng)久——無(wú)論它有多出色。
這份規(guī)范由多個(gè)章節(jié)組成,每個(gè)章節(jié)包含一組相關(guān)的規(guī)則察迟。我會(huì)嘗試去描述每條規(guī)則背后的理念(過(guò)于明顯的理念我就省略了)。
這些規(guī)則并不是我憑空想象的耳高,它們出自于我作為一個(gè)專(zhuān)業(yè)軟件開(kāi)發(fā)工程師長(zhǎng)久以來(lái)的工作積累卷拘,以及Clojure社區(qū)成員們的反饋和建議,還有各種廣為流傳的Clojure編程學(xué)習(xí)資源祝高,如《Clojure Programming》栗弟、《The Joy of Clojure》等。
這份規(guī)范還處于編寫(xiě)階段工闺,部分章節(jié)有所缺失乍赫,內(nèi)容并不完整;部分規(guī)則沒(méi)有示例陆蟆,或者示例還不能完全將其描述清楚雷厂。未來(lái)這些問(wèn)題都會(huì)得到改進(jìn),只是請(qǐng)你了解這一情況叠殷。
你可以使用Transmuter生成一份本規(guī)范的PDF或HTML格式的文檔改鲫。
目錄
源代碼的布局和組織結(jié)構(gòu)
語(yǔ)法
命名
注釋注釋中的標(biāo)識(shí)

異常
集合
可變量
字符串
正則表達(dá)式

慣用法

源代碼的布局和組織結(jié)構(gòu)
幾乎所有人都認(rèn)為任何代碼風(fēng)格都是丑陋且難以閱讀的,除了自己的之外林束。把這句話(huà)中的“除了自己之外”去掉像棘,那差不多就能成立了『埃—— Jerry Coffin 關(guān)于代碼縮進(jìn)的評(píng)論

使用兩個(gè) 空格 進(jìn)行縮進(jìn)缕题,不使用制表符。

1
2
3
4
5
6
7

;; 正確
(when something
(something-else))

;; 錯(cuò)誤 - 四個(gè)空格
(when something
(something-else))

縱向?qū)R函數(shù)參數(shù)胖腾。

1
2
3
4
5
6
7

;; 正確
(filter even?
(range 1 10))

;; 錯(cuò)誤
(filter even?
(range 1 10))

對(duì)齊let綁定烟零,以及map類(lèi)型中的關(guān)鍵字。

1
2
3
4
5
6
7
8
9
10
11

;; 正確
(let [thing1 "some stuff"
thing2 "other stuff"]
{:thing1 thing1
:thing2 thing2})

;; 錯(cuò)誤
(let [thing1 "some stuff"
thing2 "other stuff"]
{:thing1 thing1
:thing2 thing2})

當(dāng)defn
沒(méi)有文檔字符串時(shí)咸作,可以選擇省略函數(shù)名和參數(shù)列表之間的空行锨阿。

1
2
3
4
5
6
7
8
9
10
11
12

;; 正確
(defn foo
[x]
(bar x))

;; 正確
(defn foo [x]
(bar x))

;; 錯(cuò)誤
(defn foo
[x] (bar x))

當(dāng)函數(shù)體較簡(jiǎn)短時(shí),可以選擇忽略參數(shù)列表和函數(shù)體之間的空行记罚。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

;; 正確
(defn foo [x]
(bar x))

;; 適合簡(jiǎn)單的函數(shù)
(defn goo [x] (bar x))

;; 適合包含多種參數(shù)列表的函數(shù)
(defn foo
([x] (bar x))
([x y]
(if (predicate? x)
(bar x)
(baz x))))

;; 錯(cuò)誤
(defn foo
[x] (if (predicate? x)
(bar x)
(baz x)))

跨行的文檔說(shuō)明字符串每行都要縮進(jìn)墅诡。

1
2
3
4
5
6
7
8
9
10
11
12
13

;; 正確
(defn foo
"Hello there. This is
a multi-line docstring."
[]
(bar))

;; 錯(cuò)誤
(defn foo
"Hello there. This is
a multi-line docstring."
[]
(bar))

使用Unix風(fēng)格的換行符(*BSD、Solaris毫胜、Linux书斜、OSX用戶(hù)無(wú)需設(shè)置诬辈,Windows用戶(hù)則需要格外注意了)如果你使用Git,為了防止項(xiàng)目中意外引入Windows風(fēng)格的換行符荐吉,不妨添加如下設(shè)置:

1

$ git config --global core.autocrlf true

在括號(hào)(
焙糟、{
、[
样屠、]
穿撮、}
、)
的外部添加空格痪欲,括號(hào)內(nèi)部不要添加悦穿。

1
2
3
4
5
6

;; 正確
(foo (bar baz) quux)

;; 錯(cuò)誤
(foo(bar baz)quux)
(foo ( bar baz ) quux)

避免在集合中使用逗號(hào)分隔符。

1
2
3
4
5
6
7

;; 正確
[1 2 3]
(1 2 3)

;; 錯(cuò)誤
[1, 2, 3]
(1, 2, 3)

可以考慮在map中適當(dāng)使用逗號(hào)和換行以增強(qiáng)可讀性业踢。

1
2
3
4
5
6
7
8
9

;; 正確
{:name "Bruce Wayne" :alter-ego "Batman"}

;; 正確栗柒,且會(huì)增強(qiáng)可讀性
{:name "Bruce Wayne"
:alter-ego "Batman"}

;; 正確,且較為緊湊
{:name "Bruce Wayne", :alter-ego "Batman"}

將所有的反括號(hào)放在一行中知举。

1
2
3
4
5
6
7
8

;; 正確
(when something
(something-else))

;; 錯(cuò)誤
(when something
(something-else)
)

頂層函數(shù)之間空出一行瞬沦。

1
2
3
4
5
6
7
8

;; 正確
(def x ...)

(defn foo ...)

;; 錯(cuò)誤
(def x ...)
(defn foo ...)

函數(shù)或宏的定義體中不要添加空行。
每行盡量不超過(guò)80個(gè)字符雇锡。
避免在行末輸入多余的空格逛钻。
為每個(gè)命名空間創(chuàng)建單獨(dú)的文件锰提。
使用一個(gè)完整的ns
指令來(lái)聲明命名空間,其包含import
立肘、require
、refer
惩嘉、以及use
踢故。

1
2
3
4
5
6
7
8
9
10

(ns examples.ns
(:refer-clojure :exclude [next replace remove])
(:require (clojure [string :as string]
[set :as set])
[clojure.java.shell :as sh])
(:use (clojure zip xml))
(:import java.util.Date
java.text.SimpleDateFormat
(java.util.concurrent Executors
LinkedBlockingQueue)))

避免使用只有一個(gè)元素的命名空間名惹苗。

1
2
3
4
5

;; 正確
(ns example.ns)

;; 錯(cuò)誤
(ns example)

避免使用過(guò)長(zhǎng)的命名空間(不超過(guò)五個(gè)元素)殿较。

一個(gè)函數(shù)不應(yīng)超過(guò)10行代碼。事實(shí)上桩蓉,大多數(shù)函數(shù)應(yīng)保持在5行代碼以?xún)?nèi)淋纲。

函數(shù)的參數(shù)個(gè)數(shù)不應(yīng)超過(guò)三到四個(gè)。

語(yǔ)法
避免使用require
院究、refer
等改變命名空間的函數(shù)洽瞬,它們只應(yīng)在REPL中使用本涕。
使用declare
實(shí)現(xiàn)引用傳遞。
優(yōu)先使用map
這類(lèi)高階函數(shù)伙窃,而非loop/recur
菩颖。

優(yōu)先使用前置、后置條件來(lái)檢測(cè)函數(shù)參數(shù)和返回值:

1
2
3
4
5
6
7
8
9
10

;; 正確
(defn foo [x]
{:pre [(pos? x)]}
(bar x))

;; 錯(cuò)誤
(defn foo [x]
(if (pos? x)
(bar x)
(throw (IllegalArgumentException "x must be a positive number!")))

不要在函數(shù)中定義變量:

1
2
3
4

;; 非常糟糕
(defn foo []
(def x 5)
...)

本地變量名不應(yīng)覆蓋clojure.core
中定義的函數(shù):

1
2
3

;; 錯(cuò)誤——這樣一來(lái)函數(shù)中調(diào)用map時(shí)就需要指定完整的命名空間了为障。
(defn foo [map]
...)

使用seq
來(lái)判斷一個(gè)序列是否為空(空序列等價(jià)于nil)晦闰。

1
2
3
4
5
6
7
8
9
10
11

;; 正確
(defn print-seq [s]
(when (seq s)
(prn (first s))
(recur (rest s))))

;; 錯(cuò)誤
(defn print-seq [s]
(when-not (empty? s)
(prn (first s))
(recur (rest s))))

使用when
替代(if ... (do ...)

1
2
3
4
5
6
7
8
9
10

;; 正確
(when pred
(foo)
(bar))

;; 錯(cuò)誤
(if pred
(do
(foo)
(bar)))

使用if-let
替代let

  • if
    鳍怨。

1
2
3
4
5
6
7
8
9
10

;; 正確
(if-let [result :foo]
(something-with result)
(something-else))

;; 錯(cuò)誤
(let [result :foo]
(if result
(something-with result)
(something-else)))

使用when-let
替代let

  • when
    呻右。

1
2
3
4
5
6
7
8
9
10

;; 正確
(when-let [result :foo]
(do-something-with result)
(do-something-more-with result))

;; 錯(cuò)誤
(let [result :foo]
(when result
(do-something-with result)
(do-something-more-with result)))

使用if-not
替代(if (not ...) ...)

1
2
3
4
5
6
7

;; 正確
(if-not (pred)
(foo))

;; 錯(cuò)誤
(if (not pred)
(foo))

使用when-not
替代(when (not ...) ...)
鞋喇。

1
2
3
4
5
6
7
8
9

;; 正確
(when-not pred
(foo)
(bar))

;; 錯(cuò)誤
(when (not pred)
(foo)
(bar))

使用not=
替代(not (= ...))
声滥。

1
2
3
4
5

;; 正確
(not= foo bar)

;; 錯(cuò)誤
(not (= foo bar))

當(dāng)匿名函數(shù)只有一個(gè)參數(shù)時(shí),優(yōu)先使用%
侦香,而非%1
醒串。

1
2
3
4
5

;; 正確

(Math/round %)

;; 錯(cuò)誤

(Math/round %1)

當(dāng)匿名函數(shù)有多個(gè)參數(shù)時(shí),優(yōu)先使用%1
鄙皇,而非%
芜赌。

1
2
3
4
5

;; 正確

(Math/pow %1 %2)

;; 錯(cuò)誤

(Math/pow % %2)

只有在必要的時(shí)候才使用匿名函數(shù)缠沈。

1
2
3
4
5

;; 正確
(filter even? (range 1 10))

;; 錯(cuò)誤
(filter #(even? %) (range 1 10))

當(dāng)匿名函數(shù)包含多行語(yǔ)句時(shí)洲愤,使用fn
來(lái)定義柬赐,而非#(do ...)

1
2
3
4
5
6
7
8

;; 正確
(fn [x]
(println x)
(* x 2))

;; 錯(cuò)誤(你不得不使用do

(do (println %)

(* % 2))

在特定情況下優(yōu)先使用complement
酝陈,而非匿名函數(shù)沉帮。

1
2
3
4
5

;; 正確
(filter (complement some-pred?) coll)

;; 錯(cuò)誤
(filter #(not (some-pred? %)) coll)

當(dāng)函數(shù)已存在對(duì)應(yīng)的求反函數(shù)時(shí)待牵,則應(yīng)使用該求反函數(shù)(如even?
和odd?
)洲敢。
某些情況下可以用comp
使代碼更簡(jiǎn)潔压彭。

1
2
3
4
5

;; 正確
(map #(capitalize (trim %)) ["top " " test "])

;; 更好
(map (comp capitalize trim) ["top " " test "])

某些情況下可以用partial
使代碼更簡(jiǎn)潔。

1
2
3
4
5

;; 正確
(map #(+ 5 %) (range 1 10))

;; 或許更好
(map (partial + 5) (range 1 10))

當(dāng)遇到嵌套調(diào)用時(shí)询一,建議使用->
宏和->>
宏健蕊。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

;; 正確
(-> [1 2 3]
reverse
(conj 4)
prn)

;; 不夠好
(prn (conj (reverse [1 2 3])
4))

;; 正確
(->> (range 1 10)
(filter even?)
(map (partial * 2)))

;; 不夠好
(map (partial * 2)
(filter even? (range 1 10)))

當(dāng)需要連續(xù)調(diào)用Java類(lèi)的方法時(shí)缩功,優(yōu)先使用..
嫡锌,而非->

1
2
3
4
5

;; 正確
(-> (System/getProperties) (.get "os.name"))

;; 更好
(.. System getProperties (get "os.name"))

在cond
和condp
中歌懒,使用:else
來(lái)處理不滿(mǎn)足條件的情況及皂。

1
2
3
4
5
6
7
8
9
10
11

;; 正確
(cond
(< n 0) "negative"
(> n 0) "positive"
:else "zero"))

;; 錯(cuò)誤
(cond
(< n 0) "negative"
(> n 0) "positive"
true "zero"))

當(dāng)比較的變量和方式相同時(shí)查剖,優(yōu)先使用condp
,而非cond
倔监。

1
2
3
4
5
6
7
8
9
10
11
12
13

;; 正確
(cond
(= x 10) :ten
(= x 20) :twenty
(= x 30) :forty
:else :dunno)

;; 更好
(condp = x
10 :ten
20 :twenty
30 :forty
:dunno)

當(dāng)條件是常量時(shí)浩习,優(yōu)先使用case
谱秽,而非cond
或condp
郊供。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

;; 正確
(cond
(= x 10) :ten
(= x 20) :twenty
(= x 30) :forty
:else :dunno)

;; 更好
(condp = x
10 :ten
20 :twenty
30 :forty
:dunno)

;; 最佳
(case x
10 :ten
20 :twenty
30 :forty
:dunno)

某些情況下驮审,使用set
作為判斷條件疯淫。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

;; 錯(cuò)誤
(remove #(= % 0) [0 1 2 3 4 5])

;; 正確
(remove #{0} [0 1 2 3 4 5])

;; 錯(cuò)誤
(count (filter #(or (= % \a)
(= % \e)
(= % \i)
(= % \o)
(= % \u))
"mary had a little lamb"))

;; 正確
(count (filter #{\a \e \i \o \u} "mary had a little lamb"))

使用(inc x)
和(dec x)
替代(+ x 1)
和(- x 1)
熙掺。

使用(pos? x)
、(neg? x)
类浪、以及(zero? x)
替代(> x 0)
费就、(< x 0)
力细、和(= x 0)
眠蚂。

進(jìn)行Java操作時(shí)逝慧,優(yōu)先使用Clojure提供的語(yǔ)法糖云稚。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

;;; 創(chuàng)建對(duì)象
;; 正確
(java.util.ArrayList. 100)

;; 錯(cuò)誤
(new java.util.ArrayList 100)

;;; 調(diào)用靜態(tài)方法
;; 正確
(Math/pow 2 10)

;; 錯(cuò)誤
(. Math pow 2 10)

;;; 調(diào)用實(shí)例方法
;; 正確
(.substring "hello" 1 3)

;; 錯(cuò)誤
(. "hello" substring 1 3)

;;; 訪(fǎng)問(wèn)靜態(tài)屬性
;; 正確
Integer/MAX_VALUE

;; 錯(cuò)誤
(. Integer MAX_VALUE)

;;; 訪(fǎng)問(wèn)實(shí)例屬性
;; 正確
(.someField some-object)

;; 錯(cuò)誤
(. some-object some-field)

命名
編程中真正的難點(diǎn)只有兩個(gè):驗(yàn)證緩存的有效性;命名鲸拥⌒谈希—— Phil Karlton

命名空間建議使用以下兩種方式:項(xiàng)目名稱(chēng).模塊名稱(chēng)

組織名稱(chēng).項(xiàng)目名稱(chēng).模塊名稱(chēng)

對(duì)于命名空間中較長(zhǎng)的元素角撞,使用lisp-case
格式谒所,如bruce.project-euler
劣领。
使用lisp-case
格式來(lái)命名函數(shù)和變量尖淘。
使用CamelCase
來(lái)命名接口(protocol)、記錄(record)趁桃、結(jié)構(gòu)和類(lèi)型(struct & type)卫病。對(duì)于HTTP蟀苛、RFC帜平、XML等縮寫(xiě)评腺,仍保留其大寫(xiě)格式。
對(duì)于返回布爾值的函數(shù)名稱(chēng)蝶念,使用問(wèn)號(hào)結(jié)尾担敌,如even?

當(dāng)方法或宏不能在STM中安全使用時(shí)刹悴,須以感嘆號(hào)結(jié)尾土匀,如reset!
就轧。
命名類(lèi)型轉(zhuǎn)換函數(shù)時(shí)使用->
,而非to
镇饺。

1
2
3
4
5

;; 正確
(defn f->c ...)

;; 不夠好
(defn f-to-c ...)

對(duì)于可供重綁定的變量(即動(dòng)態(tài)變量)梦鉴,使用星號(hào)括起肥橙,如earmuffs
存筏。
無(wú)需對(duì)常量名進(jìn)行特殊的標(biāo)識(shí),因?yàn)樗械淖兞慷紤?yīng)該是常量予跌,除非有特別說(shuō)明。
對(duì)于解構(gòu)過(guò)程中或參數(shù)列表中忽略的元素烁焙,使用_
來(lái)表示。
參考clojure.core
中的命名規(guī)范操骡,如pred
岔激、coll
:函數(shù):f
跨细、g
鹦倚、h
:參數(shù)內(nèi)容是一個(gè)函數(shù)
n
:整數(shù),通常是一個(gè)表示大小的值
index
:整數(shù)索引
x
冀惭、y
:數(shù)值
s
:字符串
coll
:集合
pred
:斷言型的閉包
& more
:可變參數(shù)

宏:expr
:表達(dá)式
body
:語(yǔ)句
binding
:一個(gè)向量震叙,包含宏的綁定

集合
用100種函數(shù)去操作同一種數(shù)據(jù)結(jié)構(gòu),要好過(guò)用10種函數(shù)操作10種數(shù)據(jù)結(jié)構(gòu)散休∶铰ィ—— Alan J. Perlis

避免使用列表(list)來(lái)存儲(chǔ)數(shù)據(jù)(除非它真的就是你想要的)。
優(yōu)先使用關(guān)鍵字(keyword)划址,而非普通的哈希鍵:

1
2
3
4
5

;; 正確
{:name "Bruce" :age 30}

;; 錯(cuò)誤
{"name" "Bruce" "age" 30}

編寫(xiě)集合時(shí),優(yōu)先使用內(nèi)置的語(yǔ)法形式嵌洼,而非構(gòu)造函數(shù)鳖昌。但是,在定義唯一值集合(set)時(shí),只有當(dāng)元素都是常量時(shí)才可使用內(nèi)置語(yǔ)法悉患,否則應(yīng)使用構(gòu)造函數(shù)回窘,如下所示:

1
2
3
4
5
6
7
8
9

;; 正確
[1 2 3]

{1 2 3}

(hash-set (func1) (func2)) ; 元素在運(yùn)行時(shí)確定

;; bad
(vector 1 2 3)
(hash-set 1 2 3)

{(func1) (func2)} ; 若(func1)和(func2)的值相等,則會(huì)拋出運(yùn)行時(shí)異常。

避免使用數(shù)值索引來(lái)訪(fǎng)問(wèn)集合元素。

優(yōu)先使用關(guān)鍵字來(lái)獲取哈希表(map)中的值。

1
2
3
4
5
6
7
8
9
10

(def m {:name "Bruce" :age 30})

;; 正確
(:name m)

;; 錯(cuò)誤——太過(guò)啰嗦
(get m :name)

;; 錯(cuò)誤——可能拋出空指針異常
(m :name)

集合可以被用作函數(shù):

1
2
3
4

;; 正確
(filter #{\a \e \o \i \u} "this is a test")

;; 缺點(diǎn)——不夠美觀

關(guān)鍵字可以被用作函數(shù):

1

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

只有在非常強(qiáng)調(diào)性能的情況下才可使用瞬時(shí)集合(transient collection)秤涩。

避免使用Java集合匀谣。

避免使用Java數(shù)組,除非遇到需要和Java類(lèi)進(jìn)行交互,或需要高性能地處理基本類(lèi)型時(shí)才可使用毫痕。

可變量
引用(Refs)
建議所有的IO操作都使用io!
宏進(jìn)行包裝,以免不小心在事務(wù)中調(diào)用了這些代碼。
避免使用ref-set

控制事務(wù)的大小挪丢,即事務(wù)所執(zhí)行的工作越少越好。
避免出現(xiàn)短期事務(wù)和長(zhǎng)期事務(wù)訪(fǎng)問(wèn)同一個(gè)引用(Ref)的情形丹鸿。

代理(Agents)
send
僅使用于計(jì)算密集型、不會(huì)因IO等因素阻塞的線(xiàn)程。
send-off
則用于會(huì)阻塞、休眠的線(xiàn)程氯析。

原子(Atoms)
避免在事務(wù)中更新原子。
避免使用reset!

字符串
優(yōu)先使用clojure.string
中提供的字符串操作函數(shù),而不是Java中提供的或是自己編寫(xiě)的函數(shù)。

1
2
3
4
5

;; 正確
(clojure.string/upper-case "bruce")

;; 錯(cuò)誤
(.toUpperCase "bruce")

異常
復(fù)用已有的異常類(lèi)型拆座,如:java.lang.IllegalArgumentException

java.lang.UnsupportedOperationException

java.lang.IllegalStateException

java.io.IOException

優(yōu)先使用with-open
岖赋,而非finally
恳啥。


如果可以用函數(shù)實(shí)現(xiàn)相同功能沿猜,不要編寫(xiě)一個(gè)宏矢劲。
首先編寫(xiě)一個(gè)宏的用例,爾后再編寫(xiě)宏本身棵红。
盡可能將一個(gè)復(fù)雜的宏拆解為多個(gè)小型的函數(shù)凶赁。
宏只應(yīng)用于簡(jiǎn)化語(yǔ)法,其核心應(yīng)該是一個(gè)普通的函數(shù)。
使用語(yǔ)法轉(zhuǎn)義(syntax-quote虱肄,即反引號(hào))致板,而非手動(dòng)構(gòu)造list

注釋
好的代碼本身就是文檔咏窿。因此在添加注釋之前斟或,先想想自己該如何改進(jìn)代碼,讓它更容易理解集嵌。做到這一點(diǎn)后萝挤,再通過(guò)注釋讓代碼更清晰「罚——Steve McConnel

學(xué)會(huì)編寫(xiě)容易理解的代碼怜珍,然后忽略下文的內(nèi)容。真的咽块!

對(duì)于標(biāo)題型的注釋?zhuān)褂弥辽偎膫€(gè)分號(hào)起始绘面。

對(duì)于頂層注釋?zhuān)褂萌齻€(gè)分號(hào)起始。

為某段代碼添加注釋時(shí)侈沪,使用兩個(gè)分號(hào)起始揭璃,且應(yīng)與該段代碼對(duì)齊。

對(duì)于行尾注釋?zhuān)褂靡粋€(gè)分號(hào)起始即可亭罪。

分號(hào)后面要有一個(gè)空格瘦馍。

1
2
3
4
5
6
7
8
9
10
11
12

;;;; Frob Grovel

;;; 這段代碼有以下前提:
;;; 1. Foo.
;;; 2. Bar.
;;; 3. Baz.

(defn fnord [zarquon]
;; If zob, then veeblefitz.
(quux zot
mumble ; Zibblefrotz.
frotz))

對(duì)于成句的注釋?zhuān)涫鬃帜笐?yīng)該大寫(xiě),句與句之間用一個(gè)空格分隔应役。
避免冗余的注釋?zhuān)?/p>

1
2

;; 錯(cuò)誤
(inc counter) ; counter變量的值加1

注釋要和代碼同步更新情组。過(guò)期的注釋還不如沒(méi)有注釋。
有時(shí)箩祥,使用#_
宏要優(yōu)于普通的注釋?zhuān)?/p>

1
2
3
4
5
6
7

;; 正確
(+ foo #_(bar x) delta)

;; 錯(cuò)誤
(+ foo
;; (bar x)
delta)

好的代碼和好的笑話(huà)一樣院崇,不需要額外的解釋∨圩妫——Russ Olsen

避免使用注釋去描述一段寫(xiě)得很糟糕的代碼底瓣。重構(gòu)它,讓它更為可讀蕉陋。(做或者不做捐凭,沒(méi)有嘗試這一說(shuō)〉树蓿——Yoda)

注釋中的標(biāo)識(shí)
標(biāo)識(shí)應(yīng)該寫(xiě)在對(duì)應(yīng)代碼的上一行茁肠。
標(biāo)識(shí)后面是一個(gè)冒號(hào)和一個(gè)空格,以及一段描述文字缩举。
如果標(biāo)識(shí)的描述文字超過(guò)一行垦梆,則第二行需要進(jìn)行縮進(jìn)匹颤。
將自己姓名的首字母以及當(dāng)前日期附加到標(biāo)識(shí)描述文字中:

1
2
3
4
5

(defn some-fun
[]
;; FIXME: 這段代碼在v1.2.3之后偶爾會(huì)崩潰,
;; 這可能和升級(jí)BarBazUtil有關(guān)奶赔。(xz 13-1-31)
(baz))

對(duì)于功能非常明顯惋嚎,實(shí)在無(wú)需添加注釋的情況,可以在行尾添加一個(gè)標(biāo)識(shí):

1
2
3

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

使用TODO
來(lái)表示需要后期添加的功能或特性站刑。
使用FIXME
來(lái)表示需要修復(fù)的問(wèn)題另伍。
使用OPTIMIZE
來(lái)表示會(huì)引起性能問(wèn)題的代碼,并需要修復(fù)绞旅。
使用HACK
來(lái)表示這段代碼并不正規(guī)摆尝,需要在后期進(jìn)行重構(gòu)。
使用REVIEW
來(lái)表示需要進(jìn)一步審查這段代碼因悲,如:REVIEW: 你確定客戶(hù)會(huì)正確地操作X嗎堕汞?

可以使用其它你認(rèn)為合適的標(biāo)識(shí)關(guān)鍵字,但記得一定要在項(xiàng)目的README
文件中描述這些自定義的標(biāo)識(shí)晃琳。

慣用法
使用函數(shù)式風(fēng)格進(jìn)行編程,避免改變變量的值卫旱。
保持編碼風(fēng)格。
用正常人的思維來(lái)思考顾翼。

貢獻(xiàn)
本文中的所有內(nèi)容都還沒(méi)有最后定型,我很希望能夠和所有對(duì)Clojure代碼規(guī)范感興趣的同仁一起編寫(xiě)此文适贸,從而形成一份對(duì)社區(qū)有益的文檔灸芳。
你可以隨時(shí)創(chuàng)建討論話(huà)題,或發(fā)送合并申請(qǐng)拜姿。我在這里提前表示感謝烙样。
宣傳
一份由社區(qū)驅(qū)動(dòng)的代碼規(guī)范如果得不到社區(qū)本身的支持和認(rèn)同,那它就毫無(wú)意義了蕊肥。發(fā)送一條推特误阻,向朋友和同事介紹此文。任何評(píng)論晴埂、建議、以及意見(jiàn)都能夠讓我們向前邁進(jìn)一小步寻定。請(qǐng)讓我們共同努力吧儒洛!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市狼速,隨后出現(xiàn)的幾起案子琅锻,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件恼蓬,死亡現(xiàn)場(chǎng)離奇詭異惊完,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)处硬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門(mén)小槐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人荷辕,你說(shuō)我怎么就攤上這事凿跳。” “怎么了疮方?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵控嗜,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我骡显,道長(zhǎng),這世上最難降的妖魔是什么壁顶? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮痹愚,結(jié)果婚禮上窖式,老公的妹妹穿的比我還像新娘萝喘。我一直安慰自己阁簸,他們只是感情好启妹,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布饶米。 她就那樣靜靜地躺著照瘾,像睡著了一般丧慈。 火紅的嫁衣襯著肌膚如雪伊滋。 梳的紋絲不亂的頭發(fā)上笑旺,一...
    開(kāi)封第一講書(shū)人閱讀 52,156評(píng)論 1 308
  • 那天关噪,我揣著相機(jī)與錄音,去河邊找鬼藤韵。 笑死欲险,一個(gè)胖子當(dāng)著我的面吹牛匹涮,可吹牛的內(nèi)容都是我干的然低。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼带兜,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼吨灭!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起涩咖,我...
    開(kāi)封第一講書(shū)人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎闸昨,沒(méi)想到半個(gè)月后薄风,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體循诉,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡茄猫,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了勇劣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片比默。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡退敦,死狀恐怖侈百,靈堂內(nèi)的尸體忽然破棺而出钝域,到底是詐尸還是另有隱情例证,我是刑警寧澤迷捧,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布,位于F島的核電站抵屿,受9級(jí)特大地震影響轧葛,放射性物質(zhì)發(fā)生泄漏尿扯。R本人自食惡果不足惜衷笋,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望慢蜓。 院中可真熱鬧晨抡,春花似錦耘柱、人聲如沸调煎。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)赤拒。三九已至挎挖,卻和暖如春肋乍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背锚烦。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工蛉拙, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留孕锄,地道東北人畸肆。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓轴脐,卻偏偏與公主長(zhǎng)得像大咱,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子丑搔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容