原文: 創(chuàng)業(yè)團(tuán)隊(duì)如何制定可執(zhí)行的代碼規(guī)范
回想起來(lái)自己工作這么些年豺型,也經(jīng)歷了不少團(tuán)隊(duì)毁涉,經(jīng)歷的項(xiàng)目更不算少了屑柔, 但是要說到代碼規(guī)范屡萤, 問我我經(jīng)歷的這些代碼規(guī)范是不是滿意,我不得不如實(shí)回答:不是很滿意掸宛。當(dāng)然我自己的代碼規(guī)范和風(fēng)格也沒有完全固化下來(lái)死陆,近一年左右也開始關(guān)注到這個(gè)問題,為了讓自己的代碼風(fēng)格能逐漸固化唧瘾,我會(huì)專門用一個(gè)筆記來(lái)記錄一些可能自己會(huì)糾結(jié)的寫法措译,這樣做了以后明顯能感覺到自己代碼風(fēng)格的飄忽程度有所收斂。恰巧公司負(fù)責(zé)的項(xiàng)目也需要整理代碼規(guī)范饰序,正因如此我開始思考如何制定可執(zhí)行的代碼規(guī)范這個(gè)問題领虹。
提到團(tuán)隊(duì)的代碼規(guī)范,不止我經(jīng)歷過的求豫,我和一些朋友也有聊過塌衰, 有微軟那個(gè)級(jí)別的诉稍,也有BAT這種級(jí)別的,項(xiàng)目大的也有最疆,小的亦很多杯巨。其中不乏規(guī)范的做的比較好的,有規(guī)范努酸、有工具服爷、還會(huì)有Code Review來(lái)保證。但是大公司規(guī)范和流程真的適合所有團(tuán)隊(duì)嗎获诈?我所看到的是大部分團(tuán)隊(duì)參照某某公司的規(guī)范和流程仍源,定義了一個(gè)非常嚴(yán)格的標(biāo)準(zhǔn),然而實(shí)際上并沒有嚴(yán)格實(shí)施下去或者沒有持續(xù)實(shí)施下去舔涎。最后都會(huì)甩鍋給“歷史包袱太重”镜会、“開發(fā)人員太多太雜難以推廣”這樣的理由。
近半年到一年在代碼規(guī)范這一塊我主要思考如何在中小團(tuán)隊(duì)沒有代碼規(guī)范的基礎(chǔ)上制定代碼規(guī)范终抽。根據(jù)自己的思考也正在組內(nèi)逐步實(shí)踐,從目前實(shí)踐情況來(lái)看我是比較滿意的桶至,所以把自己觀點(diǎn)寫出來(lái)昼伴,希望能對(duì)跟我有同樣困惑的人有些幫助。
代碼規(guī)范不應(yīng)該被定為KPI
所有的規(guī)范镣屹,包括但不限于代碼規(guī)范圃郊,都會(huì)包含規(guī)范制定、規(guī)范推廣執(zhí)行女蜈、規(guī)范修正的過程持舆。 其中規(guī)范的推廣和執(zhí)行通常是最難的(這就是為什么有很多流程文檔,但是流程還是非澄苯眩混亂的原因)逸寓,而制定了什么樣的規(guī)范直接決定了推廣執(zhí)行的難度,所以我們先從代碼規(guī)范的制定說起覆山。
大部分團(tuán)隊(duì)?wèi)?yīng)該都是有KPI的竹伸,而且一般重要的事情都會(huì)被定成KPI, 所以有些團(tuán)隊(duì)為了強(qiáng)調(diào)代碼規(guī)范簇宽, 將其定為某些員工的KPI勋篓,這樣重視代碼規(guī)范行為我是非常欣賞的,但是我不認(rèn)同魏割,因?yàn)槲艺J(rèn)為代碼規(guī)范不應(yīng)該是一個(gè)文檔譬嚣, 代碼規(guī)范應(yīng)該是一種行為, 一種持續(xù)的行為钞它,而KPI是要求可以量化有明確目標(biāo)的拜银。若把代碼規(guī)范當(dāng)作KPI殊鞭, 背了KPI的員工為了讓KPI可量化, 通常情況會(huì)寫出來(lái)一個(gè)代碼規(guī)范文檔盐股,眾所周知文檔最可 量化的當(dāng)然是頁(yè)數(shù)钱豁,故最終可能會(huì)產(chǎn)出一個(gè)幾十頁(yè)的代碼規(guī)范,它可能是結(jié)合了Google疯汁、Facebook牲尺、Tencent等等大公司的代碼規(guī)范,幾乎面面俱到幌蚊,看起來(lái)就很高大上谤碳。
代碼規(guī)范文檔出來(lái)了,KPI看起來(lái)也完成得不錯(cuò)溢豆,那然后呢蜒简?如果我們把代碼規(guī)范理解為一種行為,那這文檔就僅僅只是一個(gè)行為準(zhǔn)則漩仙,它就像是一部法律搓茬,要求大家都要如何做,所以接下來(lái)更重點(diǎn)的工作應(yīng)該是去讓這些文檔落地队他,讓大家理解認(rèn)可執(zhí)行它卷仑。并且還需要有相應(yīng)的監(jiān)督機(jī)制、審查機(jī)制來(lái)保證大家確實(shí)按規(guī)范在寫代碼麸折。但是后面這些锡凝,也就是整個(gè)代碼規(guī)范實(shí)施最難的點(diǎn),要量化又極其不易垢啼。能如何量化呢窜锯?量化推廣程度?量化大家對(duì)各條代碼規(guī)范的理解透徹程度芭析?難道用考試來(lái)量化嗎锚扎?這就是把代碼規(guī)范設(shè)定成KPI的尷尬, 為了讓KPI看起來(lái)豐滿馁启, 產(chǎn)出了一個(gè)豐滿的規(guī)范工秩, 而對(duì)于整個(gè)過程中最難的落地執(zhí)行環(huán)節(jié), 豐滿的規(guī)范為其增加了阻力进统。
以前我對(duì)于代碼規(guī)范的理解是也是越豐富越好助币,但是在近半年推廣代碼規(guī)范的過程中我開始青睞簡(jiǎn)單一些的代碼規(guī)范,因?yàn)槲蚁嘈糯蟛糠秩藭?huì)贊同:一個(gè)被100%徹底執(zhí)行了的40分代碼規(guī)范應(yīng)該是好于一個(gè)被執(zhí)行了40%的100分代碼規(guī)范螟碎。
制定代碼規(guī)范要循序漸進(jìn)
這個(gè)觀點(diǎn)可能會(huì)更比較多人的看法不太一樣眉菱, 因?yàn)楹芏嗳硕颊J(rèn)為規(guī)范應(yīng)該前期就定下來(lái),而且盡可能面面俱到掉分,否則后面定規(guī)范容易背上歷史包袱俭缓。前期就應(yīng)該定規(guī)范的這個(gè)觀點(diǎn)我比較認(rèn)同克伊,首先我們拋開你們團(tuán)隊(duì)已經(jīng)有非常完善代碼規(guī)范這種情況,因?yàn)槿绻悄菢踊梗阒恍枰丛幸?guī)范執(zhí)行即可愿吹。這里主要討論新項(xiàng)目沒有規(guī)范的情況下怎么做,我們可以復(fù)盤一下新項(xiàng)目開始階段惜姐,通常情況新項(xiàng)目需求節(jié)奏都會(huì)非忱绻颍快,基礎(chǔ)框架歹袁、基礎(chǔ)組件坷衍、大批量業(yè)務(wù)需求要開發(fā),又因?yàn)槭切马?xiàng)目条舔,通常不會(huì)有特別多的人力投入枫耳,這種情況下,一個(gè)很嚴(yán)格冗長(zhǎng)的代碼規(guī)范孟抗,要求大家在拼命跑的過程中還要去理解執(zhí)行你的規(guī)范迁杨,可能性大嗎?所以這個(gè)時(shí)期的代碼規(guī)范需要非常簡(jiǎn)單易于理解凄硼,要在所有人即使在趕需求铅协,也能忍受的范圍內(nèi)制定規(guī)范。這個(gè)階段最急迫的需求是用簡(jiǎn)單的代碼規(guī)范讓大家養(yǎng)成習(xí)慣帆喇,提升意識(shí),宣告這個(gè)項(xiàng)目是有規(guī)范的亿胸。
我們拿前端項(xiàng)目來(lái)舉例坯钦,首先應(yīng)該先保證JS代碼風(fēng)格是對(duì)的,其次可能根據(jù)技術(shù)選型不同(例如Angular侈玄,React)婉刀,要遵循另外一批Best Practice。按上述思路序仙,我會(huì)在前期只要求大家JS代碼格式規(guī)范就行了突颊。因?yàn)榘迅鞣NBest Practice一股腦的全丟進(jìn)去容易繞暈大家。 如果你真的舍不得那些Best Practice潘悼,我建議將其列為建議級(jí)別的律秃,先不做必須,必須的條目盡可能精簡(jiǎn)治唤。
制定代碼規(guī)范需要"獨(dú)裁"
上面一段提到代碼規(guī)范應(yīng)該循序漸進(jìn)棒动,但是簡(jiǎn)單的規(guī)范從何而來(lái)呢?之前看到過的一種做法是:團(tuán)隊(duì)內(nèi)大家一起討論宾添,民主決定某一些規(guī)范的細(xì)節(jié)船惨,因?yàn)檫@樣可以出來(lái)一個(gè)適配這個(gè)團(tuán)隊(duì)的代碼規(guī)范柜裸。 這聽起來(lái)很美好,非常民主粱锐,大家很平等疙挺,但是回想一下以前這么做的結(jié)果是什么?我猜應(yīng)該會(huì)有很多人又回憶起“大括號(hào)應(yīng)不應(yīng)該換行”怜浅、“else是否應(yīng)該換行”铐然、“是否允許空兩行”、“JS結(jié)尾帶不帶分號(hào)”等等類似的爭(zhēng)論吧海雪,然而這些爭(zhēng)論是有必要的嗎锦爵?說白了,大部分爭(zhēng)論找的理由都只是在為自己的代碼習(xí)慣爭(zhēng)取更多空間奥裸。這樣的爭(zhēng)論還只是“民主”引發(fā)問題的開始险掀,更嚴(yán)重的是這會(huì)在所有開發(fā)人員心中形成一種“規(guī)范是可以商量和討論的”心理暗示,這必對(duì)后續(xù)規(guī)范的執(zhí)行成為阻礙湾宙,特別是一些本身就有爭(zhēng)議的點(diǎn)樟氢,總會(huì)有人伺機(jī)反撲。另外侠鳄,“民主”的規(guī)范其實(shí)很難做到讓所有人心理上平衡埠啃,例如可能會(huì)讓B開發(fā)覺得自己在遵從A開發(fā)的習(xí)慣,即使這種感覺可能不是那么強(qiáng)烈伟恶,它也會(huì)變成規(guī)范執(zhí)行的阻力碴开。
正因?yàn)樯鲜鲈颍曳浅=ㄗh制定規(guī)范時(shí)“獨(dú)裁”博秫。我們的目標(biāo)很清晰潦牛,就是要求代碼寫法一致,“獨(dú)裁”的基礎(chǔ)上可以選擇一個(gè)第三方的標(biāo)準(zhǔn)挡育,例如細(xì)的條目可以完全選擇Google或者Facebook或者其他一些大公司的標(biāo)準(zhǔn)(當(dāng)然可能還需要考慮我上面提到的循序漸進(jìn)巴碗,做裁剪,但是規(guī)則細(xì)則不要再去討論和挑戰(zhàn))即寒。首先可以保證的是這些規(guī)范不會(huì)有太大的問題橡淆,跟著做不會(huì)犯大錯(cuò);其次母赵,“獨(dú)裁”使用的規(guī)范來(lái)源于第三方逸爵,對(duì)團(tuán)隊(duì)內(nèi)所有人公平;最后凹嘲,這樣的規(guī)范和行業(yè)更親近痊银。
我在我們的前端項(xiàng)目里面就選擇了StandardJS的規(guī)范,StandardJS的出現(xiàn)初衷也正是為了解決上述“民主”引發(fā)的問題施绎。除此之外溯革,還有一個(gè)好處是這些第三方規(guī)范的成熟不只是規(guī)范本身贞绳,它的配套工具會(huì)成熟很多,可以節(jié)省自己很多成本致稀。
代碼規(guī)范從“立法”到“執(zhí)法”
上面我們已經(jīng)討論了如何建立代碼規(guī)范冈闭,主要強(qiáng)調(diào)了代碼規(guī)范不應(yīng)只是一紙空文、代碼規(guī)范要循序漸進(jìn)抖单、代碼規(guī)范的制定需要“獨(dú)裁”萎攒。這些都屬于“立法”過程,接下來(lái)要討論的必然是“執(zhí)法”矛绘,代碼規(guī)范的“執(zhí)法”主要需要關(guān)注兩點(diǎn)耍休,一點(diǎn)是“違法”行為的判定,另一點(diǎn)是“違法”行為的責(zé)任追究货矮,也就是代碼規(guī)則檢查以及發(fā)現(xiàn)不符合規(guī)范的代碼應(yīng)該由誰(shuí)來(lái)負(fù)責(zé)羊精。
代碼規(guī)則檢查通常直接使用現(xiàn)有成熟工具就好,例如前端開發(fā)常用的ESLint囚玫,現(xiàn)在各種語(yǔ)言都有各自比較成熟的工具喧锦,我這里想強(qiáng)調(diào)的是幾個(gè)檢查代碼的時(shí)機(jī),一是寫代碼的時(shí)候抓督,這是源頭燃少,配置一個(gè)好的IDE檢查規(guī)則能從源頭避免不規(guī)范的代碼。二是提交時(shí)候铃在,通常是設(shè)置git/svn的hooks(PS: git的hooks在2.9.0之前相當(dāng)?shù)碾y用阵具,如果你用的版本低于2.9.0,可以考慮升級(jí)并配置代碼檢查的鉤子)定铜。三是CI的時(shí)候阳液,這是最后一關(guān),可以保證合流以后的代碼不出現(xiàn)規(guī)范的問題宿稀。只要在上面三個(gè)點(diǎn)嚴(yán)格執(zhí)行了趁舀,不規(guī)范的代碼幾乎已經(jīng)無(wú)處可藏赖捌。
“違法”行為判定盡可能通過工具來(lái)判定祝沸,那如果出現(xiàn)了庫(kù)里面提交了不合規(guī)則的代碼應(yīng)該由誰(shuí)去改呢?如果有CI越庇,那只需要增加提交構(gòu)建罩锐,即可在push后的第一時(shí)間揪出違規(guī)者。如果沒有CI卤唉,我建議是先建立CI涩惑,如果實(shí)在沒有,那可以考慮最后提交代碼負(fù)責(zé)制桑驱,最后提交代碼的人可以去找這份代碼是merge了誰(shuí)的竭恬,追溯到上游把“鍋”丟出去跛蛋,最終找到違規(guī)者并要求改進(jìn)(不限于代碼的改進(jìn),更重要的是各種代碼檢查環(huán)境的配置)痊硕。這樣的定義可以讓所有開發(fā)知道遇到問題以后該如何走下一步赊级,我認(rèn)為是非常有必要的。
說到這里我猜必然有讀者想到了Code Review岔绸,實(shí)際上Code Review不應(yīng)該是去關(guān)注代碼風(fēng)格的理逊,所有到Code Review環(huán)節(jié)的代碼必然是要過了代碼風(fēng)格檢查的,Code Review主要關(guān)注的是代碼結(jié)構(gòu)設(shè)計(jì)和代碼邏輯盒揉,它是在代碼規(guī)范上一層的東西晋被。如果你的團(tuán)隊(duì)在使用Code Review來(lái)保證代碼規(guī)范,那你們可能需要進(jìn)一步完善自己的代碼規(guī)范檢查工具刚盈。
總結(jié)
代碼規(guī)范的好處大家都知道羡洛,但是任重道遠(yuǎn)。真正去推行代碼規(guī)范的人扁掸,如果按我上面說的幾點(diǎn)去做翘县,可能會(huì)有各方面的壓力,特別是上面提到的“獨(dú)裁”和“執(zhí)法”兩點(diǎn)谴分,但是從我自己的實(shí)踐經(jīng)驗(yàn)來(lái)看锈麸,想象中的壓力小于實(shí)際,主要還是需要向同事們解釋清楚各種做法的理由牺蹄,得到理解和支持忘伞。為了避免前期的推行的壓力過大,可以考慮裁剪規(guī)則(特別是在沒有很好代碼規(guī)范文化的團(tuán)隊(duì)內(nèi))沙兰,因?yàn)樘嵘龍F(tuán)隊(duì)人員意識(shí)和養(yǎng)成代碼規(guī)范的習(xí)慣應(yīng)該是最最首要的任務(wù)氓奈,這兩點(diǎn)有了以后,再逐步的把要求提高鼎天,應(yīng)該會(huì)容易得多舀奶。這個(gè)過程有困難,但是我堅(jiān)定的認(rèn)為這是值得的斋射。