關(guān)于代碼評(píng)審(CodeReview)那些不得不說(shuō)的事兒
當(dāng)前位置:點(diǎn)晴教程→知識(shí)管理交流
→『 技術(shù)文檔交流 』
在一個(gè)成熟的團(tuán)隊(duì)中,CodeReview 是整個(gè)研發(fā)流程中不可或缺的一步,而那些即將走向成熟的團(tuán)隊(duì)可能對(duì) CodeReview 有很多的誤解和問(wèn)題,也不清楚 CodeReview 該如何去做,本文筆者將結(jié)合自己的經(jīng)驗(yàn)和知識(shí),談?wù)勎覍?duì) CodeReview 流程的一些理解和建議 。 什么是CodeReviewCodeReview 國(guó)內(nèi)也稱「代碼評(píng)審或者代碼審查」,也簡(jiǎn)稱CR,是指在軟件開(kāi)發(fā)過(guò)程中,工程師對(duì)其他人所寫代碼做審閱(后文統(tǒng)稱CodeReview),以達(dá)到控制代碼質(zhì)量的目的。通常的流程都是由代碼寫作者發(fā)起,請(qǐng)團(tuán)隊(duì)內(nèi)其他人審閱代碼,其他人對(duì)代碼提出改進(jìn)建議,再由代碼寫作者修改重新提交,直至代碼通過(guò)大家的審閱為止。 為什么要做CodeReview?其實(shí)很多人都不是很重視CodeReview,因?yàn)镃odeReview的效果短期很難看到,也很難量化衡量。就如同運(yùn)動(dòng)一樣,偶爾過(guò)量的運(yùn)動(dòng)不僅對(duì)身體無(wú)益,可能還會(huì)起反作用,不過(guò)長(zhǎng)期的堅(jiān)持肯定會(huì)讓你更健康,但能讓你健康多少很難量化,不過(guò)前一段時(shí)間github上爆火的項(xiàng)目《程序猿延壽指南》里給出了可參考的數(shù)據(jù),每周3次45分鐘揮拍運(yùn)動(dòng)可以減少全因死亡率47%,按其公式折算大概增加9年的預(yù)期壽命。運(yùn)動(dòng)除了增加預(yù)期壽命外,也能顯著減少很多疾病的發(fā)病率。堅(jiān)持CodeReview如同堅(jiān)持運(yùn)動(dòng)一樣,趨勢(shì)肯定是讓整個(gè)代碼庫(kù)更為健康長(zhǎng)壽。 CodeReview從長(zhǎng)期來(lái)看,有幾個(gè)明顯的好處,接下來(lái)就一一講一下。 提升代碼質(zhì)量假如將一個(gè)系統(tǒng)比作一個(gè)生命體,一行行代碼比作一個(gè)個(gè)細(xì)胞,不好的設(shè)計(jì)宛如癌細(xì)胞,會(huì)逐漸擴(kuò)散,終將殺死系統(tǒng)。而CodeReview的過(guò)程就像是T細(xì)胞吞噬掉癌細(xì)胞,保證系統(tǒng)的健康成長(zhǎng)。讓系統(tǒng)有更長(zhǎng)久的生命力。
因?yàn)閱蝹€(gè)人可能在某些方便做的比較好,集大家之所長(zhǎng)就能在各個(gè)方面都做的比較好。另外,隨著CodeReview流程日常化,每個(gè)參與人的編碼能力也會(huì)逐步提升,無(wú)限趨近于團(tuán)隊(duì)最高水準(zhǔn),因?yàn)樵贑odeReview的過(guò)程中,你可以看到別人做的好的地方,可以學(xué)習(xí)到經(jīng)驗(yàn),也可以看到別人做的不好的地方,吸取到教訓(xùn)。隨著時(shí)間的流逝,逐漸積累為參與者的能力。 提前發(fā)現(xiàn)問(wèn)題在沒(méi)有CodeReview流程的時(shí)候,我們都是依賴于測(cè)試,甚至是依賴于功能上線后用戶暴露問(wèn)題,這種發(fā)現(xiàn)方式已經(jīng)偏晚了,尤其是讓用戶暴露問(wèn)題的時(shí)候可能問(wèn)題已經(jīng)非常大了。「問(wèn)題暴露的越晚,風(fēng)險(xiǎn)也就越大」。而CodeReview一般是放在代碼測(cè)試之前,如果能在這個(gè)階段就發(fā)現(xiàn)問(wèn)題就能提前將各種風(fēng)險(xiǎn)扼殺在搖籃中。但是,CodeReview真的能提前發(fā)現(xiàn)問(wèn)題嗎?如果能的話,可以提前發(fā)現(xiàn)什么樣的問(wèn)題? 我個(gè)人覺(jué)得CodeReview可以提前發(fā)現(xiàn)流程或者實(shí)現(xiàn)上的問(wèn)題,尤其是在做業(yè)務(wù)需求的時(shí)候,不同工作經(jīng)驗(yàn)的人對(duì)同一個(gè)需求的理解肯定會(huì)有差異,代碼實(shí)現(xiàn)上也會(huì)有很大的差異,有時(shí)候一點(diǎn)點(diǎn)的理解偏差,導(dǎo)致出現(xiàn)那種失之毫厘謬以千里的后果,寫代碼的人也會(huì)因?yàn)樘幵谧约旱乃季S定式中發(fā)現(xiàn)不了問(wèn)題,而別人可能因?yàn)榻?jīng)驗(yàn)豐富或者需求相關(guān)背景了解更多,就能很輕易發(fā)現(xiàn)問(wèn)題。像這種情況一般出現(xiàn)在團(tuán)隊(duì)新人身上,他們對(duì)已有系統(tǒng)和業(yè)務(wù)了解不多,實(shí)現(xiàn)需求時(shí)很容易出現(xiàn)問(wèn)題,這時(shí)候如果有人幫忙指出就能避免更嚴(yán)重的后果,另外也有助于新人了解業(yè)務(wù)和融入團(tuán)隊(duì)。 在CodeReview過(guò)程中另外一種問(wèn)題也比較容易發(fā)現(xiàn),就是那些別人之前踩過(guò)的坑。比如Java中SimpleDateFormat其實(shí)有線程安全的問(wèn)題,不了解的人很容易就踩坑了。如果別人踩過(guò)這個(gè)坑,就可以在CodeReview過(guò)程中提前幫你指出來(lái)。很多開(kāi)源的類庫(kù),甚至Jdk中很多包或多或少都有使用上的坑…… 這種例子就數(shù)不勝數(shù)了。 當(dāng)然CodeReview也不是萬(wàn)能的,也有很多問(wèn)題發(fā)現(xiàn)不了的,比如一些邊緣Case或者是代碼計(jì)算結(jié)果的準(zhǔn)確性,比如你代碼實(shí)現(xiàn)了一個(gè)很復(fù)雜公式的計(jì)算,你總不能指望有人能通過(guò)看代碼來(lái)發(fā)現(xiàn)問(wèn)題吧。這些還是老老實(shí)實(shí)去做測(cè)試吧! 經(jīng)驗(yàn)和知識(shí)的傳遞程序猿可以寫出能運(yùn)行的代碼,但真正的工程師才能寫出低bug、易擴(kuò)展、易維護(hù)的高質(zhì)量代碼,更高級(jí)的工程師還能幫其他人成為一名合格的工程師。CodeReview的流程也是高級(jí)工程師來(lái)幫助其他人最直接的方式。 在CodeReview中,你可以看到其他人寫出來(lái)的優(yōu)秀代碼、優(yōu)秀的設(shè)計(jì),甚至和改動(dòng)相關(guān)的業(yè)務(wù)背景知識(shí)……,Review越多,學(xué)到的也越多。另外,即便是哪些不太好的代碼,經(jīng)過(guò)別人的Review,必然會(huì)留下很多評(píng)論或者是改動(dòng)建議,甚至是別人之前踩的坑,你都能看到,從這些內(nèi)容上你也可以學(xué)到很多新的知識(shí)。CodeReview不僅僅是一個(gè)提升代碼質(zhì)量方式,它也可以肩負(fù)起知識(shí)積累和消息集散的功能。 舉個(gè)我之前遇到過(guò)的例子,我們之前有個(gè)功能需要操作機(jī)器上的文件,當(dāng)然用Java的File也能實(shí)現(xiàn),但是對(duì)操作多層級(jí)的文件夾時(shí)就很不方便了,需要自己寫很多的代碼,搞不好還容易出bug。后來(lái)我發(fā)現(xiàn)apache-common包中提供了IOUtils類,可以很方便操作文件夾。我把這個(gè)寫到CodeReview的評(píng)論中,只要看到過(guò)的人都會(huì)知道原來(lái)有這個(gè)東西可以用。 所以,Review別人代碼時(shí)請(qǐng)毫不吝嗇地留下你的建議吧,另外,CodeReview時(shí)也不要忘記關(guān)注下別人的建議,說(shuō)不定可以學(xué)到新的東西。 如何做好CodeReview說(shuō)完了CodeReview的好處,相信你肯定已經(jīng)躍躍欲試了,如何能做好CodeReview?這里我根據(jù)我的知識(shí)和經(jīng)驗(yàn)分享下我的看法。 CodeReview的步驟了解改動(dòng)的背景CodeReview不是一上來(lái)就看代碼,這樣有可能你會(huì)看的云里霧里,純粹是浪費(fèi)時(shí)間。CodeReview雖然是Review代碼,但是首先你的知道你要看的代碼實(shí)現(xiàn)了什么樣的功能,是在什么樣的背景下去做的,清楚前因后果之后,你才能知道這個(gè)代碼大概應(yīng)該怎么去寫,你才能更好的去Review別人的代碼、去發(fā)現(xiàn)別人的問(wèn)題。 縱觀全局知道背景之后,在你腦海中就會(huì)有一個(gè)大概的編碼思路,也有個(gè)流程主線。這個(gè)時(shí)候可能有兩種情況,你和寫代碼人的思路相同,那你就順著你們共同的思路去幫忙Review整個(gè)流程是否正確。另一種情況就是你們思路不同,你就得看代碼去了解寫作者的思路,然后確認(rèn)是誰(shuí)的思路有問(wèn)題,或者是誰(shuí)的思路更好,然后同寫作者一起將這個(gè)流程優(yōu)化到更優(yōu)。 逐層細(xì)化確定完整個(gè)流程之后,就可以逐步深入到代碼細(xì)節(jié)中了,細(xì)節(jié)可以Review的地方就很多了,可以看下下一節(jié)的內(nèi)容,這里就先不展開(kāi)了。 CodeReview的關(guān)注點(diǎn)在CodeReview的過(guò)程中,如果有一些立足點(diǎn)的話可以幫助大家更好的完成CodeReview的過(guò)程,我大概總結(jié)出以下幾點(diǎn):
上面描述更偏概括性,我們來(lái)舉一些更詳細(xì)的例子,幫助大家理解上面幾點(diǎn)。
注意事項(xiàng)CodeReview的禮節(jié)首先CodeReview不是你個(gè)人炫技的舞臺(tái),看到別人代碼的問(wèn)題需要禮貌指出,切忌diss別人。其次,CodeReview不要為了提問(wèn)題而提問(wèn)題,有些代碼就是沒(méi)問(wèn)題,你也沒(méi)必要糾結(jié)必須要提個(gè)問(wèn)題,直接通過(guò)即可。這里在額外說(shuō)一點(diǎn),大部分Review別人的代碼,只關(guān)注到別人做的不好的地方,而忽視了別人做的好的地方,遇到好的代碼、好的設(shè)計(jì)也別忘記點(diǎn)個(gè)贊。 CodeReview應(yīng)當(dāng)及時(shí)別人提的CodeReview應(yīng)當(dāng)及時(shí)處理,在很多公司中CodeReview是開(kāi)發(fā)流程中必要的一環(huán),沒(méi)有Review通過(guò)的肯定是不能上線的,如果CodeReview長(zhǎng)時(shí)間不處理可能會(huì)延誤后續(xù)的流程。另外一點(diǎn),CodeReview是相互的,今天你及時(shí)幫別人Review了,明天別人也會(huì)及時(shí)幫你Review,「與人方便即與己方便」。 如何寫出對(duì)CodeReview友好的代碼
時(shí)刻謹(jǐn)記上面這句話。 提交前先做好自審提前自己處理掉一些低級(jí)錯(cuò)誤,可以先借助一些工具完成一些簡(jiǎn)單的檢查。例如我們團(tuán)隊(duì)會(huì)借助checkstyle、spotbug、sonar、pmd等工具完成代碼風(fēng)格和一些潛在bug的檢查。然后自己做好功能的自測(cè),盡可能先消滅一部分bug,為CodeReview減少一些負(fù)擔(dān)。 寫清楚變更描述這里對(duì)應(yīng)上文中CodeReview步驟中的了解改動(dòng)背景,作為代碼的寫作者,你不能一上來(lái)就讓別人從代碼入手吧,可能看你代碼的很多其他人都缺少代碼改動(dòng)相關(guān)的上下文信息,完全理解代碼成本很高,所以需要在變更描述中將這些信息描述清楚,包括但不僅限于改動(dòng)背景、改動(dòng)點(diǎn)、流程、具體設(shè)計(jì)…… 一句話概括就是「好的變更描述應(yīng)該說(shuō)清楚這次是做了什么變更,以及為什么要這么做」。 更詳實(shí)的變更描述可以讓Review代碼人減少理解成本,更快完成CodeReview的流程,你代碼改動(dòng)也就能更快進(jìn)入后續(xù)流程了。 單個(gè)變更盡可能短一個(gè)非常大的變更幾乎沒(méi)有Review,因?yàn)榇蟮母膭?dòng)首先就很難Review,其實(shí)也更耗費(fèi)時(shí)間,還有出問(wèn)題的概率也更大,誰(shuí)Review通過(guò)了代碼但之后上線出問(wèn)題,可能是要和你一起背鍋的。所以建議大家將大的代碼變更盡可能拆小,因?yàn)樾〉淖兏幸韵逻@些好處:
對(duì)于那些很難拆分的變更,也不是需要完全禁止,有時(shí)候就是有改動(dòng)非常大,而且無(wú)法再去拆分了,這時(shí)候還是建議通過(guò)其他方式來(lái)保證代碼質(zhì)量,比如全流程測(cè)試。然后也建議做好出問(wèn)題時(shí)的快速恢復(fù)方案。 注意事項(xiàng)注意自己的情緒代碼的寫作者在CodeReview的流程中是弱勢(shì)的一方,很多人代碼在收到評(píng)論被要求要修改代碼的時(shí)候,都有一種不太愿意接受的心態(tài),其實(shí)我自己也經(jīng)常會(huì)有這種心態(tài),尤其是在時(shí)間比較緊張的情況下。其實(shí)這是很正常的心態(tài),但是還是需要去控制自己的情緒的,從評(píng)論者的角度出發(fā),他肯定也不是在刁難你,也是希望代碼質(zhì)量能更高。如果真遇到這種情況,首先可以和評(píng)論者討論清楚他的要求是否合理,如果確定了合理性當(dāng)然還是要改的。但如果在時(shí)間比較緊張的情況下,協(xié)商是否可以不修改或者是之后再修改,確實(shí)有些錦上添花的修改沒(méi)必要阻塞之后的流程。 CodeReview流程應(yīng)該盡早提交日常情況下,還是建議早點(diǎn)提交CodeReview,并留出一定的時(shí)間來(lái)做修改,盡可能不要讓這個(gè)流程變的匆忙。大部分公司的實(shí)踐都是在進(jìn)入測(cè)試流程的時(shí)候同時(shí)進(jìn)入CodeReview流程。 關(guān)于CodeReview的幾個(gè)誤區(qū)CodeReview是純浪費(fèi)時(shí)間?如果你的團(tuán)隊(duì)剛開(kāi)始推行CodeReview流程,這個(gè)問(wèn)題肯定是會(huì)被很多人問(wèn)到的。所以是不是呢? 這里我拿鍛煉身體類比下,大家都知道堅(jiān)持運(yùn)動(dòng)對(duì)健康有益,但如果只是一時(shí)興起,偶爾過(guò)量的運(yùn)動(dòng)不僅對(duì)身體無(wú)益,可能還會(huì)起反作用。實(shí)際上,堅(jiān)持運(yùn)動(dòng)對(duì)健康的影響其實(shí)很難量化,但我們現(xiàn)在都知道,運(yùn)動(dòng)是好的。同樣,CodeReview如同運(yùn)動(dòng)一樣,它可能會(huì)耗費(fèi)一定的精力和時(shí)間,但長(zhǎng)期堅(jiān)持下來(lái)必然會(huì)讓整個(gè)代碼庫(kù)、整個(gè)系統(tǒng)甚至這個(gè)團(tuán)隊(duì)更加健康。 另外,如果一個(gè)團(tuán)隊(duì)CodeReview機(jī)制很成熟,寫代碼的人隨著被Review的次數(shù)增加,其代碼質(zhì)量必然也會(huì)逐步提交,那么代碼中的問(wèn)題肯定也會(huì)逐步減少,隨之而來(lái)的就是CodeReview的過(guò)程越來(lái)越輕松。
工期很緊,沒(méi)時(shí)間做CodeReview!這也是很多團(tuán)隊(duì)不做CodeReview的借口。你不做CodeReview省下的時(shí)間,會(huì)在后面測(cè)試,甚至是在后面長(zhǎng)期維護(hù)中花費(fèi)更多的時(shí)間。我們有句耳熟能詳?shù)睦显捊凶觥澳サ恫徽`砍柴工”,其實(shí)CodeReview和測(cè)試在軟件開(kāi)發(fā)過(guò)程中就是“磨刀”的工作。 「做好事前控制而不是事后彌補(bǔ)。因?yàn)闀r(shí)候彌補(bǔ)的代價(jià)會(huì)非常高,」 只有高級(jí)工程師才有資格Review別人代碼?雖然事實(shí)上幾乎都是高級(jí)工程師在Review別人的代碼,我理解造成這種現(xiàn)象的原因其實(shí)也比較簡(jiǎn)單,高級(jí)工程師確實(shí)經(jīng)驗(yàn)豐富一些,也更容易R(shí)eview出別人代碼中的問(wèn)題,所以會(huì)留下更多的Review記錄,造成只有高級(jí)工程師才參與CodeReview的假象。但這絕不意味著初級(jí)工程師沒(méi)有資格Review別人的代碼,所謂三人行必有我?guī)煟幢闶浅跫?jí)工程師也有可能發(fā)現(xiàn)Review出別人代碼中的問(wèn)題。 即便你暫時(shí)確實(shí)經(jīng)驗(yàn)不夠豐富,很難找出別人的問(wèn)題,但你也可以從別人Review代碼的過(guò)程中學(xué)到很多東西,就像上文所說(shuō)CodeReview也是團(tuán)妒經(jīng)驗(yàn)和知識(shí)的一種傳遞方式。參與CodeReview也是成為高級(jí)工程師必不可少的一步。 都有測(cè)試流程了,為什么還要做CodeReview?這個(gè)問(wèn)題算是已經(jīng)在上文中回答過(guò)了,CodeReview需要看很多個(gè)方面的內(nèi)容,而測(cè)試只能保證其結(jié)果的準(zhǔn)確性。 有了CodeReview就不需要測(cè)試了?問(wèn)這個(gè)問(wèn)題的人相比于問(wèn)上個(gè)問(wèn)題的人又走了另一個(gè)極端,又把CodeReview和測(cè)試放在了對(duì)立面上。雖然CodeReview如果做的比較好的話,確實(shí)能提前發(fā)現(xiàn)一些比較明顯的問(wèn)題,但是做CodeReview的是人,人是無(wú)法大規(guī)模且精準(zhǔn)的去校驗(yàn)程序的執(zhí)行過(guò)程,而這恰恰是自動(dòng)化測(cè)試所擅長(zhǎng)的,所以說(shuō)CodeReview和測(cè)試并不是對(duì)立關(guān)系,而是一種互補(bǔ)關(guān)系。 只要我在團(tuán)隊(duì)推行了CodeReview流程,代碼質(zhì)量就會(huì)迅速提高?首先可以肯定的是代碼質(zhì)量是會(huì)提高的,但也許沒(méi)有那么快。我之前從一個(gè)沒(méi)有CodeReview流程的團(tuán)隊(duì)加入到一個(gè)有嚴(yán)格CodeReview流程的團(tuán)隊(duì)時(shí),有較長(zhǎng)一段適應(yīng)期。我當(dāng)時(shí)最大的感受就是CodeReview太耗時(shí)間了,尤其是我剛開(kāi)始還沒(méi)適應(yīng)新團(tuán)隊(duì)開(kāi)發(fā)規(guī)范的時(shí)候,寫代碼和被Review后改代碼所花費(fèi)的時(shí)間基本上五五開(kāi),當(dāng)然之后會(huì)好很多。另外,每個(gè)人也需要花20%左右的時(shí)間和精力去Review別人的代碼,相當(dāng)于花接近三分之一的開(kāi)發(fā)時(shí)間來(lái)處理CodeReview相關(guān)工作,這個(gè)比例高到可能你們老板都會(huì)懷疑,但我們當(dāng)時(shí)就做到了,結(jié)果就是我們的代碼質(zhì)量非常高。 以我的經(jīng)歷來(lái)看,如果CodeReview想要有效果,時(shí)間投入肯定是少不了的,冰凍三尺非一日之寒,滴水石穿非一日之功。不要高估它的短期價(jià)值,也不要低估它的長(zhǎng)期價(jià)值。 參考資料
該文章在 2024/12/17 11:06:36 編輯過(guò) |
關(guān)鍵字查詢
相關(guān)文章
正在查詢... |