01
背景
Code Review是互聯(lián)網(wǎng)公司的技術(shù)部門(mén)的基本要求,或者對(duì)技術(shù)比較重視的公司,在這方面也會(huì)比較重視吧。如果哪家互聯(lián)網(wǎng)公司沒(méi)有這個(gè)要求,也許稱(chēng)不上一個(gè)真正的互聯(lián)網(wǎng)公司吧。?
這里分享下我們項(xiàng)目組針對(duì)于Code Review這個(gè)環(huán)節(jié)的相關(guān)問(wèn)題進(jìn)行總結(jié)及其思考。
02
Code Review的作用
其實(shí)大部分人都知道Code Review的作用。這里簡(jiǎn)述下幾點(diǎn)主要作用:
①盡量避免bug的出現(xiàn)。只能盡量降低bug的"產(chǎn)出率",提前發(fā)現(xiàn)bug,降低生產(chǎn)事故發(fā)生率。
②方便維護(hù),降低維護(hù)成本。編寫(xiě)規(guī)范的代碼和優(yōu)秀的代碼可以給未來(lái)接手的同學(xué)更好的理解其意圖進(jìn)行維護(hù)或者在其基礎(chǔ)上繼續(xù)開(kāi)發(fā),不會(huì)讓新同學(xué)想“打死前任”的沖動(dòng)。
③正確處理業(yè)務(wù)需求邏輯。開(kāi)發(fā)同學(xué)實(shí)現(xiàn)的業(yè)務(wù)需求是否與需求對(duì)應(yīng),是否會(huì)存在理解偏差,是否存在處理不當(dāng)?shù)鹊取?/p>
④盡量最優(yōu)實(shí)現(xiàn)。在編寫(xiě)代碼的過(guò)程中,每個(gè)人的邏輯思維都可能存在不同,在評(píng)審過(guò)程中,開(kāi)發(fā)同學(xué)寫(xiě)的代碼還存在現(xiàn)有更好、更優(yōu)的實(shí)現(xiàn)方式,或者把實(shí)現(xiàn)的最優(yōu)邏輯分享給其它同學(xué)討論學(xué)習(xí)。
03
實(shí)戰(zhàn)分享
分享下我們這邊的一些Code Review經(jīng)驗(yàn)。
3.1、背景
最近整理了下每次評(píng)審存在的問(wèn)題,并且做了統(tǒng)計(jì)分析。大概經(jīng)歷了1年多的時(shí)間,接到30來(lái)個(gè)中、高等級(jí)的業(yè)務(wù)需求,參與了項(xiàng)目組的每次代碼評(píng)審,也作為主要的評(píng)審人員,并且把每次的評(píng)審都做了記錄,登記在wiki上。至今代碼評(píng)審有問(wèn)題的記錄數(shù)達(dá)到200來(lái)個(gè)。因新同學(xué)加入我們團(tuán)隊(duì),每次接手的需求開(kāi)發(fā)完成后進(jìn)行Code Review,我們都會(huì)比較針對(duì)性的對(duì)其代碼進(jìn)行比較仔細(xì)的審核,所以對(duì)于比較初級(jí)的問(wèn)題也是比較多,所以出現(xiàn)這類(lèi)問(wèn)題占比比較多也是比較合理的。我們團(tuán)隊(duì)的“老油條”經(jīng)歷過(guò)多次“洗禮”,代碼質(zhì)量也是得到很高的提升,相應(yīng)的評(píng)審問(wèn)題也是比較少的。所以下面的統(tǒng)計(jì)數(shù)據(jù)也是比較客觀,如果低級(jí)問(wèn)題比較多也是能理解的。
使用的工具:編碼規(guī)范+業(yè)務(wù)規(guī)范+技術(shù)規(guī)范+數(shù)據(jù)庫(kù)規(guī)范。
3.2、問(wèn)題分類(lèi)
這些問(wèn)題分類(lèi)是我自定義分類(lèi)的,可能存在不嚴(yán)謹(jǐn)?shù)牡胤健?/p>
主要分為兩大類(lèi):代碼問(wèn)題和業(yè)務(wù)問(wèn)題。
問(wèn)題類(lèi)別匯總:從統(tǒng)計(jì)上來(lái)說(shuō),業(yè)務(wù)問(wèn)題占了差不多1/4,代碼問(wèn)題占了3/4。所以我們能看出業(yè)務(wù)問(wèn)題也是在Code Review過(guò)程中占有很大的一部分,不容忽視;代碼問(wèn)題占用了絕大多數(shù),是我們技術(shù)人員比較著重關(guān)注的。
3.3、業(yè)務(wù)問(wèn)題
業(yè)務(wù)處理、業(yè)務(wù)規(guī)范、規(guī)范習(xí)慣。
◇業(yè)務(wù)處理:占了7成,說(shuō)明業(yè)務(wù)處理占了業(yè)務(wù)問(wèn)題的絕大部分。主要是與業(yè)務(wù)需求相關(guān)的處理上,不能達(dá)到業(yè)務(wù)上的需求,出現(xiàn)不合理或者與需求上存在差異,還有與具體的使用方式存在問(wèn)題,需求實(shí)現(xiàn)上存在的疑惑點(diǎn)等等。例子:有無(wú)登錄用戶(hù)cookies區(qū)分處理;接口是否需要增加登錄訪問(wèn)限制;匯總?cè)蝿?wù)時(shí)間應(yīng)該靈活支持自定義;瓜分紅包處理后無(wú)需再查庫(kù)等等。
◇業(yè)務(wù)規(guī)范:占了28%,主要是在業(yè)務(wù)實(shí)現(xiàn)上,使用的方式或者特定業(yè)務(wù)上使用不合理,沒(méi)有與業(yè)務(wù)規(guī)范上保持一致。比如:發(fā)獎(jiǎng)應(yīng)該調(diào)用統(tǒng)一發(fā)獎(jiǎng)接口;接收短信的手機(jī)號(hào)是哪種號(hào)碼類(lèi)型;判斷活動(dòng)時(shí)間其它取字段等等。
◇規(guī)范習(xí)慣:在業(yè)務(wù)規(guī)范上沒(méi)有養(yǎng)成一種習(xí)慣。比如:文檔沒(méi)有更新,SQL沒(méi)有實(shí)時(shí)更新等。
3.4、代碼問(wèn)題
編碼習(xí)慣、命名規(guī)范、日志打印、代碼優(yōu)化、數(shù)據(jù)庫(kù)、規(guī)范習(xí)慣、事務(wù)處理、異常處理、公共復(fù)用、bug、并發(fā)問(wèn)題、代碼注釋。
從統(tǒng)計(jì)數(shù)據(jù)得知,我們這邊主要出現(xiàn)的代碼問(wèn)題集中在:編碼習(xí)慣、命名規(guī)范、日志打印、代碼優(yōu)化這幾塊,占用了62%。但是其它的問(wèn)題也是同等重要,基本上每一項(xiàng)在代碼評(píng)審中都是非常重要的!
◇編碼習(xí)慣:占23%,這一塊在全部問(wèn)題中占比最大,主要是在編寫(xiě)的代碼中,使用的方式不是較好或者存在不合理的地方,而且有一些也可能跟我們業(yè)務(wù)上緊密相關(guān)。比如:①if包含return,不需要再else;②Map判斷key是否存在無(wú)需get后判斷對(duì)象是否為空,直接用Map api方法contains即可;③RPC調(diào)用結(jié)果應(yīng)增加狀態(tài)碼判斷;④避免在循環(huán)中寫(xiě)過(guò)于復(fù)雜度邏輯,可以抽取一下,等等。
◇命名規(guī)范:占16%,這一類(lèi)問(wèn)題排在第二位。也是大部分新同學(xué)出現(xiàn)的比較多,沒(méi)有按照規(guī)范來(lái),在命名上容易出現(xiàn)“隨心所欲”。比如:①接口名不要以Ixxx命名;②方法命名長(zhǎng)度太長(zhǎng);③命名拼寫(xiě)錯(cuò)誤;④數(shù)據(jù)庫(kù)表索引名太長(zhǎng);⑤命名與實(shí)際業(yè)務(wù)含義不符,等等。
◇日志打?。?b>占14%,這類(lèi)問(wèn)題在評(píng)審過(guò)程中,也出現(xiàn)不少日志打印比較粗心或者極少打印關(guān)鍵日志。我們都知道日志的重要性,幫助我們分析邏輯,排查線上問(wèn)題無(wú)比重要。比如:①日志級(jí)別使用錯(cuò)誤;②關(guān)鍵日志無(wú)打??;③方法入?yún)⑴c業(yè)務(wù)數(shù)據(jù)沒(méi)有打印,存在“失聯(lián)”;④異常堆棧未打印,等等。
◇代碼優(yōu)化:占14%,編寫(xiě)的代碼存在可優(yōu)化的空間或者使用方式不是很合理,性能上存在問(wèn)題等。比如:①方法長(zhǎng)度過(guò)長(zhǎng);②if嵌套太多,影響閱讀;③校驗(yàn)方法可以抽取成為單獨(dú)方;④不要在循環(huán)中查庫(kù),可優(yōu)化為查一次庫(kù);⑤邏輯不清晰需重構(gòu),等等。
◇數(shù)據(jù)庫(kù):占7%,主要是在與SQL打交道上存在問(wèn)題。比如:①使用union all語(yǔ)句應(yīng)優(yōu)化;②SQL中變量盡量傳遞進(jìn)來(lái),不要寫(xiě)死;③排序使用自增主鍵ID來(lái)代替create_time,等等。
◇規(guī)范習(xí)慣:占7%,主要是在編寫(xiě)代碼中一些規(guī)范上存在不合理的地方,這個(gè)也比較緊跟業(yè)務(wù)習(xí)慣上。比如:①M(fèi)agic數(shù)字應(yīng)定義為常量或根據(jù)業(yè)務(wù)需要使用配置參數(shù);②不要在方法中修改入?yún)?;③無(wú)用代碼別注釋直接刪除,等等。
◇事務(wù)處理:占4%,主要是在事務(wù)處理上存在不合理或者使用有誤,容易存在數(shù)據(jù)不一致造成bug。比如:①機(jī)會(huì)發(fā)放和獎(jiǎng)品發(fā)放應(yīng)該在同一事務(wù);②事務(wù)范圍不合理,應(yīng)該只包含insert、update放在事務(wù)里,其它rpc,mq調(diào)用應(yīng)該在事務(wù)外;③分布式鎖和事務(wù)處理應(yīng)該拆分,等等。
◇異常處理:占3%,在處理異常時(shí)存在不合理。比如:①RPC調(diào)用業(yè)務(wù),出現(xiàn)業(yè)務(wù)異常,應(yīng)該往后拋;②RPC請(qǐng)求出現(xiàn)異常需捕獲③兌換碼出現(xiàn)更新失敗應(yīng)拋出異常,等等。
◇公共復(fù)用:占3%,公共復(fù)用主要是工具已經(jīng)封裝好了無(wú)需重復(fù)寫(xiě)同樣的代碼,或者多次使用存在可以復(fù)用的代碼應(yīng)該抽取出來(lái)。比如:①多次return同一結(jié)果,應(yīng)封裝成公共的處理結(jié)果方法,直接返回即可,簡(jiǎn)化代碼,容易維護(hù);②RPC調(diào)用盡量封裝成service,供其它業(yè)務(wù)可能需要復(fù)用,等等。
◇bug:占4%,比較明顯的bug其實(shí)也不多,在業(yè)務(wù)處理上容易存在邏輯漏洞。在前面所說(shuō)的編碼習(xí)慣、事務(wù)處理等,也有的算是bug,沒(méi)有歸屬在這個(gè)分類(lèi)里。
◇并發(fā)問(wèn)題:占3%,并發(fā)問(wèn)題在我們每次評(píng)審的過(guò)程中,并發(fā)問(wèn)題都是特別關(guān)注的。比如:①獎(jiǎng)品的發(fā)放邏輯是否存在并發(fā)問(wèn)題;②用戶(hù)抽獎(jiǎng)是否存在并發(fā)問(wèn)題,等等。
◇代碼注釋?zhuān)?b>占2%,代碼注釋上這塊問(wèn)題是最少的,但是也是需要我們留意的,特別是對(duì)以后維護(hù)有很重要的意義。比如:①在比較復(fù)雜的業(yè)務(wù)邏輯,需要增加注釋?zhuān)虎趶椏蛱嵝逊祷啬J(rèn)特定值時(shí),應(yīng)增加注釋?zhuān)奖憷斫狻?/p>
3.5、業(yè)務(wù)開(kāi)發(fā)規(guī)范
我們?cè)贑ode Review的過(guò)程中,也根據(jù)實(shí)際業(yè)務(wù)進(jìn)行總結(jié)了跟業(yè)務(wù)緊密關(guān)聯(lián)的問(wèn)題,也就是業(yè)務(wù)開(kāi)發(fā)規(guī)范。在業(yè)務(wù)處理的時(shí)候,根據(jù)業(yè)務(wù)特點(diǎn)或者業(yè)務(wù)處理方式,我們需要按照實(shí)際業(yè)務(wù)去調(diào)用我們規(guī)定的方式,因?yàn)樵啻纬霈F(xiàn),所以做下記錄,防止后人或新人重復(fù)掉坑里,甚至重復(fù)出現(xiàn)同一類(lèi)問(wèn)題事故。同時(shí),我們針對(duì)總結(jié)的問(wèn)題,也按照建議和強(qiáng)制的規(guī)范級(jí)別來(lái)要求或者指導(dǎo)我們的同學(xué)進(jìn)行更好的開(kāi)發(fā)。
04
總結(jié)
在經(jīng)歷了這么一段時(shí)間的Code Review,在代碼層面上容易出現(xiàn)編碼不規(guī)范、命名不規(guī)范、日志打印問(wèn)題、代碼優(yōu)化等問(wèn)題,在數(shù)據(jù)庫(kù)層面上也出現(xiàn)了不規(guī)范使用問(wèn)題等。同時(shí)也遇到了很多容易出現(xiàn)問(wèn)題并且處理不當(dāng)?shù)膯?wèn)題,比如,在事務(wù)處理,異常處理、并發(fā)問(wèn)題處理上都存在比較嚴(yán)重的問(wèn)題。所以通過(guò)對(duì)這類(lèi)問(wèn)題我們基本知道了每次Code Review的關(guān)注點(diǎn)在哪,容易出現(xiàn)問(wèn)題的地方在哪,或者在設(shè)計(jì)實(shí)現(xiàn)上是否合理等,都能很好的協(xié)助我們對(duì)待每次評(píng)審,都是盡量高質(zhì)量的完成我們的目標(biāo)。
我們也發(fā)現(xiàn)了這么多問(wèn)題,也不是僅僅指出了事,負(fù)責(zé)人需要將相關(guān)問(wèn)題處理解決,有時(shí)甚至需要有經(jīng)驗(yàn)豐富的同學(xué)幫忙審核,而且每次評(píng)審?fù)曛笪覀兘?jīng)理都會(huì)在周會(huì)上詢(xún)問(wèn)相關(guān)人員是否把最近評(píng)審的相關(guān)問(wèn)題處理的如何,以此達(dá)到有始有終。
本次分析了全部的問(wèn)題,并且進(jìn)行歸類(lèi),發(fā)現(xiàn)很多同學(xué)容易出現(xiàn)編碼習(xí)慣方面的問(wèn)題,有時(shí)為了追求“高效”,而快速編碼,手敲代碼一把梭,容易忘了基本規(guī)范。
編寫(xiě)可維護(hù)的、高性能的、有效的代碼,能夠幫助我們整個(gè)項(xiàng)目達(dá)成比較好的共識(shí),這非常有益于我們以后維護(hù)前人留下的“坑”,而不會(huì)坑到新人。有些問(wèn)題似乎看起來(lái)非常低級(jí),也許會(huì)說(shuō)怎么能犯這種錯(cuò)誤,其實(shí)我們應(yīng)該都應(yīng)該有包容心,畢竟每個(gè)人都是一步一步成長(zhǎng),有錯(cuò)就指出,有錯(cuò)我們就改。
大家相互促進(jìn),相互提升,在評(píng)審的過(guò)程中,能夠更好的提高自己的代碼質(zhì)量、技術(shù)能力,甚至設(shè)計(jì)能力。
05
最佳實(shí)踐建議
以下是我工作多年的7點(diǎn)建議,希望對(duì)各位有所幫助:
1)制定規(guī)范:編碼規(guī)范+技術(shù)規(guī)范+業(yè)務(wù)規(guī)范+數(shù)據(jù)庫(kù)規(guī)范,形成標(biāo)準(zhǔn)文檔化。
2)根據(jù)需求開(kāi)發(fā),定期安排相關(guān)開(kāi)發(fā)人員、評(píng)審人員參與Code Review,有需要的話(huà)可以邀請(qǐng)測(cè)試人員參與。
3)開(kāi)始評(píng)審前,要求相關(guān)代碼通過(guò)阿里編碼規(guī)范/FIndBugs/SonarLint等插件進(jìn)行前期掃描,避免出現(xiàn)比較多的基本問(wèn)題。
4)新同學(xué)首次參入進(jìn)來(lái),需要著重關(guān)注新人,給予更好的建議,幫助提升代碼質(zhì)量。
5)針對(duì)評(píng)審質(zhì)量很高的代碼給予肯定,并且表?yè)P(yáng)相關(guān)人員。
6)定期總結(jié)Code Review存在的問(wèn)題,記錄相關(guān)問(wèn)題于wiki(文檔)上,按月度或季度定期輸出總結(jié)。
7)制定與實(shí)際業(yè)務(wù)相關(guān)的開(kāi)發(fā)規(guī)范,防止重復(fù)掉坑,重復(fù)出現(xiàn)同一類(lèi)問(wèn)題事故等。
這是搬運(yùn)工一些工作心得,如果覺(jué)得哪里說(shuō)的不好,或者有其它見(jiàn)解,歡迎評(píng)論,大家一起探討。
推薦閱讀
dubbo面試題!會(huì)這些,說(shuō)明你看懂了dubbo源碼
Kafka面試題!掌握它才說(shuō)明你真正懂Kafka