讓代碼審查扮演更好的角色
代碼審查(Code Review)是很多大公司里面都有的一個(gè)流程。它指的是一個(gè)人編碼,另有幾個(gè)人負(fù)責(zé)審查,并提出修改意見。代碼審查在大多數(shù)情況下對(duì)公司整體的工程質(zhì)量是有提高的,但是如果使用不當(dāng)?shù)脑?,很可能反倒?huì)降低工程質(zhì)量。代碼審查究竟在一個(gè)組織里面是有正面效應(yīng)或者是負(fù)面效應(yīng)取決于很多因素,而我認(rèn)為其中最重要的是代碼審查在開發(fā)過程中扮演的角色。
首先,我們先看看在代碼審查中所需要找出的問題類型。它們可以是:
- 語法及代碼風(fēng)格問題:一般有靜態(tài)檢查工具可以解決,但難免有疏漏。
- 效率問題:需要有一定經(jīng)驗(yàn)的人來辨別低效的部分。
- 命名問題:這其實(shí)是一個(gè)很經(jīng)常出現(xiàn)也很重要的問題。對(duì)于一個(gè)人來講說得通的命名不見得對(duì)于團(tuán)隊(duì)而言說得通,所以很多時(shí)候較難的命名要由團(tuán)隊(duì)通過代碼審查協(xié)同解決。
- 設(shè)計(jì)問題:小到接口的設(shè)計(jì),大到服務(wù)間通信的協(xié)議,都屬于設(shè)計(jì)問題,根據(jù)情況可以由小部分人或者整個(gè)團(tuán)隊(duì)解決。設(shè)計(jì)問題是代碼審查中最常見的問題。
對(duì)于前三種問題,相對(duì)來講都很好解決。其中相對(duì)棘手的莫過效率問題,但實(shí)際上基本上知道效率問題的人都知道優(yōu)化方案。然而,如果一個(gè)審查的人突然提出一個(gè)很合理的設(shè)計(jì)問題,需要你重新修改源代碼,你會(huì)發(fā)現(xiàn)你需要花大量地時(shí)間重新編寫。
例如,在編寫一個(gè)JavaScript庫packageA的時(shí)候,你提交了代碼審查。有人可能會(huì)提醒你:packageA是用于桌面端網(wǎng)站的庫,相對(duì)應(yīng)的還有一個(gè)移動(dòng)端的庫packageB。為了保持工程上的一致性,建議把packageA改成盒packageB一樣的API。一致性一直以來是一個(gè)讓人無法反駁的設(shè)計(jì)追求,所以你只好把辛辛苦苦自己設(shè)計(jì)好的API全部重改…
所以,若你的代碼里面被提出存在設(shè)計(jì)問題,消耗的工程時(shí)間會(huì)增加。而工程時(shí)間對(duì)公司來講就是金錢。
造成存在需要大改的設(shè)計(jì)問題的原因其實(shí)無非三個(gè):
- 設(shè)計(jì)能力不足
- 對(duì)開發(fā)的系統(tǒng)不熟悉,缺乏上下文(Context)
- 過晚提交代碼審查
前兩個(gè)原因都很直白,但是第三個(gè)原因有點(diǎn)匪夷所思。什么叫做過晚提交代碼審查?
我想是代碼審查英文單詞中的”Review”給予人的誤導(dǎo),很多人是在代碼幾乎完成或者已經(jīng)完成后才提交代碼審查的。就好像在做一盤菜,做到***一步的時(shí)候才想起來要嘗一小口看看味道對(duì)不對(duì),結(jié)果發(fā)現(xiàn)沒加鹽。
在***一步進(jìn)行代碼審查,還會(huì)因?yàn)閷彶檎咭幌伦咏邮仗嘈畔ⅲ斐伤赡軣o法發(fā)現(xiàn)一些應(yīng)該發(fā)現(xiàn)的問題。
顯然“審查”扮演的角色在這里出現(xiàn)了問題,它不應(yīng)該是傳統(tǒng)意義上的到***一步進(jìn)行把關(guān),而應(yīng)該是貫穿整個(gè)編碼過程的一個(gè)輔助過程。用比較老式的軟件工程“土話”說,它應(yīng)該是一個(gè)Umbrella Activity(雨傘活動(dòng)),全程保護(hù)編碼過程的質(zhì)量。
現(xiàn)在,我的代碼審查流程是這樣的:首先完成一個(gè)基本的設(shè)計(jì),加上基本的注釋,達(dá)到一個(gè)完成度——最可能出現(xiàn)大設(shè)計(jì)問題的完成度。接著 commit,并推入到代碼審查中,邀請(qǐng)其他人來審查。這基本上就是對(duì)他們說,“看,這是我寫的,很簡單,可能爛得跟一坨屎一樣,麻煩你們幫我看看有沒有什么大問題”。
稍微有點(diǎn)開發(fā)經(jīng)驗(yàn)的人,都可以大概估計(jì)出自己手頭的工作進(jìn)行到哪一步可能出現(xiàn)大的設(shè)計(jì)問題。例如,當(dāng)你在設(shè)計(jì)一個(gè)新的模塊,那么可能出現(xiàn)大的設(shè)計(jì)問題的時(shí)候可能就是設(shè)計(jì)API的時(shí)候。再緊接著,下一個(gè)可能出現(xiàn)大的設(shè)計(jì)問題的就是類之間的抽象關(guān)系,等等。
我甚至還會(huì)自己給自己的代碼進(jìn)行審查。這并不是在做驗(yàn)算,而是在通過代碼審查告訴團(tuán)隊(duì)自己的疑問,提出自己的想法,這樣大家就能更好地與你溝通。相信我,把有疑問、猶豫不決的地方提出來;有自己獨(dú)特想法的地方,也要指出來,因?yàn)槟愕莫?dú)特想法有時(shí)候?qū)F(tuán)隊(duì)來講就是不好的想法。
每當(dāng)遇到心里覺得可能出現(xiàn)大的設(shè)計(jì)問題的時(shí)候,盡量利用代碼審查,讓團(tuán)隊(duì)和你一起解決。對(duì)于工程經(jīng)驗(yàn)少的人來說(比如我),更應(yīng)該多做一點(diǎn)這樣的事。一開始這樣做可能反倒會(huì)開銷更多人的時(shí)間,但是過一陣子之后,你就更有把握做好的設(shè)計(jì)決策。換句話說,發(fā)生大設(shè)計(jì)問題的概率就會(huì)降低。因?yàn)槟憧偰茉诤蛣e人溝通的時(shí)候?qū)W到新東西。
然而,如果每次都在編碼完成之后再進(jìn)行代碼審查,雖說***經(jīng)過代碼審查可能也會(huì)產(chǎn)出高質(zhì)量的代碼,可你將花大部分時(shí)間在煩悶上,而花很少的時(shí)間真正體會(huì)他人提出的意見的真正價(jià)值。
長此以往,整個(gè)工程團(tuán)隊(duì)的工程時(shí)間可以得到顯著的下降。首先是因?yàn)槊總€(gè)人的經(jīng)驗(yàn)都能通過代碼審查增長得更快,因此總體工程效率會(huì)提高;第二是因?yàn)槿瘫Wo(hù)的代碼審查很好地解決(或緩解)各種層面的設(shè)計(jì)問題,讓工程無論從短期還是長期來講,需要花費(fèi)的工程時(shí)間降低,并且技術(shù)債務(wù)(technical debt)也會(huì)減少。
幸運(yùn)的是,雖說這里提到的是比較宏觀的流程問題,卻是一件落實(shí)到每個(gè)工程師自身的事情。也就是說,代碼審查如何執(zhí)行最終還是歸結(jié)于編碼的工程師個(gè)人。整個(gè)流程的轉(zhuǎn)換無需有新的工具加入,也不需要有很多復(fù)雜的文檔。所需要的只不過是對(duì)團(tuán)隊(duì)的一次培訓(xùn)——這篇文章或許就是一個(gè)不錯(cuò)的素材。