技术分享 | CodeReview主要Review什么?
源寶導(dǎo)讀:Code Review, 意即代碼審查,是指一種有意識(shí)和系統(tǒng)的召集其他程序員來(lái)檢查彼此的代碼是否有錯(cuò)誤的地方. 在敏捷團(tuán)隊(duì)中推行CodeReview, 可以幫助團(tuán)隊(duì)快速成長(zhǎng).本文將分享在"天際-建模平臺(tái)"如何推行&實(shí)踐CodeReview。
一、為什么要 Code Review?
要不要Code Review,需要結(jié)合當(dāng)前的環(huán)境和形勢(shì)來(lái)決定。如果項(xiàng)目組開(kāi)發(fā)任務(wù)極其緊張,?此時(shí)再進(jìn)行Code Review可能會(huì)收到不利的效果,因勢(shì)利導(dǎo),求同存異是Code Review的核心所在。
Code Review, 需要和項(xiàng)目組成員溝通和配合,同時(shí)也在檢驗(yàn)各成員的技術(shù)水平。
需要注意的是,人都有惰性,每個(gè)人都有自己的一套行為準(zhǔn)則和規(guī)范,要想把他們的行為或規(guī)范統(tǒng)一起來(lái),很容易使他們產(chǎn)生抗拒心理。
在Code Review之前,和項(xiàng)目成員溝通好,有一個(gè)共同的愿景,并輔助以相應(yīng)的培訓(xùn),把部分人員的短板補(bǔ)齊。會(huì)減輕項(xiàng)目成員的一些不適感,也會(huì)使得項(xiàng)目運(yùn)行更加順暢。
同時(shí), 也要注意,不要事事求完美主義,一步求成。"慢即是快"。
二、?Code Review的前提條件
Code Review本身屬于"事后"工作,可以起到查漏被缺的作用。?
在推行Code Review時(shí),需要先提前準(zhǔn)備以下幾個(gè)工作,以便團(tuán)隊(duì)能夠更快更好的接受和實(shí)施。
建立規(guī)范, 包含:
編碼規(guī)范,如變量命名,文件命名規(guī)范等。
設(shè)計(jì)原則,如單一職責(zé)原則,最少知識(shí)原則等。
分支管理策略。
完善的文檔,方便查閱。文檔內(nèi)容最好能共建,千萬(wàn)不可出現(xiàn)"一言堂";
制定Code Review流程&目標(biāo),以及實(shí)施周期。
例如, 根據(jù)當(dāng)前團(tuán)隊(duì)的實(shí)際情況,將Code Review實(shí)施分為3個(gè)階段。
第一階段,重點(diǎn)關(guān)注,恰到好處的函數(shù)注釋,"硬編碼"問(wèn)題,常見(jiàn)變量命名規(guī)則等,預(yù)期實(shí)施周期為1~3個(gè)月。
第二階段,重點(diǎn)關(guān)注,代碼耦合性,單一職責(zé)、最少知識(shí)原則, 潛在隱患,性能問(wèn)題等,預(yù)期實(shí)施周期為3~6個(gè)月。
第三階段,重點(diǎn)關(guān)注,模塊實(shí)現(xiàn)方案,設(shè)計(jì)模式,最佳實(shí)踐,代碼重構(gòu)等。
在實(shí)施過(guò)程中,如果遇到比較大的阻力或困難,推行Code Review所得到的收益較低時(shí),可以考慮適當(dāng)"休息"一段時(shí)間。
三、常見(jiàn)的Code Review項(xiàng)
3.1 git 提交規(guī)范
git commit提交規(guī)范, 如:
不標(biāo)注信息
不及時(shí)commit
提交時(shí)標(biāo)注的信息不規(guī)范等
都是嚴(yán)重阻擾review的因素之一,除了常規(guī)的描述信息外,還可以按類(lèi)型等備注:
feat: 新特性
fix: 修改問(wèn)題
refactor: 代碼重構(gòu)
docs: 文檔修改
chore: 其他修改
test: 測(cè)試用例修改
style: 代碼格式修改等等
當(dāng)然,也要以利用一些工具,來(lái)協(xié)助我們完成基本的約束和檢查。
3.2 風(fēng)格
3.2.1 可讀性
衡量可讀性,有很好的實(shí)踐標(biāo)準(zhǔn),即Code Review時(shí)能否非常容易的理解代碼邏輯,如果不能,那意味著代碼的可讀性要進(jìn)行改進(jìn)。
3.2.2 命名
命名對(duì)可讀性非常重要,我個(gè)人傾向于函數(shù)名/類(lèi)名長(zhǎng)一點(diǎn)都沒(méi)關(guān)系,但必須能清晰的表明函數(shù)/類(lèi)的作用。
英語(yǔ)用詞盡量準(zhǔn)確, 哪怕需要借助翻譯工具,也是值得的。但有一點(diǎn)需要注意,如果使用的單詞很冷門(mén),都沒(méi)人認(rèn)識(shí), 那就不要使用。
3.2.3 函數(shù)體長(zhǎng)度/類(lèi)長(zhǎng)度
函數(shù)體太長(zhǎng),不好閱讀,一般建議不要超過(guò)50行。
類(lèi)太長(zhǎng), 如超過(guò)1000行,那可能就要看下是否違反了"單一職責(zé)"原則。
3.2.4 參數(shù)個(gè)數(shù)
不要太多,一般不要超過(guò)5個(gè), 超過(guò)5個(gè),建議使用對(duì)象。
3.2.5 注釋
恰到好處的注釋,能夠幫助我們理解函數(shù)/類(lèi)的作用。
3.3 架構(gòu)/設(shè)計(jì)
3.3.1 單一職責(zé)原則
這是經(jīng)常被違背的原則,也是最難運(yùn)用好的原則。
一個(gè)類(lèi)只做一類(lèi)相關(guān)的事情。
一個(gè)函數(shù)/方法, 最好只做一件事情。
3.3.2 行為是否統(tǒng)一
什么是行為統(tǒng)一? 例如:
錯(cuò)誤處理是否統(tǒng)一
錯(cuò)誤提示是否統(tǒng)一
彈出框是否統(tǒng)一
......
同一邏輯/行為,有沒(méi)有執(zhí)行同樣的代碼路徑,?低質(zhì)量的代碼一個(gè)特征是,同一邏輯/行為,在不同的地方或不同的方式觸發(fā)時(shí),沒(méi)有執(zhí)行同樣的代碼路徑(產(chǎn)生出不同的結(jié)果),或者是各處copy一份實(shí)現(xiàn),導(dǎo)致非常難以維護(hù).。
3.3.3 代碼污染
代碼有沒(méi)有對(duì)其他模塊強(qiáng)耦合。
3.3.4 重復(fù)代碼
主要看有沒(méi)有把公用組件,可復(fù)用的代碼、函數(shù)抽取出來(lái)。
3.3.5 ?開(kāi)放-封閉原則
簡(jiǎn)單理解是,看代碼好不好擴(kuò)展。
3.3.6 健壯性
核心數(shù)據(jù)有沒(méi)有強(qiáng)制校驗(yàn)?
對(duì)業(yè)務(wù)有沒(méi)有考慮完整, 邏輯是否健壯。
有沒(méi)有潛在的bug?
有沒(méi)有內(nèi)存泄露?有沒(méi)有循環(huán)依賴(lài)?
......
3.3.7 錯(cuò)誤處理
有沒(méi)有很好的Error Handling? 如網(wǎng)絡(luò)出錯(cuò),,IO出錯(cuò)等。
3.3.8 面向接口編程/面向?qū)ο蠼涌诰幊?/strong>
主要看有沒(méi)有進(jìn)行合適的抽象,把一些行為抽象為接口。
3.3.9 效率/性能
客戶(hù)端程序?qū)︻l繁的消息和較大數(shù)據(jù)等耗時(shí)操作是否處理得當(dāng)。
關(guān)鍵算法的時(shí)間復(fù)雜度是多少? 有沒(méi)有潛在的性能瓶頸?
3.3.10 代碼重構(gòu)
新的改動(dòng)是打補(bǔ)丁,讓代碼質(zhì)量繼續(xù)惡化,還是對(duì)代碼質(zhì)量提升有幫助?
四、Code Review如何實(shí)施?
結(jié)合當(dāng)前建模小組團(tuán)隊(duì)的實(shí)際情況:
新人較多,多對(duì)業(yè)務(wù)不對(duì)熟悉。
前期團(tuán)隊(duì)人員少,但有CodeReview的文化。
已有相關(guān)的編碼規(guī)范的知識(shí)沉淀,但因之前迭代任務(wù)重/人力資源緊張等因素,?導(dǎo)致未長(zhǎng)期推行下來(lái)。
針對(duì)以上情況,經(jīng)過(guò)團(tuán)隊(duì)內(nèi)部協(xié)商研討,輸出相應(yīng)的解決機(jī)制:
"結(jié)對(duì)編程",每個(gè)Story盡量安排兩位同學(xué)一起完成(1位主責(zé)人),主要有兩個(gè)目的:
老帶新,在工作實(shí)踐中多溝通交流,幫助新員工盡快熟悉業(yè)務(wù),融入團(tuán)隊(duì)。
相互審查代碼,提高代碼質(zhì)量,同時(shí)促進(jìn)新老員工溝通交流,思想上多碰撞。
兩級(jí)代碼審查機(jī)制
第一級(jí),由"結(jié)對(duì)編程"小組的兩位同學(xué)交叉審查代碼,過(guò)濾掉一些簡(jiǎn)單的代碼問(wèn)題。
第二級(jí),由技術(shù)leader進(jìn)行最終審查,確保代碼審查保質(zhì)保量完成。
定期分享收錄的典型問(wèn)題
代碼審查過(guò)程中,發(fā)現(xiàn)的一些典型問(wèn)題,及時(shí)收錄并做好分析。
定期開(kāi)展"壞代碼"分享會(huì)。
主要實(shí)施分三個(gè)階段進(jìn)行:
第一階段, 恰到好處的函數(shù)注釋, "硬編碼"問(wèn)題,常見(jiàn)變量命名規(guī)則等,預(yù)期實(shí)施周期為1~3個(gè)月。
第二階段,代碼耦合性, 單一職責(zé)、最少知識(shí)原則, 潛在隱患,性能問(wèn)題等,?預(yù)期實(shí)施周期為3~6個(gè)月。
第三階段,模塊實(shí)現(xiàn)方案,設(shè)計(jì)模式,最佳實(shí)踐,代碼重構(gòu)等。
從目前實(shí)施過(guò)程的體會(huì), 以及結(jié)合同學(xué)們的一些經(jīng)驗(yàn)來(lái)看,在Code Review時(shí)建議:
單次查看代碼不多于500行,人的精力有限,一次審查太多的代碼,收益可能不理想。
單次審查建議不要超過(guò)30分鐘。
祖?zhèn)鞔a怎么辦?
只查看git diff中, 帶有"+"的代碼,歷史代碼可以暫時(shí)忽略不看,在不斷的迭代中,遲早會(huì)遇到需要修改"祖?zhèn)?#34;代碼的。
這也是一種"妥協(xié)"的辦法,讓代碼審查者和開(kāi)發(fā)者之間有一個(gè)平衡。
對(duì)于"開(kāi)發(fā)者"的心理會(huì)產(chǎn)生一定的影響,他/她可能需要提前做好準(zhǔn)備,萬(wàn)一哪天需要修改"祖?zhèn)?#34;代碼呢?
在下一節(jié)中,收錄了實(shí)施過(guò)程中發(fā)現(xiàn)的一些典型的問(wèn)題代碼,大家可以一起"品嘗"下。
五、?低質(zhì)量代碼的常見(jiàn)特征
5.1 案例1
違反"單一職責(zé)"原則。
同一邏輯/行為, 通過(guò)不同的方式觸發(fā)時(shí), 不會(huì)執(zhí)行同樣的代碼路徑。
缺少注釋。
函數(shù)/類(lèi)命名亂, 詞不達(dá)意, 或"掛羊頭賣(mài)狗肉"。
上例函數(shù),其實(shí)是想對(duì)傳入的參數(shù)進(jìn)行判斷,如果值無(wú)效,取默認(rèn)圖片,否則返回拼接地址好的img src相對(duì)地址。從函數(shù)的實(shí)現(xiàn)來(lái)看, 有如下幾個(gè)問(wèn)題:
函數(shù)名setDefaultImg并不合適,無(wú)任何對(duì)數(shù)據(jù)的更新/修改,最終目的是想拿到img的拼接地址(或者默認(rèn)圖片)。
形參`res`是一個(gè)對(duì)象, 實(shí)際使用到的屬性只有兩個(gè)基本類(lèi)型,遵循最少知識(shí)原則,應(yīng)修改形參。
`let imgUrl`,其實(shí)是拼接url的前綴,取名如 `imgPrefixUrl`會(huì)比較合適。
let 使用不當(dāng),如 `let imgUrl`,因涉及不到變量再賦值,使用`const是比較合適的`。
`res.imgId`,即異常情況的處理,少了對(duì)`res.type`的處理。
變量命名,如`previewImgSrc`,取此名也不太合適,該src使用的目的并不確定,建議使用有比較通用涵義的名字。
可考慮重構(gòu)為:
export function getImgSrc(imgId, imgType) { if(typeof imgId !== 'string' || typeof imgType !== 'string') { return require('@/asserts/images/icon.png') } return `${getImagePrefixUrl()}${imgId}.${imgType}?t=${+new Date()}`}5.2 案例2
參數(shù)傳遞自由度過(guò)大,易引發(fā)后續(xù)不可控的風(fēng)險(xiǎn)。
上例代碼中,傳遞給`$emit`的數(shù)據(jù)是`this.$props`,會(huì)有以下問(wèn)題:
存在高耦合關(guān)系( 數(shù)據(jù)結(jié)構(gòu) 耦合)。
接收參數(shù),建議盡量使用:基礎(chǔ)數(shù)據(jù)類(lèi)型,如:字符串, 數(shù)字,布爾值等,非必要情況下, 不使用復(fù)雜數(shù)據(jù)類(lèi)型,如: Array, Object等。
可考慮重構(gòu)為:?
handleSelect(){ this.$emit('select', this.$props.userId)}5.3 案例3
違反"單一職責(zé)"原則,一個(gè)函數(shù)處理多個(gè)任務(wù),可能會(huì)在調(diào)函數(shù)時(shí)產(chǎn)生“異外的感覺(jué)”。
形參設(shè)計(jì)過(guò)度(形參無(wú)須解構(gòu),后續(xù)若有需要添加新的參數(shù)時(shí)再添加,也可考慮使用options參數(shù)等來(lái)實(shí)現(xiàn)擴(kuò)展)。
從上面的代碼中,我們可考慮從以下幾個(gè)角度著手重構(gòu), 以增強(qiáng)可讀性。
在入口函數(shù)處理,調(diào)用功能函數(shù)(通過(guò)函數(shù)名來(lái)區(qū)分功能),明示調(diào)用邏輯。
減少代碼量,增強(qiáng)可讀性,能用ES6 方法解決的就用它解決,盡量不造不必要的輪子,比如使用Array.findIndex來(lái)解決查找數(shù)組是否存在某一項(xiàng)的問(wèn)題。
優(yōu)化業(yè)務(wù)邏輯,刪除不必要的代碼,增強(qiáng)代碼的可維護(hù)性。
函數(shù)重新命名,務(wù)必做到“見(jiàn)名知意”。
添加必要的注釋(遵循jsdocs注釋規(guī)范)。
可考慮重構(gòu)為:
mounted(){const {row} = this.getSelectedRow();this.deleteRow(row);this.resetGrid();},/*** @description: 刪除指定的表格行數(shù)據(jù)* @param {Object} row, 表格行數(shù)據(jù)* @return*/deleteRow(row) {this.$refs.grid.remove(row)}/*** @description: 重置表格**/resetGrid(){if(this.$refs.grid.innerData.length && this.$refs.grid.innerData.findIndex(item => item.isQueryField) < -1){this.$refs.grid.innerData[0].isQueryField = truethis.handleChange({name: 'isQueryField',row: { $index: 0 },data: this.$refs.grid.innerData})}}六、總結(jié)
敏捷團(tuán)隊(duì)由"創(chuàng)建-振蕩-成熟-規(guī)范"的過(guò)程中, 不同的階段建議采取不同的方式開(kāi)展CodeReview, 需要考慮團(tuán)隊(duì)的整體情況以及當(dāng)前公司的業(yè)務(wù)的緊急程度,?優(yōu)先解決首要問(wèn)題,再接著解決其他次要問(wèn)題。
通過(guò)幾個(gè)月的漸進(jìn) & 持續(xù)的推行Code Review后,團(tuán)隊(duì)成員是可以達(dá)到以下效果的:
促進(jìn)團(tuán)隊(duì)成員的相互交流, 加速團(tuán)隊(duì)朝"成熟-規(guī)范"階段前進(jìn)。
知識(shí)分享, 促進(jìn)團(tuán)隊(duì)成員進(jìn)行反思和總結(jié)。
代碼質(zhì)量和可維護(hù)性, 可讀性等的提高。
查漏補(bǔ)缺, 發(fā)現(xiàn)一些潛在的問(wèn)題點(diǎn)等。
最佳實(shí)踐, 能夠更好更快的完成任務(wù)的方法。
------ END ------
作者簡(jiǎn)介
張同學(xué):?開(kāi)發(fā)工程師,目前負(fù)責(zé)天際-建模平臺(tái)產(chǎn)品的研發(fā)工作。
也許您還想看:
技術(shù)分享|Java SDK動(dòng)態(tài)數(shù)據(jù)源和上下文機(jī)制
技術(shù)分享|NodeJS分布式鏈路追蹤實(shí)現(xiàn)
技術(shù)分享 | Java SDK 元數(shù)據(jù)驅(qū)動(dòng)的事件通信架構(gòu)
技術(shù)分享|Hangfire深度實(shí)踐
技術(shù)分享 | APT結(jié)合JavaPoet生成模板化Java源代碼文件
技術(shù)分享 | 玩轉(zhuǎn)高效UI自動(dòng)化測(cè)試
更多明源云·天際開(kāi)放平臺(tái)場(chǎng)景案例與開(kāi)發(fā)小知識(shí),可以關(guān)注明源云天際開(kāi)發(fā)者社區(qū)公眾號(hào):
【建模】文檔服務(wù)提供高保真打印模式
明源云·天際硬核技術(shù)認(rèn)可:獲華為鯤鵬技術(shù)認(rèn)證書(shū)
天際·開(kāi)發(fā)者社區(qū)“重裝發(fā)布”!
總結(jié)
以上是生活随笔為你收集整理的技术分享 | CodeReview主要Review什么?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 一行代码完成定时任务调度,基于Quart
- 下一篇: 如何在单个测试中同时执行多个断言