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í)
源代碼的布局和組織結(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)讓我們共同努力吧儒洛!