1 簡(jiǎn)介
? ?Google具有許多涵蓋所有語(yǔ)言和所有項(xiàng)目的通用工程實(shí)踐,這些文檔代表了我們隨著時(shí)間的推移積累的各種最佳實(shí)踐的集體經(jīng)驗(yàn)。開(kāi)源項(xiàng)目或其他組織可能會(huì)從此知識(shí)中受益,因此我們致力于在可能的情況下將其公開(kāi)提供。
1.1 術(shù)語(yǔ)
這些文檔中有一些使用Google內(nèi)部術(shù)語(yǔ),我們?cè)诖讼蛲獠孔x者闡明這些術(shù)語(yǔ):
- CL:代表“變更列表”(
ChangeList),表示一個(gè)已包含到版本控制中或正在進(jìn)行代碼評(píng)審的更改。其他組織通常將其稱為“更改”或“補(bǔ)丁”。 - LGTM:代碼評(píng)審者在批準(zhǔn)CL時(shí)所說(shuō)的“在我看來(lái)這個(gè)CL很好”的縮寫(xiě),即
look good to me的縮寫(xiě)。 - Nit: 全稱
nitpick,意思是雞蛋里挑骨頭。
1.2 指南說(shuō)明
? ?在Google,我們通過(guò)代碼評(píng)審來(lái)保證代碼和產(chǎn)品的質(zhì)量。代碼評(píng)審是一個(gè)過(guò)程,在此過(guò)程中,代碼段作者以外的人來(lái)評(píng)審這段代碼。本文檔是Google代碼評(píng)審流程和政策的規(guī)范描述。
Google的代碼評(píng)審指南,實(shí)際上包含兩組獨(dú)立的文檔:
- 如何進(jìn)行代碼評(píng)審?
- CL開(kāi)發(fā)者指南
2 如何進(jìn)行代碼評(píng)審?
2.1 引言
2.1.1 代碼評(píng)審到底評(píng)審什么
代碼評(píng)審應(yīng)關(guān)注的點(diǎn):
- 設(shè)計(jì):代碼是否經(jīng)過(guò)精心設(shè)計(jì)并適合你的系統(tǒng)?
- 功能:代碼是否符合開(kāi)發(fā)者的預(yù)期意圖?代碼對(duì)用戶的表現(xiàn)是否良好?
- 復(fù)雜性:可以簡(jiǎn)化代碼嗎?將來(lái)當(dāng)其他開(kāi)發(fā)人員遇到該代碼時(shí),他們是否能夠輕松理解和使用該代碼?
- 測(cè)試:是否有正確且設(shè)計(jì)良好的自動(dòng)化測(cè)試?
- 命名:開(kāi)發(fā)人員是否為變量,類,方法等選擇了清晰的名稱?
- 注釋:這些注釋是否清晰有用?
- 風(fēng)格:代碼是否遵循我們的風(fēng)格指南?
- 文檔:開(kāi)發(fā)者是否也更新了相關(guān)的文檔?
2.1.2 選擇最佳的評(píng)審者
? ?通常,你希望找到能夠在合理的時(shí)間內(nèi)對(duì)你的代碼做出回復(fù)的最佳評(píng)審者。
? ?最好的評(píng)審者應(yīng)該是能夠?yàn)槟銓?xiě)的代碼片段提供最徹底、最正確的評(píng)審的人。通常,代碼的擁有者是OWNERS中的人,但也可能不是。這意味著有時(shí)需要不同的人來(lái)查看CL的不同部分。
? ?如果找到了理想的評(píng)審者但他們卻沒(méi)有時(shí)間,至少要將更改的內(nèi)容抄送給他們。
2.1.3 自我評(píng)審
? ?如果你與某人一起對(duì)一段代碼進(jìn)行編程,并且他有資格對(duì)代碼進(jìn)行良好的代碼評(píng)審,則該代碼將被視為已評(píng)審。
? ?你還可以進(jìn)行自我代碼評(píng)審(即自己既扮演開(kāi)發(fā)者,又扮演評(píng)審者)。評(píng)審者會(huì)提出問(wèn)題,而CL的開(kāi)發(fā)者只有在被提問(wèn)時(shí)才能回答。
2.2 代碼評(píng)審標(biāo)準(zhǔn)
? ?代碼評(píng)審的主要目的是確保Google代碼庫(kù)的整體代碼運(yùn)行狀況隨著時(shí)間的推移而不斷改善。所有代碼評(píng)審工具和過(guò)程都是為此目的而生。
? ?為了實(shí)現(xiàn)這一點(diǎn),必須做出一些折衷。
? ?首先,開(kāi)發(fā)人員必須能夠在其任務(wù)上取得進(jìn)展。如果你從未向代碼庫(kù)提交過(guò)改進(jìn),那么代碼庫(kù)將永遠(yuǎn)不會(huì)得到改進(jìn)。另外,如果評(píng)審人員讓任何更改都很難進(jìn)行,那么開(kāi)發(fā)人員將沒(méi)有動(dòng)力做出一些改進(jìn)。
? ?另一方面,評(píng)審者有責(zé)任保證每個(gè)CL的質(zhì)量,以使得代碼庫(kù)的整體代碼運(yùn)行狀況不會(huì)隨著時(shí)間的流逝而減少。有種情況比較棘手:因?yàn)殡S著時(shí)間的推移,通常會(huì)由于每次CL小幅的下降而導(dǎo)致代碼庫(kù)整體的退化,尤其是當(dāng)團(tuán)隊(duì)處于明顯的時(shí)間限制下并且他們認(rèn)為必須采取捷徑才能實(shí)現(xiàn)其目標(biāo)時(shí)。
? ?此外,評(píng)審者對(duì)他們正在評(píng)審的代碼擁有所有權(quán)和責(zé)任。他們需要確保代碼庫(kù)的一致性、可維護(hù)性、以及2.1.1節(jié)“代碼評(píng)審到底評(píng)審什么”中提到的所有其他事項(xiàng)。
? ?因此,我們期望將以下規(guī)則作為代碼評(píng)審中的標(biāo)準(zhǔn):
? ?通常,即使CL并不完美,但可以肯定它能改善正在使用的系統(tǒng)的整體代碼運(yùn)行狀況,則評(píng)審者就應(yīng)該通過(guò)它。
? ?這是所有代碼評(píng)審指南中的高級(jí)原則。
? ?當(dāng)然,這是有局限性的。例如,如果CL添加了評(píng)審者不希望在其系統(tǒng)中使用的功能,那么即使代碼設(shè)計(jì)得當(dāng),評(píng)審者也可以拒絕通過(guò)它。
? ?這里一個(gè)關(guān)鍵點(diǎn)是:沒(méi)有“完美”的代碼,只有更好的代碼。評(píng)審人不應(yīng)要求開(kāi)發(fā)者在批準(zhǔn)前將CL的每一小塊都做優(yōu)化。相反,與他們所建議的更改的重要性相比,評(píng)審者應(yīng)該平衡取得進(jìn)步的需要。評(píng)審者追求的不是完美,而是持續(xù)改進(jìn)。總體而言,提高系統(tǒng)的可維護(hù)性,可讀性和可理解性的CL不能因?yàn)樗皇恰巴昝赖摹倍谎舆t幾天或幾周通過(guò)。
? ?評(píng)審者應(yīng)該隨時(shí)對(duì)可以優(yōu)化的代碼發(fā)表評(píng)論,但是如果不是很重要,可以在其前面加上“ Nit:”之類的字眼,以使作者知道這只是他們可以選擇忽略的優(yōu)化點(diǎn)。
2.2.1 指導(dǎo)
? ?代碼評(píng)審具有重要的功能,可以教給開(kāi)發(fā)者有關(guān)語(yǔ)言、框架或通用軟件設(shè)計(jì)原理方面的新知識(shí)。留下有助于開(kāi)發(fā)者學(xué)習(xí)新知識(shí)的評(píng)論總是很好的。共享知識(shí)是隨著時(shí)間的推移而改善系統(tǒng)代碼運(yùn)行狀況的一部分。請(qǐng)記住,如果你的評(píng)論純粹是教育性的,但對(duì)于滿足本文檔中描述的標(biāo)準(zhǔn)不是至關(guān)重要的,請(qǐng)?jiān)谄淝熬Y前面加上“ Nit:”,或者對(duì)代碼提交者表明并非強(qiáng)制要求在本次CL中一定要對(duì)其解決。
2.2.2 原則
- 技術(shù)事實(shí)和數(shù)據(jù)要大于意見(jiàn)和個(gè)人偏好。
- 在代碼樣式方面,樣式指南是絕對(duì)權(quán)威的。不在樣式指南中的任何純樣式點(diǎn)(如空格等)都是個(gè)人喜好問(wèn)題。樣式應(yīng)與代碼中的樣式保持一致。如果沒(méi)有以前的樣式,請(qǐng)接受開(kāi)發(fā)者的樣式。
- 軟件設(shè)計(jì)方面幾乎從來(lái)都不是純粹的樣式問(wèn)題,也不是個(gè)人喜好問(wèn)題。 它們基于基本原則,應(yīng)權(quán)衡這些原則,而不僅僅是個(gè)人意見(jiàn)。 有時(shí)會(huì)有一些有效的其他選擇,如果開(kāi)發(fā)者可以證明(通過(guò)數(shù)據(jù)或基于可靠的工程原理)幾種方法同樣有效,那么評(píng)審者應(yīng)接受開(kāi)發(fā)者的偏愛(ài)。 否則,最終的選擇需要由軟件設(shè)計(jì)的標(biāo)準(zhǔn)原理來(lái)決定。
- 如果沒(méi)有其他規(guī)則適用,則評(píng)審者可以要求開(kāi)發(fā)者與當(dāng)前代碼庫(kù)中的內(nèi)容保持一致,只要這不會(huì)使系統(tǒng)的總體代碼運(yùn)行狀況惡化。
2.2.3 解決沖突
? ?在代碼評(píng)審中發(fā)生任何沖突時(shí),第一步應(yīng)始終是基于本指南促使開(kāi)發(fā)者和評(píng)審者達(dá)成共識(shí)。
? ?當(dāng)達(dá)成共識(shí)變得特別困難時(shí),在評(píng)審者和開(kāi)發(fā)者之間進(jìn)行面對(duì)面的會(huì)議或VC可能會(huì)有所幫助,而不僅僅是嘗試通過(guò)代碼評(píng)審注釋來(lái)解決沖突。(但如果這樣做了,請(qǐng)確保將討論的結(jié)果記錄在CL上的注釋中,以備將來(lái)閱讀。)
? ?如果那不能解決問(wèn)題,則最常見(jiàn)的解決方法是升級(jí)。升級(jí)的途徑通常是進(jìn)行更廣泛的團(tuán)隊(duì)討論,其中包括TL的權(quán)衡,要求代碼維護(hù)者的決定或要求Eng經(jīng)理提供幫助。不要因?yàn)殚_(kāi)發(fā)者和評(píng)審者不能達(dá)成一致意見(jiàn)而讓CL一直放在那里。
2.3 代碼評(píng)審到底評(píng)審什么?
2.3.1 設(shè)計(jì)
? ?評(píng)審中最重要的內(nèi)容是CL的總體設(shè)計(jì)。CL中各種代碼的交互是否有意義?此更改是屬于你的代碼庫(kù)還是lib包?它與系統(tǒng)的其余部分是否集成良好?現(xiàn)在是添加此功能的好時(shí)機(jī)嗎?
2.3.2 功能性
? ?此CL是否達(dá)到開(kāi)發(fā)者的預(yù)期目的?開(kāi)發(fā)者打算為該代碼的用戶帶來(lái)什么好處? 這里的“用戶”通常既是最終用戶(當(dāng)此代碼更改時(shí)影響到的人)又是開(kāi)發(fā)人員(將來(lái)他們將不得不“使用”此代碼的人)。
? ?通常,我們希望開(kāi)發(fā)者能夠?qū)L進(jìn)行良好的測(cè)試,以確保它們?cè)谶M(jìn)行代碼評(píng)審時(shí)能夠正常工作。但是,作為評(píng)審者,你仍然應(yīng)該考慮邊緣情況,尋找并發(fā)性問(wèn)題,嘗試像用戶一樣思考,并確保沒(méi)有僅僅通過(guò)閱讀代碼就能看到的錯(cuò)誤。
? ?你可以根據(jù)需要驗(yàn)證CL,對(duì)于評(píng)審者而言,檢查CL的行為最重要的時(shí)間點(diǎn)是對(duì)用戶產(chǎn)生影響時(shí)(例如UI更改)。當(dāng)你僅僅閱讀代碼時(shí),很難理解某些更改將如何影響用戶。對(duì)于這樣的更改,如果過(guò)于麻煩而無(wú)法自己嘗試,則可以讓開(kāi)發(fā)人員為你提供功能演示。
? ?在代碼評(píng)審時(shí),另一個(gè)需要特別重點(diǎn)考慮功能性的時(shí)間點(diǎn)是:CL中是否正在進(jìn)行某種并行編程,從理論上講它可能會(huì)導(dǎo)致死鎖或競(jìng)爭(zhēng)條件。僅通過(guò)運(yùn)行代碼很難檢測(cè)到這類問(wèn)題,通常需要有人(開(kāi)發(fā)人員和評(píng)審者)仔細(xì)考慮它們,以確保不會(huì)引入問(wèn)題。 (請(qǐng)注意,這也是在可能出現(xiàn)競(jìng)爭(zhēng)條件或死鎖的情況下不使用并發(fā)模型的一個(gè)很好的理由,這會(huì)使進(jìn)行代碼評(píng)審或理解代碼非常復(fù)雜。)
2.3.3 復(fù)雜性
? ?CL是否本不需要如此復(fù)雜? 對(duì)CL的每個(gè)維度都要進(jìn)行檢查——個(gè)別行是否太復(fù)雜? 功能太復(fù)雜了嗎? 類太復(fù)雜了嗎? “太復(fù)雜”通常意味著“代碼閱讀者無(wú)法快速理解”。 這也可能意味著“開(kāi)發(fā)者在嘗試調(diào)用或修改此代碼時(shí)更可能引入bug”。
? ?一種特殊類型的復(fù)雜性是過(guò)度設(shè)計(jì),即開(kāi)發(fā)人員使代碼變得比需要的通用,或者增加了系統(tǒng)目前不需要的功能。評(píng)審者應(yīng)特別警惕過(guò)度設(shè)計(jì)。鼓勵(lì)開(kāi)發(fā)人員解決他們現(xiàn)在需要解決的已知問(wèn)題,而不是解決開(kāi)發(fā)者認(rèn)為將來(lái)可能需要解決的問(wèn)題。
2.3.4 測(cè)試
? ?根據(jù)更改需求進(jìn)行單元測(cè)試、集成測(cè)試或端到端測(cè)試。通常,應(yīng)在與生產(chǎn)代碼相同的CL中添加測(cè)試,除非CL在處理緊急情況。
? ?確保CL中的測(cè)試正確、合理且有用。測(cè)試代碼不會(huì)測(cè)試他們自己,我們也很少為測(cè)試代碼編寫(xiě)測(cè)試腳本,所以必須要確保測(cè)試是有效的。
? ?代碼損壞時(shí),測(cè)試會(huì)執(zhí)行失敗嗎? 如果代碼基于它來(lái)更改,將會(huì)產(chǎn)生誤報(bào)嗎?每個(gè)測(cè)試都會(huì)做出簡(jiǎn)單而有用的斷言嗎? 測(cè)試是否在不同的測(cè)試方法之間適當(dāng)?shù)胤珠_(kāi)?
? ?請(qǐng)記住,測(cè)試代碼也是必須維護(hù)的。 不要僅僅因?yàn)樗鼈儾皇侵鬟壿嫷囊徊糠侄邮軠y(cè)試代碼的復(fù)雜性設(shè)計(jì)。
2.3.5 命名
? ?開(kāi)發(fā)人員是否為代碼中所有的變量、類、方法等選擇了一個(gè)好名字? 一個(gè)好名字需要足夠長(zhǎng)以充分傳達(dá)它的含義或作用,但又不能太長(zhǎng)而令人難以閱讀。
2.3.6 注釋
? ?開(kāi)發(fā)人員是否用可理解的英語(yǔ)寫(xiě)下了清晰的注釋?所有注釋實(shí)際上都是必要的嗎? 通常,解釋了為什么存在某些代碼的注釋是非常有用的,而不應(yīng)該解釋某些代碼在做什么時(shí)。如果代碼不夠清晰,且無(wú)法解釋自身,則應(yīng)使代碼更簡(jiǎn)單。有一些例外情況(例如,正則表達(dá)式和復(fù)雜算法通常會(huì)在注釋中解釋它們的作用,從而大大受益),但大多數(shù)注釋是針對(duì)代碼本身無(wú)法包含的信息,例如決策背后的原因。
? ?查看此CL之前的注釋可能對(duì)你也會(huì)有所幫助。比如,也許有一個(gè)TODO現(xiàn)在可以刪除了、有意見(jiàn)或建議不要進(jìn)行此更改等等。
? ?請(qǐng)注意:注釋與類、模塊或函數(shù)的文檔不同,注釋?xiě)?yīng)表示一段代碼的用途,包括它應(yīng)如何使用以及使用時(shí)的會(huì)發(fā)生什么。
2.3.7 代碼樣式
? ?Google提供了所有主要語(yǔ)言甚至大多數(shù)次要語(yǔ)言的樣式指南。 確保CL遵循適當(dāng)?shù)臉邮街改稀?br>
? ?如果你想改善樣式指南中沒(méi)有的樣式點(diǎn),請(qǐng)?jiān)谧⑨屒懊婕由稀?Nit:”,以使開(kāi)發(fā)人員知道這是你認(rèn)為可以改善代碼但不是強(qiáng)制性的要求。不要阻撓僅根據(jù)個(gè)人風(fēng)格偏好提交的CL。
? ?CL的開(kāi)發(fā)者不應(yīng)將主要樣式更改與其他更改混在一起。這使得很難看到CL中的更改,合并和回滾也會(huì)變得更加復(fù)雜,并導(dǎo)致其他問(wèn)題。例如,如果開(kāi)發(fā)者想要重新格式化整個(gè)文件,請(qǐng)他們僅將重新格式化的格式作為一個(gè)CL發(fā)送給你,然后再發(fā)送另一個(gè)具有功能更改的CL。
2.3.8 文檔
? ?如果CL改變了用戶構(gòu)建、測(cè)試、與代碼交互或釋放代碼的方式,請(qǐng)檢查其是否還更新了相關(guān)限的文檔,包括README文件、頁(yè)面和任何生成的參考文檔。如果CL刪除或棄用了代碼,請(qǐng)考慮是否還應(yīng)刪除該文檔。如果缺少文檔,請(qǐng)?zhí)峤o開(kāi)發(fā)者。
2.3.9 每一行代碼
? ?查看已分配給你檢查的每一行代碼。有時(shí)可以掃描諸如數(shù)據(jù)文件、生成的代碼或大型數(shù)據(jù)結(jié)構(gòu)之類的東西,但不要掃描人工編寫(xiě)的類、函數(shù)或代碼塊,并假設(shè)其中的內(nèi)容是沒(méi)問(wèn)題的。顯然,某些代碼比其他代碼更需要仔細(xì)檢查——這是你必須要做出的判斷,但你至少應(yīng)確保你了解所有代碼在做什么。
? ?如果對(duì)你來(lái)說(shuō)某段代碼太難閱讀了,這會(huì)使評(píng)審速度變慢,那么你應(yīng)該讓開(kāi)發(fā)人員知道這一點(diǎn),并讓他們解釋一下,然后再嘗試評(píng)審。在Google,我們聘請(qǐng)的都是出色的軟件工程師,你也是其中之一。如果你看不懂這段代碼,其他開(kāi)發(fā)人員也很可能看不懂。 因此,當(dāng)你要求開(kāi)發(fā)者進(jìn)行解釋時(shí),你還可以幫助將來(lái)的開(kāi)發(fā)人員理解此代碼。
? ?如果你了解代碼,但又認(rèn)為沒(méi)有資格進(jìn)行某部分的評(píng)審,請(qǐng)確保在CL上有一位合格的評(píng)審員,特別是在復(fù)雜性問(wèn)題上(例如安全性、并發(fā)性、可訪問(wèn)性、國(guó)際化等)。
2.3.10 上下文
? ?在廣泛的上下文下查看CL通常會(huì)很有幫助。 通常,代碼查看工具只會(huì)向你顯示圍繞要更改的部分的幾行代碼。有時(shí),你必須查看整個(gè)文件,以確保更改確實(shí)有意義。例如,你可能會(huì)看到僅添加了四行,但是當(dāng)你查看整個(gè)文件時(shí),你會(huì)看到這四行分散到一個(gè)50行的方法中,所以開(kāi)發(fā)者需要將其分解為較小的方法。
? ?在整個(gè)系統(tǒng)的上下文中考慮CL也很有用。此CL是在改善系統(tǒng)的代碼運(yùn)行狀況,還是使整個(gè)系統(tǒng)更加復(fù)雜,測(cè)試更少等?不要接受會(huì)降低系統(tǒng)代碼運(yùn)行狀況的CL。大多數(shù)系統(tǒng)會(huì)通過(guò)許多小的更改而變得復(fù)雜,因此,重要的是要防止新更改中出現(xiàn)很小的復(fù)雜性。
2.3.11 好的事情
? ?如果你在CL中看到不錯(cuò)的東西,請(qǐng)告訴開(kāi)發(fā)人員,尤其是當(dāng)他們以出色的方式回答了你的評(píng)論之一時(shí)。代碼評(píng)審?fù)ǔV魂P(guān)注錯(cuò)誤,但是他們也應(yīng)該鼓勵(lì)和贊賞良好實(shí)踐。在指導(dǎo)方面,有時(shí)候告訴開(kāi)發(fā)人員正確的做法比告訴他們哪里做錯(cuò)了更有價(jià)值。
2.3.12 總結(jié)
在進(jìn)行代碼評(píng)審時(shí),你應(yīng)確保:
- 代碼經(jīng)過(guò)精心設(shè)計(jì)。
- 功能對(duì)代碼的用戶來(lái)說(shuō)要友好。
- UI的任何更改都是有效的,并且看起來(lái)不錯(cuò)。
- 任何并行編程都是安全完成的。
- 代碼實(shí)現(xiàn)沒(méi)有比需要的復(fù)雜。
- 開(kāi)發(fā)人員沒(méi)有實(shí)現(xiàn)他們將來(lái)可能需要的東西,但不知道他們現(xiàn)在需要什么。
- 代碼具有適當(dāng)?shù)膯卧獪y(cè)試。
- 測(cè)試代碼經(jīng)過(guò)精心設(shè)計(jì)。
- 開(kāi)發(fā)者對(duì)所有內(nèi)容都使用了清晰的名稱。
- 注釋是清晰而有用的,并且大多數(shù)解釋了原因而不是什么。
- 代碼已正確文檔化(通常在g3doc中)。
- 代碼符合我們的樣式指南。
確保評(píng)審要求檢查的每一行代碼、查看上下文、確保改善代碼的運(yùn)行狀況、并稱贊開(kāi)者所做的出色工作。
2.4 瀏覽評(píng)審中的CL
2.4.1 摘要
? ?既然你已經(jīng)知道”評(píng)審代碼什么到底在評(píng)審什么"了,那么管理分散在多個(gè)文件中的代碼評(píng)審的最有效方法是什么呢?
- 這個(gè)更改有意義嗎?它有一個(gè)很好的描述嗎?
- 看一下變化中最重要的部分,它整體設(shè)計(jì)得好嗎?
- 以適當(dāng)?shù)捻樞虿榭雌溆嗟腃L。
2.4.2 第一步:全面了解變化
? ?通常,通過(guò)查看CL的描述以及CL的功能來(lái)了解更改。但這種更改有意義嗎?如果發(fā)現(xiàn)不應(yīng)該進(jìn)行此更改,請(qǐng)立即做出回復(fù),并說(shuō)明為什么不應(yīng)該進(jìn)行更改。當(dāng)你拒絕這樣的更改時(shí),最好向開(kāi)發(fā)者建議一下他們應(yīng)該做些什么。
? ?例如,你可能會(huì)說(shuō):“看起來(lái)你在其中做了一些出色的工作,謝謝!但是,我們實(shí)際上正朝著刪除你在此處修改的FooWidget系統(tǒng)的方向發(fā)展,因此我們不想現(xiàn)在對(duì)其做任何新的修改。相反,重構(gòu)我們的新BarWidget類如何?”
? ?請(qǐng)注意,評(píng)審者不僅拒絕了當(dāng)前的CL并提出其他建議,而且還禮貌地做到了。這種禮貌很重要,因?yàn)榧词刮覀儾煌?,作為開(kāi)發(fā)者我們也想表明我們彼此尊重。
? ?如果收到多個(gè)你不想更改的CL,則應(yīng)考慮重新設(shè)計(jì)團(tuán)隊(duì)的開(kāi)發(fā)流程或已發(fā)布的外部貢獻(xiàn)者的流程,以便在編寫(xiě)CL之前進(jìn)行更多的溝通。最好在人們完成大量現(xiàn)在必須扔掉或徹底重寫(xiě)的工作之前告訴他們“不”。
2.4.3 第二步:檢查CL的主要部分
? ?查找屬于此CL的“主要”部分的文件。通常,如果一個(gè)文件的邏輯更改數(shù)量最多,那么它就是CL的主要部分。首先看這些主要部分。這有助于為CL的所有較小部分提供上下文,并通常加快執(zhí)行代碼評(píng)審的速度。如果CL太大,你無(wú)法確定哪些部分是主要零件,請(qǐng)?jiān)儐?wèn)開(kāi)發(fā)者你應(yīng)該首先看什么,或要求他們將CL分成多個(gè)CL。
? ?如果你發(fā)現(xiàn)CL的這一部分存在一些主要的設(shè)計(jì)問(wèn)題,則即使你現(xiàn)在沒(méi)有時(shí)間評(píng)審CL的其余部分,也應(yīng)立即發(fā)送這些評(píng)論。實(shí)際上,評(píng)審CL的其余部分可能會(huì)浪費(fèi)時(shí)間,因?yàn)槿绻O(shè)計(jì)問(wèn)題比較嚴(yán)重,那么正在評(píng)審的許多其他代碼都將消失并且無(wú)論如何都不會(huì)變得很重要。
? ?立即發(fā)出這些主要的設(shè)計(jì)評(píng)論有兩個(gè)主要原因:
- 開(kāi)發(fā)人員通常會(huì)在發(fā)出一個(gè)CL之后立即基于該CL進(jìn)行新工作。如果你正在評(píng)審的CL中存在重大設(shè)計(jì)問(wèn)題,那么他們也將不得不重新設(shè)計(jì)其以后的CL。在他們?cè)谟袉?wèn)題的設(shè)計(jì)之上進(jìn)行過(guò)多額外工作之前,你就需要告訴他們。
- 重大的設(shè)計(jì)變更比小的變更需要更長(zhǎng)的時(shí)間。開(kāi)發(fā)者幾乎都有截止日期;為了保證在截止日期之前完成工作,并在代碼庫(kù)中保留高質(zhì)量的代碼,開(kāi)發(fā)者需要盡快開(kāi)始CL的所有重大重做。
2.4.4 第三步:以適當(dāng)?shù)捻樞驗(yàn)g覽其余的CL
? ?一旦你確認(rèn)CL再整體上沒(méi)有大的設(shè)計(jì)問(wèn)題之后,請(qǐng)嘗試找出邏輯順序來(lái)瀏覽文件,同時(shí)還要確保不要錯(cuò)過(guò)對(duì)任何文件的評(píng)審。通常,在瀏覽了主要文件之后,按照代碼評(píng)審工具向你展示的順序?yàn)g覽每個(gè)文件是最簡(jiǎn)單的。有時(shí)在閱讀主要代碼之前先閱讀測(cè)試代碼也是有幫助的,因?yàn)檫@樣你就可以知道這些更改的意圖是什么了。
2.5 代碼評(píng)審的速度
2.5.1 為什么代碼評(píng)審要快速完成?
? ?在Google,我們優(yōu)化了開(kāi)發(fā)團(tuán)隊(duì)可以一起生產(chǎn)產(chǎn)品的速度,而不是優(yōu)化了單個(gè)開(kāi)發(fā)人員可以編寫(xiě)代碼的速度。個(gè)人發(fā)展的速度固然很重要,但并沒(méi)有整個(gè)團(tuán)隊(duì)的速度更重要。
? ?當(dāng)代碼評(píng)審緩慢時(shí),會(huì)發(fā)生幾件事:
-
整個(gè)團(tuán)隊(duì)的速度下降。對(duì)評(píng)審沒(méi)有快速回應(yīng)的個(gè)人來(lái)說(shuō),他可以完成其他工作。但由于每個(gè)CL都在等待評(píng)審,因此團(tuán)隊(duì)其余成員的新功能和bug修復(fù)會(huì)被延遲幾天、幾周或幾個(gè)月。 -
開(kāi)發(fā)人員開(kāi)始抗議代碼評(píng)審過(guò)程。如果評(píng)審者僅每隔幾天回答一次,但每次都要求對(duì)CL進(jìn)行重大更改,那么這對(duì)于開(kāi)發(fā)者來(lái)說(shuō)可能會(huì)令人沮喪且困難。 通常情況下,這表現(xiàn)為對(duì)評(píng)審者的過(guò)于“嚴(yán)格”的抱怨。如果評(píng)審者要求進(jìn)行實(shí)質(zhì)性的更改(確實(shí)可以改善代碼運(yùn)行狀況的更改),且每次開(kāi)發(fā)者進(jìn)行更新時(shí)都做出快速響應(yīng),則抱怨往往會(huì)消失。實(shí)際上,大多數(shù)對(duì)代碼評(píng)審過(guò)程的抱怨都可以通過(guò)加快速度來(lái)解決。 -
代碼的健康狀況可能會(huì)受到影響。當(dāng)審查變慢時(shí),允許開(kāi)發(fā)者提交不盡可能好的CLs的壓力就增大了。緩慢的審核也會(huì)阻止代碼清理、重構(gòu)和對(duì)現(xiàn)有CL的進(jìn)行進(jìn)一步改進(jìn)。
2.5.2 怎樣快速的進(jìn)行代碼評(píng)審呢?
? ?如果你沒(méi)有在做一件需要集中精神的任務(wù),你應(yīng)該在CL出現(xiàn)后不久后就做一下代碼評(píng)審。
? ?一個(gè)工作日是響應(yīng)代碼評(píng)審請(qǐng)求所需的最長(zhǎng)時(shí)間(即第二天早上的第一件事)。
? ?遵循這些準(zhǔn)則意味著一個(gè)典型的CL應(yīng)在一天之內(nèi)進(jìn)行多輪評(píng)審(如果需要)。
2.5.3 速度 vs 中斷
? ?有時(shí)個(gè)人的速度比團(tuán)隊(duì)的速度更為重要。如果你正在集中精神做某件任務(wù),比如編寫(xiě)代碼,請(qǐng)不要打斷自己去做代碼評(píng)審。 研究表明,開(kāi)發(fā)人員在中斷之后要花很長(zhǎng)時(shí)間才能恢復(fù)到平穩(wěn)的開(kāi)發(fā)流程。 因此,在編寫(xiě)代碼時(shí)打斷自己實(shí)際上對(duì)團(tuán)隊(duì)來(lái)說(shuō)要比讓其他開(kāi)發(fā)者稍等一會(huì)兒的代價(jià)更為昂貴。
? ?相反,在你的工作中等待一個(gè)斷點(diǎn),然后再響應(yīng)一個(gè)評(píng)審請(qǐng)求。這可能是當(dāng)你當(dāng)前的編碼任務(wù)完成后、午飯后、從會(huì)議返回、從微廚房返回等等。
2.5.4 快速響應(yīng)
? ?當(dāng)我們談?wù)摯a評(píng)審的速度時(shí),它指的是我們的響應(yīng)時(shí)間,而不是CL通過(guò)整個(gè)評(píng)審并提交所花的時(shí)間。整個(gè)過(guò)程在理想情況下也應(yīng)該是快速的,但是個(gè)人的響應(yīng)要比整個(gè)過(guò)程迅速完成更為重要。
? ?盡管有時(shí)需要很長(zhǎng)時(shí)間才能完成整個(gè)評(píng)審過(guò)程,但在整個(gè)評(píng)審過(guò)程中獲得評(píng)審者的快速響應(yīng)也可以極大地減輕開(kāi)發(fā)人員對(duì)“緩慢”代碼評(píng)審的沮喪感。
? ?如果你太忙,無(wú)法在CL進(jìn)入時(shí)對(duì)其進(jìn)行完整的評(píng)審,你仍然可以發(fā)送一個(gè)快速的響應(yīng),讓開(kāi)發(fā)人員知道你何時(shí)可以訪問(wèn)它,或建議其他可能能夠更快地響應(yīng)的評(píng)審者來(lái)評(píng)審,或者提供一些初步的寬泛的評(píng)論。(注意:這些都不意味著你應(yīng)該中斷編碼來(lái)發(fā)送這樣的響應(yīng),而是在工作的合理斷點(diǎn)時(shí)發(fā)送響應(yīng)。)
? ?重要的是,評(píng)審者應(yīng)花足夠的時(shí)間進(jìn)行評(píng)審,以確保其“ LGTM”表示“此代碼符合我們的標(biāo)準(zhǔn)”。 但理想情況下,個(gè)人響應(yīng)仍然應(yīng)該很快。
2.5.5 跨時(shí)區(qū)的評(píng)審
? ?在處理時(shí)區(qū)差異時(shí),盡量在作者還在辦公室時(shí)聯(lián)系他。如果他們已經(jīng)回家了,那么在他們第二天回到辦公室之前,試著確保你的評(píng)審已經(jīng)完成。
2.5.6 帶評(píng)論的LGTM
? ?為了加快代碼評(píng)審的速度,在某些情況下,評(píng)審者應(yīng)給予LGTM/批準(zhǔn),即使他們也在CL上留下未解決的評(píng)論。這是在以下情況下才會(huì)出現(xiàn)的:
- 評(píng)審者確信開(kāi)發(fā)者將適當(dāng)?shù)靥幚碓u(píng)審者留下的所有評(píng)論。
- 所作的更改很小,開(kāi)發(fā)者不必做。
? ?除非另有明確說(shuō)明,否則評(píng)審者應(yīng)指定他們打算使用這些選項(xiàng)中的哪一個(gè)。
? ?當(dāng)開(kāi)發(fā)者和評(píng)審者位于不同時(shí)區(qū)時(shí),帶有注釋的LGTM特別值得考慮,否則開(kāi)發(fā)者將等待一整天才獲得“ LGTM,批準(zhǔn)”。
2.5.7 巨大的CLs
? ?如果有人向你發(fā)送了一個(gè)巨大的代碼評(píng)審,你不確定何時(shí)可以有時(shí)間對(duì)其進(jìn)行評(píng)審,通常的響應(yīng)應(yīng)該是要求開(kāi)發(fā)人員將CL拆分為多個(gè)較小的CL。而不必一次評(píng)審所有巨大的CL。這通常是可能的,并且對(duì)審閱者很有幫助,即使需要開(kāi)發(fā)人員進(jìn)行一些額外工作。
? ?如果不能將一個(gè)CL分解為較小的CL,并且你沒(méi)有時(shí)間快速評(píng)審整個(gè)CL,那么至少要對(duì)CL的總體設(shè)計(jì)寫(xiě)一些評(píng)論,然后將其發(fā)給開(kāi)發(fā)者進(jìn)行改進(jìn)。 作為評(píng)審者,你的目標(biāo)之一應(yīng)該是始終消除開(kāi)發(fā)人員的障礙,或在不犧牲代碼的運(yùn)行狀況的情況下,使他們能夠迅速采取某種進(jìn)一步的措施。
2.5.8 隨著時(shí)間的推移,代碼評(píng)審的改進(jìn)
? ?如果你遵循這些準(zhǔn)則,并且嚴(yán)格執(zhí)行代碼評(píng)審規(guī)范,則應(yīng)該發(fā)現(xiàn)整個(gè)代碼評(píng)審過(guò)程會(huì)隨著時(shí)間的流逝而越來(lái)越快。 開(kāi)發(fā)人員將了解健康代碼的要求,并從一開(kāi)始就向你發(fā)送出色的CL,所需的評(píng)審時(shí)間越來(lái)越少。評(píng)審者學(xué)會(huì)快速做出響應(yīng),并且不會(huì)在評(píng)審過(guò)程中增加不必要的延遲。但是,不要為了提高速度而在代碼評(píng)審標(biāo)準(zhǔn)或質(zhì)量上做出讓步——從長(zhǎng)遠(yuǎn)來(lái)看,這實(shí)際上不會(huì)使任何事情更快地發(fā)生。
2.5.9 緊急情況
? ?在某些緊急情況下,CL必須非??焖俚赝ㄟ^(guò)整個(gè)審核過(guò)程,并且質(zhì)量準(zhǔn)則將得到放寬。但是,請(qǐng)參閱什么是緊急情況? 描述哪些情況實(shí)際上可以視為緊急情況,哪些不可以。
2.6 如何編寫(xiě)代碼評(píng)審評(píng)論
2.6.1 摘要
- 友善
- 說(shuō)明你的理由
- 在給出明確的指導(dǎo)與指出問(wèn)題、并讓開(kāi)發(fā)人員決定之間保持平衡。
- 鼓勵(lì)開(kāi)發(fā)人員簡(jiǎn)化代碼或添加代碼注釋,而不是僅僅向你解釋其復(fù)雜性。
2.6.2 禮貌
??通常,有禮貌和尊重是重要的,同時(shí)也要對(duì)正在查看其代碼的開(kāi)發(fā)者非常有幫助。 一種方法是確保始終對(duì)代碼進(jìn)行評(píng)論,而不對(duì)開(kāi)發(fā)者進(jìn)行評(píng)論。不必總是遵循這種做法,但是在說(shuō)出可能令人不快或有爭(zhēng)議的內(nèi)容時(shí),一定要使用它。 例如:
??壞:“當(dāng)顯然不能從并發(fā)中獲得好處時(shí),為什么在這里使用線程?”
??好:“并發(fā)模型在這里增加了系統(tǒng)的復(fù)雜性,而我沒(méi)有看到任何實(shí)際的性能優(yōu)勢(shì)。因?yàn)闆](méi)有性能優(yōu)勢(shì),所以最好使該代碼為單線程而不是使用多個(gè)線程?!?/p>
2.6.3 解釋為什么
??關(guān)于上面的“好”示例,你會(huì)注意到一件事,那就是它幫助開(kāi)發(fā)人員理解你發(fā)表評(píng)論的原因是什么。你并不總是需要在評(píng)論中包含這些信息,但有時(shí)需要對(duì)你的意圖、遵循的最佳實(shí)踐或如何改善代碼的運(yùn)行狀況的建議給出更多的解釋。
2.6.4 提供指導(dǎo)
??一般來(lái)說(shuō),修復(fù)CL是開(kāi)發(fā)人員的責(zé)任,而不是評(píng)審人員的責(zé)任。你不需要為開(kāi)發(fā)人員進(jìn)行解決方案的詳細(xì)設(shè)計(jì)或編寫(xiě)代碼。
??但是,這并不意味著審閱者是沒(méi)有幫助的。通常,你應(yīng)該在指出問(wèn)題和提供直接指導(dǎo)之間取得適當(dāng)?shù)钠胶狻V赋鰡?wèn)題并讓開(kāi)發(fā)人員做出決定通??梢詭椭_(kāi)發(fā)人員學(xué)習(xí),并使代碼評(píng)審更容易。這也可以帶來(lái)更好的解決方案,因?yàn)殚_(kāi)發(fā)者比審閱者更接近代碼。
??然而,有時(shí)直接的指導(dǎo)、建議,甚至代碼更有用。代碼評(píng)審的主要目標(biāo)是獲得盡可能好的CL。第二個(gè)目標(biāo)是提高開(kāi)發(fā)人員的技能,以便他們需要越來(lái)越少的評(píng)審時(shí)間。
2.6.5 接受說(shuō)明
??如果你讓開(kāi)發(fā)人員解釋一段你不理解的代碼,通常會(huì)導(dǎo)致他們更清楚地重寫(xiě)代碼。偶爾,在代碼中添加注釋也是一種適當(dāng)?shù)捻憫?yīng),只要它只是僅僅解釋過(guò)于復(fù)雜的代碼。
??僅在代碼檢查工具中編寫(xiě)的說(shuō)明對(duì)將來(lái)的代碼閱讀者沒(méi)有幫助。它們僅在某些情況下是可以接受的,例如,當(dāng)你查看不十分熟悉的領(lǐng)域并且開(kāi)發(fā)者解釋了普通代碼讀者已經(jīng)知道的內(nèi)容時(shí)。
2.7 在代碼評(píng)審中處理回退
有時(shí),開(kāi)發(fā)人員會(huì)退回進(jìn)行代碼評(píng)審。他們要么是因?yàn)閷?duì)你的建議不同意,要么是因?yàn)楸г鼓憧傮w上過(guò)于嚴(yán)格。
2.7.1 到底誰(shuí)是對(duì)的?
??當(dāng)開(kāi)發(fā)人員不同意你的建議時(shí),請(qǐng)先花點(diǎn)時(shí)間考慮一下它們是否正確。通常,它們比你更接近代碼,因此他們實(shí)際上可能對(duì)代碼的某些方面有更好的了解。他們的論點(diǎn)有意義嗎?從代碼健康角度來(lái)看,這有意義嗎?如果是這樣,請(qǐng)讓他們知道他們是對(duì)的,然后讓問(wèn)題解決。
??但是,開(kāi)發(fā)者并不總是對(duì)的。在這種情況下,評(píng)審人應(yīng)進(jìn)一步解釋為什么他們認(rèn)為自己的建議是正確的。良好的解釋不僅說(shuō)明了對(duì)開(kāi)發(fā)人員回復(fù)的理解,而且還說(shuō)明了有關(guān)為何要求進(jìn)行更改的其他信息。
??特別是,當(dāng)評(píng)審者認(rèn)為他們的建議將改善代碼的健康狀況時(shí),如果他們認(rèn)為由此產(chǎn)生的代碼質(zhì)量改進(jìn)證明所要求的額外工作是合理的,那么他們應(yīng)該繼續(xù)提倡進(jìn)行更改。改善代碼的健康狀況往往只需要一小步。
??有時(shí)候,在一個(gè)建議真正被采納之前,它需要幾輪的解釋。只要確保始終保持禮貌,讓開(kāi)發(fā)人員知道你聽(tīng)到了他們?cè)谡f(shuō)什么,只是你不同意而已。
2.7.2 令人煩惱的開(kāi)發(fā)者
??評(píng)審人有時(shí)認(rèn)為,如果評(píng)審人堅(jiān)持要改進(jìn),開(kāi)發(fā)者會(huì)感到沮喪。有時(shí),開(kāi)發(fā)人員確實(shí)會(huì)感到不高興,但這通常是短暫的,之后他們會(huì)非常感謝你幫助他們提高了代碼質(zhì)量。通常,如果你的評(píng)論彬彬有禮,那么開(kāi)發(fā)人員實(shí)際上根本不會(huì)感到煩惱,而這些擔(dān)心只會(huì)出現(xiàn)在評(píng)審者的腦海中而已。煩惱通常與評(píng)論的編寫(xiě)方式有關(guān),而不是與評(píng)審人對(duì)代碼質(zhì)量的堅(jiān)持有關(guān)。
2.7.3 稍后再清理
??回退的一個(gè)常見(jiàn)原因是開(kāi)發(fā)人員(可以理解)想要完成任務(wù)。他們不想僅僅為了通過(guò)此CL而進(jìn)行另一輪審核。因此,他們說(shuō)他們將在以后的CL中清理某些內(nèi)容,因此你現(xiàn)在應(yīng)該LGTM此CL。一些開(kāi)發(fā)人員對(duì)此非常友好,并會(huì)立即編寫(xiě)后續(xù)的CL來(lái)解決此問(wèn)題。然而,經(jīng)驗(yàn)表明,隨著開(kāi)發(fā)人員編寫(xiě)原始CL之后時(shí)間的推移,這種清理發(fā)生的可能性越小。實(shí)際上,通常除非開(kāi)發(fā)人員在當(dāng)前CL之后立即進(jìn)行清理,否則它永遠(yuǎn)不會(huì)發(fā)生。這不是因?yàn)殚_(kāi)發(fā)人員不負(fù)責(zé)任,而是因?yàn)樗麄冇泻芏喙ぷ饕?,并且清理工作在其他工作中丟失或被遺忘。因此,通常最好是堅(jiān)持要求開(kāi)發(fā)人員在代碼進(jìn)入代碼庫(kù)并“完成”之前立即清理其CL。讓人們“以后再清理”是代碼庫(kù)退化的一種常見(jiàn)方法。
??如果CL引入新的復(fù)雜性,它必須在提交之前進(jìn)行清理,除非是緊急情況。如果CL暴露了相關(guān)的問(wèn)題,而這些問(wèn)題現(xiàn)在無(wú)法解決,那么開(kāi)發(fā)人員應(yīng)該提交一個(gè)清理錯(cuò)誤并將其分配給自己,這樣它就不會(huì)丟失。他們還可以選擇在代碼中編寫(xiě)一個(gè)TODO注釋來(lái)引用已歸檔的bug。
2.7.4 對(duì)嚴(yán)格評(píng)審的抱怨
??如果你以前對(duì)代碼的評(píng)審松懈,而轉(zhuǎn)而對(duì)代碼進(jìn)行嚴(yán)格的評(píng)審,那么一些開(kāi)發(fā)人員將大聲抱怨。提高代碼評(píng)審的速度通常會(huì)使這些抱怨消失。
??有時(shí),這些抱怨可能要花費(fèi)數(shù)月的時(shí)間才能消失,但是最終,開(kāi)發(fā)人員往往會(huì)看到嚴(yán)格代碼評(píng)審的價(jià)值,因?yàn)樗麄儠?huì)看到自己寫(xiě)出的出色代碼。有時(shí),最大聲的抗議者甚至?xí)蔀槟阕钣辛Φ闹С终?,一旦有什么事情發(fā)生,使他們真正看到你通過(guò)嚴(yán)格要求所增加的價(jià)值。
2.7.5 解決沖突
??如果你遵循上述所有內(nèi)容,但是仍然遇到無(wú)法解決的開(kāi)發(fā)人員之間的沖突,請(qǐng)參閱"代碼評(píng)審標(biāo)準(zhǔn)"以獲取有助于解決沖突的準(zhǔn)則和原則。
3 CL開(kāi)發(fā)者指南
3.1 編寫(xiě)良好的CL描述
??CL描述是一個(gè)公開(kāi)的記錄,它記錄了正在進(jìn)行的更改以及更改的原因。它將成為版本控制歷史中永久的一部分,并且可能會(huì)被數(shù)百人閱讀,而不是僅僅是你的評(píng)審者。
??未來(lái)的開(kāi)發(fā)者將會(huì)根據(jù)你的CL的描述來(lái)搜索它。將來(lái)可能有人會(huì)因?yàn)橹挥邢嚓P(guān)的模糊的記憶,卻沒(méi)有具體的細(xì)節(jié)而查找你的CL。如果所有的重要信息都在代碼中而不是描述中,那么他們很難找到你的CL。
3.1.1 第一行
- 對(duì)正在做的事情做一個(gè)簡(jiǎn)短的總結(jié)。
- 完整的句子,命令式的寫(xiě)法
- 緊接著的空行
??CL描述的第一行應(yīng)該是對(duì)CL正在做的具體工作的簡(jiǎn)短總結(jié),后面跟一個(gè)空行。這是大多數(shù)未來(lái)的代碼搜索者在瀏覽一段代碼的版本控制歷史時(shí)會(huì)看到的,因此第一行應(yīng)該有豐富的信息量,他們不必閱讀你的CL或它的整個(gè)描述就可以大致了解你的CL實(shí)際做了什么。
??按照傳統(tǒng),CL描述的第一行是一個(gè)完整的句子,寫(xiě)成好像是一個(gè)命令(命令式句子)。例如,說(shuō)"Delete the FizzBuzz RPC and replace it with the new system.",而不是"Deleting the FizzBuzz RPC and replacing it with the new system."。另外,你不必將其余說(shuō)明寫(xiě)成命令式語(yǔ)句。
3.1.2 正文內(nèi)容要豐富
??其余的描述應(yīng)該是翔實(shí)的。它可能包括對(duì)正在解決的問(wèn)題的簡(jiǎn)短描述,以及為什么這是最好的方法。如果這個(gè)方法有任何缺點(diǎn),應(yīng)該提出來(lái)。如果相關(guān),請(qǐng)包括背景信息,如錯(cuò)誤號(hào)、基準(zhǔn)測(cè)試結(jié)果和設(shè)計(jì)文檔的鏈接。
??即使是很小的CLs也需要注意其中的一些實(shí)現(xiàn)細(xì)節(jié)。
3.1.3 糟糕的CL描述
??“Fix bug”是對(duì)CL的不足描述。什么bug?為了修復(fù)這個(gè)bug,你做了什么?其他類似的錯(cuò)誤描述包括:
- "Fix build."
- "Add patch."
- "Moving code from A to B."
- "Phase 1."
- "Add convenience functions."
- "kill weird URLs."
上面這些CL描述在現(xiàn)實(shí)場(chǎng)景中是真實(shí)存在的。這些開(kāi)發(fā)者可能認(rèn)為他們正在提供有用的信息,但它們并沒(méi)有達(dá)到CL描述的目的。
3.1.4 良好的CL描述
以下是一些很好的CL描述示例。
3.1.4.1 功能變更
例如:
rpc: remove size limit on RPC server message freelist.
Servers like FizzBuzz have very large messages and would benefit from reuse. Make the freelist larger, and add a goroutine that frees the freelist entries slowly over time, so that idle servers eventually release all freelist entries.
第一行描述了CL的實(shí)際作用。描述的其余部分討論了要解決的問(wèn)題、為什么這是一個(gè)好的解決方案,以及有關(guān)實(shí)現(xiàn)的更多信息。
3.1.4.2 重構(gòu)
例如:
Construct a Task with a TimeKeeper to use its TimeStr and Now methods.
Add a Now method to Task, so the borglet() getter method can be removed (which was only used by OOMCandidate to call borglet's Now method). This replaces the methods on Borglet that delegate to a TimeKeeper.
Allowing Tasks to supply Now is a step toward eliminating the dependency on Borglet. Eventually, collaborators that depend on getting Now from the Task should be changed to use a TimeKeeper directly, but this has been an accommodation to refactoring in small steps.
Continuing the long-range goal of refactoring the Borglet Hierarchy.
第一行描述了CL的作用,以及它與過(guò)去的變化。描述的其余部分討論了具體的實(shí)現(xiàn)、CL的上下文、解決方案并不理想以及未來(lái)可能的方向。同時(shí)也解釋了為什么會(huì)做這種修改。
3.1.4.3 需要某些上下文的小型CL
例如:
Create a Python3 build rule for status.py.
This allows consumers who are already using this as in Python3 to depend on a rule that is next to the original status build rule instead of somewhere in their own tree. It encourages new consumers to use Python3 if they can, instead of Python2, and significantly simplifies some automated build file refactoring tools being worked on currently.
第一句話描述了實(shí)際正在做的事情。描述的其余部分解釋了為什么要進(jìn)行更改,并為評(píng)審者提供了大量的上下文。
3.1.5 提交CL之前請(qǐng)先檢查描述
CLs在評(píng)審期間可能發(fā)生重大變化。在提交CL之前,有必要檢查一下CL的描述,以確保該描述仍然反映CL的功能。
3.2 小型的CLs
3.2.1 為什么要編寫(xiě)小型CL?
??小型,簡(jiǎn)單CL的意義是:
-
評(píng)審的更快。比起留出30分鐘的時(shí)間來(lái)評(píng)審一個(gè)大的CLs,評(píng)審者更容易找到5分鐘的空閑來(lái)評(píng)審小的CLs。 -
評(píng)審的更加徹底。進(jìn)行較大的更改后,評(píng)審者和作者往往會(huì)因大量來(lái)來(lái)回回的回復(fù)而感到沮喪,有時(shí)某些重要的評(píng)論還會(huì)被遺漏掉。 -
引入bug的可能性更小。由于你所做的更改較少,因此你和你的評(píng)審者更容易有效地推斷出CL的影響,并查看是否會(huì)引入某些bug。 -
如果被拒絕,浪費(fèi)的工作也會(huì)更少。如果你編寫(xiě)了一個(gè)巨大的CL,然后你的審閱者說(shuō)總體方向是錯(cuò)誤的,那么你就浪費(fèi)了很多工作。 -
更容易合并。在大型CL上工作需要很長(zhǎng)時(shí)間,因此合并時(shí)你將會(huì)遇到很多的沖突,你不得不進(jìn)行頻繁合并。 -
更易于設(shè)計(jì)。完善小變更的設(shè)計(jì)和代碼運(yùn)行狀況要比完善大變更的所有細(xì)節(jié)容易得多。 -
更不容易卡在評(píng)審上發(fā)送整體更改中的一部分可以讓你在等待當(dāng)前CL審核時(shí)繼續(xù)進(jìn)行編碼。 更易于回滾。
??請(qǐng)注意,審閱者有權(quán)直接拒絕你的CL,唯一的原因是更改太大。通常他們會(huì)感謝你的貢獻(xiàn),但要求你以某種方式把它變成一系列較小的變化。在你已經(jīng)寫(xiě)了一個(gè)變更之后,分割它可能需要很多工作,或者你需要花很多時(shí)間來(lái)和評(píng)審人來(lái)爭(zhēng)論為什么應(yīng)該接受你的大變更。所以,一開(kāi)始就寫(xiě)一些小的CLs是比較容易的。
3.2.2 為什么要提交小型的CL?
??通常,一個(gè)CL的正確大小應(yīng)該是一項(xiàng)獨(dú)立的更改。這意味著:
- CL進(jìn)行的最小更改只解決一個(gè)問(wèn)題。這通常只是一個(gè)功能的一部分,而不是一個(gè)完整的功能。一般來(lái)說(shuō),編寫(xiě)太小的CLs比編寫(xiě)太大的CLs更好。與你的評(píng)審人一起找出一個(gè)可接受的大小。
- 評(píng)審人需要了解的關(guān)于CL的一切(除了未來(lái)的功能)都在CL、CL的描述、現(xiàn)有的代碼庫(kù)、或他們已經(jīng)評(píng)審的CL中。
- CL被合并之后,系統(tǒng)將繼續(xù)為其用戶和開(kāi)發(fā)人員良好運(yùn)行。
- CL不能太小以至于難以理解。如果你添加了一個(gè)新的API,則應(yīng)在同一CL中包括該API的用法,以便評(píng)審人可以更好地了解該API的使用方式。這也可以防止檢入未使用的API。
??對(duì)于“太大”,沒(méi)有硬性規(guī)定。對(duì)于CL而言,100行通常是一個(gè)合理的大小,而1000行通常太大,但這取決于你的評(píng)審者的判斷。一個(gè)更改所覆蓋的文件數(shù)也會(huì)影響它的“大小”。一個(gè)文件中200行的更改可能是可以的,但是覆蓋50個(gè)文件通常會(huì)太大。
??請(qǐng)記住,盡管從你開(kāi)始編寫(xiě)代碼的那一刻起,你就與代碼密切相關(guān),但是評(píng)審人通常沒(méi)有上下文。對(duì)你來(lái)說(shuō),一個(gè)大小尚可接受的CL可能會(huì)讓你的評(píng)審人難以承受。如果有疑問(wèn),可以編寫(xiě)比你認(rèn)為需要編寫(xiě)的更小的CLs。評(píng)審人很少會(huì)因CLs太小而抱怨。
3.2.3 什么時(shí)候提交大型CL也是可以的?
在某些情況下,較大的更改沒(méi)有那么糟糕:
- 通常,你可以將整個(gè)文件的刪除視為一行的更改,因?yàn)樗粫?huì)花費(fèi)很長(zhǎng)時(shí)間來(lái)評(píng)審。
- 有時(shí)候,一個(gè)你完全信任的自動(dòng)重構(gòu)工具會(huì)生成一個(gè)很大的CL,評(píng)審者的工作就是檢查并確認(rèn)他們確實(shí)需要更改。這些CLs可以更大,盡管有上面的一些警告(如合并和測(cè)試)但它仍然適用。
3.2.3.1 按文件拆分
??另一種分割CL的方法是對(duì)文件進(jìn)行分組,這些文件需要不同的評(píng)審人員評(píng)審,而且又是獨(dú)立的更改。
??例如:你發(fā)送一個(gè)CL來(lái)修改協(xié)議緩沖區(qū),而發(fā)送另一個(gè)CL來(lái)更改使用該協(xié)議的代碼。你必須在協(xié)議的CL之前提交修改的CL,但它們可以同時(shí)被評(píng)審。如果執(zhí)行此操作,則可能要告知兩組評(píng)審者有關(guān)你編寫(xiě)的另一個(gè)CL的信息,以便他們擁有進(jìn)行更改的上下文。
??另一個(gè)示例:你發(fā)送一個(gè)CL進(jìn)行代碼更改,而另一個(gè)CL則發(fā)送使用該代碼的配置或?qū)嶒?yàn);如果需要,這也更容易回滾,因?yàn)橛袝r(shí)將配置/實(shí)驗(yàn)文件推送到生產(chǎn)環(huán)境中比更改代碼更快。
3.2.4 單獨(dú)的重構(gòu)
??通常,最好在一個(gè)獨(dú)立的CL中進(jìn)行重構(gòu),而不是進(jìn)行特性更改或bug修復(fù)。例如,移動(dòng)和重命名一個(gè)類應(yīng)該與修復(fù)該類中的錯(cuò)誤屬于不同的CL。當(dāng)每個(gè)CL獨(dú)立時(shí),評(píng)審員更容易理解它們所引入的更改。
??不過(guò),可以在特性更改或bug修復(fù)CL中包含修復(fù)局部變量名之類的小清理。由開(kāi)發(fā)人員和評(píng)審者來(lái)決定怎么樣的重構(gòu)算是龐大的,以至于大到如果被包含在當(dāng)前的CL中,評(píng)審將變得更加困難。
3.2.5 將相關(guān)的測(cè)試代碼保存在同一CL中
??避免將測(cè)試代碼拆分為單獨(dú)的CL。即使這樣做會(huì)增加代碼行數(shù),驗(yàn)證代碼修改的測(cè)試也應(yīng)該進(jìn)入相同的CL。
??然而,類似于重構(gòu)準(zhǔn)則,可以將獨(dú)立的測(cè)試修改放入單獨(dú)的CL中。包括:
- 使用新測(cè)試驗(yàn)證先前存在的提交代碼。
- 重構(gòu)測(cè)試代碼(例如,引入輔助函數(shù))。
- 引入更大的測(cè)試框架代碼(例如集成測(cè)試)。
3.2.6 不要破壞構(gòu)建
??如果你有幾個(gè)相互依賴的CLs,那么你需要找到一種方法來(lái)確保在提交每個(gè)CL之后整個(gè)系統(tǒng)都能繼續(xù)工作。否則,你可能會(huì)在CL提交之間將所有其他開(kāi)發(fā)人員的構(gòu)建中斷幾分鐘(如果在以后的CL提交中出現(xiàn)意外的問(wèn)題,則可能需要更長(zhǎng)的時(shí)間)。
3.2.7 無(wú)法將CL拆分成小的?
??有時(shí)你會(huì)遇到一些情況,似乎你的CL必須很大,但這往往都是假象。練習(xí)編寫(xiě)小型CLs的開(kāi)發(fā)者幾乎總能找到將功能分解為一系列小更改的方法。
??在編寫(xiě)大型CL之前,請(qǐng)考慮在這之前加上只進(jìn)行重構(gòu)的CL是否可以為以后簡(jiǎn)潔的實(shí)現(xiàn)做好鋪墊。與你的隊(duì)友交談,看看是否有人對(duì)如何在小型CLs中實(shí)現(xiàn)該功能有想法。
??如果所有這些選項(xiàng)都失敗了(這應(yīng)該是極為罕見(jiàn)的),那么請(qǐng)事先獲得評(píng)審人員的同意來(lái)評(píng)審一個(gè)大型的CL,這樣他們就會(huì)被預(yù)先提醒接下來(lái)會(huì)發(fā)生什么。在這種情況下,估計(jì)要經(jīng)歷很長(zhǎng)時(shí)間的評(píng)審過(guò)程,注意不要引入bug,并在編寫(xiě)測(cè)試時(shí)格外小心謹(jǐn)慎。
3.3 如何處理評(píng)審者的評(píng)論?
??當(dāng)你將CL發(fā)送出去進(jìn)行審核時(shí),你的評(píng)審人很可能會(huì)對(duì)你的CL做出一些評(píng)論。這里是有關(guān)如何處理審閱者評(píng)論的一些有用信息。
3.3.1 不要往心里去
??評(píng)審的目的是保證我們代碼庫(kù)和產(chǎn)品的質(zhì)量。當(dāng)評(píng)審者對(duì)你的代碼提出批評(píng)時(shí),請(qǐng)嘗試將其視對(duì)你、代碼庫(kù)、Google的幫助,而不是對(duì)你或你的能力的人身攻擊。
??有時(shí),評(píng)審人會(huì)感到抓狂,并在評(píng)論中表達(dá)這種抓狂。對(duì)于評(píng)審者來(lái)說(shuō),這不是一個(gè)好習(xí)慣,但是作為開(kāi)發(fā)者,你應(yīng)該為此做好準(zhǔn)備。問(wèn)問(wèn)自己,“評(píng)審人試圖與我交流的建設(shè)性內(nèi)容是什么?”然后像他們實(shí)際所說(shuō)的那樣操作。
??切勿對(duì)代碼評(píng)審的評(píng)論以憤怒的方式回復(fù)。這是對(duì)職業(yè)禮節(jié)的嚴(yán)重違反,它將永遠(yuǎn)存在于代碼評(píng)審工具中。如果你因太生氣或煩惱而無(wú)法友好地回答,請(qǐng)離開(kāi)計(jì)算機(jī)一段時(shí)間,或進(jìn)行其他操作,直到你感到足夠鎮(zhèn)靜可以禮貌地回答為止。
??通常,如果評(píng)審人沒(méi)有以建設(shè)性和禮貌的方式提供反饋,請(qǐng)親自向他們解釋。如果你無(wú)法當(dāng)面或視頻通話與他們交談,請(qǐng)向他們發(fā)送私人電子郵件。用一種友好的方式向他們解釋你不喜歡的事情以及你希望他們做些什么。如果他們也以非建設(shè)性的方式對(duì)此私密討論做出回應(yīng),或者沒(méi)有起到預(yù)期的作用,請(qǐng)酌情上報(bào)給你的經(jīng)理。
3.3.2 修正代碼
??如果評(píng)審者說(shuō)他們不理解代碼中的某些內(nèi)容,你的第一個(gè)反應(yīng)應(yīng)該是通過(guò)代碼本身來(lái)解釋。如果代碼不能自我解釋,請(qǐng)為代碼添加注釋,解釋代碼存在的原因。只有當(dāng)評(píng)論看起來(lái)毫無(wú)意義時(shí),你才可以在代碼評(píng)審工具中給予回復(fù)。
??如果評(píng)審者不理解你的某些代碼,則其他將來(lái)的代碼讀者也可能不理解。在代碼檢查工具中編寫(xiě)解釋不會(huì)對(duì)將來(lái)的代碼閱讀者有所幫助,但是闡明你的代碼或添加代碼注釋卻會(huì)對(duì)他們有所幫助。
3.3.3 為自己考慮
??編寫(xiě)CL需要大量的工作。通常情況下,你會(huì)很滿足于自己終于發(fā)出了一份CL,覺(jué)得自己已經(jīng)完成了任務(wù),并且確信不需要再做其他工作了。因此,當(dāng)評(píng)審人對(duì)一些可以改進(jìn)的地方進(jìn)行了評(píng)論時(shí),很容易讓人本能地認(rèn)為這些評(píng)論是錯(cuò)誤的、評(píng)審者正在不必要地阻礙你、或者他們應(yīng)該讓你提交CL。然而,不管你現(xiàn)在有多確定,花點(diǎn)時(shí)間回顧一下,考慮一下評(píng)審人是否提供了有價(jià)值的反饋,這將有助于代碼庫(kù)和谷歌。你對(duì)自己的第一個(gè)問(wèn)題應(yīng)該是,“評(píng)審人是正確的嗎?”
??如果你無(wú)法回答該問(wèn)題,則評(píng)審者可能需要解釋他們的評(píng)論。
??如果你已經(jīng)考慮過(guò)了,但仍然認(rèn)為你是對(duì)的,那么你可以解釋一下為什么你的做事方法對(duì)代碼庫(kù)、用戶或谷歌更好。通常,評(píng)論者實(shí)際上是在提供建議,他們希望你自己思考什么是最好的。實(shí)際上,你可能知道一些評(píng)審者并不知道的內(nèi)容,比如有關(guān)用戶的、代碼庫(kù)的或CL的。所以把更多有關(guān)上下文的信息也寫(xiě)進(jìn)去吧。通常,你和評(píng)審者可以基于一些技術(shù)事實(shí)來(lái)達(dá)成某種共識(shí)。
3.3.4 解決沖突
??解決沖突的第一步應(yīng)該始終是設(shè)法與你的評(píng)審者達(dá)成共識(shí)。如果無(wú)法達(dá)成共識(shí),請(qǐng)參閱代碼評(píng)審標(biāo)準(zhǔn),其中提供了這種情況下應(yīng)遵循的原則。