工程师必知的代码重构指南
作者 | CATE LAWRENCE
譯者 | 冬雨
策劃 | 蔡芳芳
本指南將帶你了解進(jìn)行代碼重構(gòu)的好處、可能遇到的挑戰(zhàn)、可以采用的工具和最佳實(shí)踐,以及重構(gòu)和技術(shù)債務(wù)之間的區(qū)別。
我們都在尋找清理代碼、降低復(fù)雜性和改進(jìn)功能的方法,重構(gòu)就是其中之一。
本指南將涵蓋以下主題:
- 重構(gòu)是什么?
- 重構(gòu)的好處是什么?
- 技術(shù)債務(wù)與重構(gòu)
- 重構(gòu)度量
- 代碼重構(gòu)的示例
- 代碼重構(gòu)的工具
- 重構(gòu)和對(duì)技術(shù)經(jīng)理的挑戰(zhàn)
- 高級(jí)管理層對(duì)重構(gòu)的支持
- 團(tuán)隊(duì)支持和重構(gòu):沖刺還是馬拉松?
- 文檔和重構(gòu)
01 什么是重構(gòu)
關(guān)于重構(gòu),Martin Fowler 寫過兩本的書,按照他的說法:
“重構(gòu)是改變軟件系統(tǒng)的過程,這一過程改變的不是代碼的外部行為,而是其內(nèi)部結(jié)構(gòu)。這是一種清理代碼、盡可能降低引入 bug 機(jī)率的方法。從本質(zhì)上說,進(jìn)行重構(gòu)時(shí),是你在代碼編寫之后改進(jìn)設(shè)計(jì)?!?/p>
02 重構(gòu)的好處是什么?
重構(gòu)代碼有許多好處。它將混亂、不正確和 / 或重復(fù)的代碼變成整潔的代碼。當(dāng)多個(gè)開發(fā)人員貢獻(xiàn)他們自己的代碼時(shí),可能會(huì)出現(xiàn)標(biāo)準(zhǔn)化的問題,它正可以解決這一問題。重構(gòu)可帶來更好的可讀性,并改善源代碼的可維護(hù)性以及整體的結(jié)構(gòu)和功能。重構(gòu)可以使代碼更易于擴(kuò)展和添加新的特性。刪除不必要的部分(如重復(fù)的部分),也可以使代碼使用的內(nèi)存更少、執(zhí)行的速度更快。
例如,在 2014 年,Kickstarter 工程師面臨著一項(xiàng)挑戰(zhàn),隨著用戶數(shù)量呈指數(shù)增長(zhǎng),導(dǎo)致查詢性能急劇下降。為了應(yīng)對(duì)此問題,他們重構(gòu)了一個(gè) MySQL 到 Redis 的查詢,減少了典型的 100ms 以上的加載時(shí)間,從而減少了加載時(shí)間的方差,總體上提升了網(wǎng)站的速度。
03 技術(shù)債務(wù)與重構(gòu)
簡(jiǎn)單來說,重構(gòu)是一種消除或減少技術(shù)債務(wù)的方法。重構(gòu)對(duì)于維護(hù)長(zhǎng)期的代碼質(zhì)量、安全性和性能至關(guān)重要。如果沒有定期進(jìn)行重構(gòu),開發(fā)商將背負(fù)巨額技術(shù)債務(wù)。如果不斷地錯(cuò)過代碼重構(gòu)的時(shí)機(jī),這種債務(wù)也會(huì)不斷地增加,從而使新的開發(fā)越來越困難,特別是在遺留代碼上的開發(fā)。
https://www.stepsize.com/blog/complete-guide-to-technical-debt
04 重構(gòu)度量
使用指標(biāo)可以讓你對(duì)真正需要處理的代碼進(jìn)行優(yōu)先級(jí)排序。它能防止你試圖一次做所有的事情,讓你先專注于最重要的任務(wù)。
此外,你需要度量標(biāo)準(zhǔn)來證明代碼重構(gòu)的有效性——這不僅僅是關(guān)于更改低效代碼的,而是關(guān)于更改低效代碼以增加價(jià)值的。要獲得真正的價(jià)值,你需要單元測(cè)試 (例如失敗的單元測(cè)試數(shù)量) 和功能測(cè)試。其他度量包括發(fā)現(xiàn)更少的 bug 和降低圈復(fù)雜度——重構(gòu)的目標(biāo)應(yīng)該是降低復(fù)雜度。高度復(fù)雜的方法或函數(shù) (例如超過 350 行) 是很好的重構(gòu)目標(biāo)。
在工作流程和任務(wù)方面,也應(yīng)考慮如何讓重構(gòu)適應(yīng)更廣泛的團(tuán)隊(duì)目標(biāo)或里程碑。其中,應(yīng)該包括更小的代碼大小和更容易理解的代碼。
05 代碼重構(gòu)的示例
代碼重構(gòu)的例子有很多,本文受篇幅所限,只關(guān)注其中的幾個(gè):
紅、綠、重構(gòu)
重構(gòu)與單元測(cè)試有著緊密的聯(lián)系。最常見的一種形式是測(cè)試驅(qū)動(dòng)開發(fā) (TDD),現(xiàn)在一提到敏捷方法就會(huì)提到它。它是指在編寫代碼之前先編寫測(cè)試。本質(zhì)上,測(cè)試應(yīng)該驅(qū)動(dòng)編程,說明代碼應(yīng)該做什么。
紅、綠、重構(gòu)是一種 TDD 實(shí)例:
—紅色:寫一個(gè)沒有實(shí)現(xiàn)代碼的測(cè)試套件,確保它失敗。
—綠色:編寫實(shí)現(xiàn)代碼,讓那個(gè)測(cè)試套件通過。
—重構(gòu):尋找優(yōu)化和改進(jìn)代碼的方法。
提取方法
https://refactoring.com/catalog/extractFunction.html
將一段代碼從一個(gè)現(xiàn)有的方法移動(dòng)到一個(gè)新方法中,新方法的命名要能清楚解釋其功能。這種技術(shù)有助于降低代碼的復(fù)雜性和提高代碼的可讀性。
提取變量
https://refactoring.com/catalog/extractVariable.html
如果遇到難以理解的表達(dá)式,或者表達(dá)式在代碼的多個(gè)地方重復(fù),那么提取變量的重構(gòu)方法可以將這樣一個(gè)表達(dá)式結(jié)果或其部分結(jié)果放置到一個(gè)單獨(dú)的變量中,這樣的變量不那么復(fù)雜,也更容易理解。這可以減少?gòu)?fù)雜性和代碼重復(fù)。
抽象分支
https://www.martinfowler.com/bliki/BranchByAbstraction.html
抽象分支是為了以漸進(jìn)的方式對(duì)軟件系統(tǒng)進(jìn)行大規(guī)模的變更,使你可以在變更的同時(shí)定期發(fā)布系統(tǒng)。這消除了在分支上重構(gòu)代碼的復(fù)雜性,否則當(dāng)你試圖合并代碼時(shí),可能會(huì)出現(xiàn)問題。
組合方法
https://scrutinizer-ci.com/docs/refactorings/compose-method
過長(zhǎng)的代碼很難理解,也很難更改。組合方法指的是一系列可用于簡(jiǎn)化方法和刪除重復(fù)代碼的措施。這包括內(nèi)聯(lián)方法、內(nèi)聯(lián)臨時(shí)變量、用查詢替換臨時(shí)變量、拆分臨時(shí)變量和消除對(duì)參數(shù)的賦值。
用查詢替換臨時(shí)變量示例:原代碼:
const basePrice = this._quantity this._itemPrice;if (basePrice > 1000) return basePrice 0.95;else return basePrice 0.98;重構(gòu)為:
get basePrice() {this._quantitythis._itemPrice;}... if (this.basePrice > 1000) return this.basePrice 0.95;else return this.basePrice 0.98拆分臨時(shí)變量代碼示例:原代碼:
let temp = 2 (height + width);console.log(temp);temp = height width;console.log(temp);重構(gòu)為:
const perimeter = 2 (height + width);console.log(perimeter);const area = height width;console.log(area);06 代碼重構(gòu)的工具
你是否需要專門的工具來進(jìn)行重構(gòu)?Martin Fowler 說,自動(dòng)化工具會(huì)有所幫助,但不是必需的。他指出:許多語言的 IDE 都有自動(dòng)化完成許多常見重構(gòu)的功能。它們是我的工具包中非常有價(jià)值的一些工具,它們可以讓我更快地進(jìn)行重構(gòu)。但這些工具不是必需的——我經(jīng)常在沒有工具支持的情況下使用編程語言工作,在這種情況下,我依賴于采取更小的步進(jìn),并使用頻繁的測(cè)試來發(fā)現(xiàn)錯(cuò)誤?!痹S多開發(fā)環(huán)境自動(dòng)化了那些機(jī)械化的重構(gòu)操作。主要的代碼重構(gòu)工具有:
- Visual studio intellicode
- Eclipse IDE
- Spring Tool Suite 4
- Rider
- IntelliJ IDEA
- SonarQube
07 重構(gòu)和對(duì)工程經(jīng)理的挑戰(zhàn)
有些問題會(huì)導(dǎo)致需要重構(gòu),為解決這些問題,需要探索公司是如何運(yùn)作的。在開始重構(gòu)之前,回答以下幾個(gè)問題:
- 什么任務(wù)優(yōu)先級(jí)最高?
- 開發(fā)的速度是什么樣的?
- 開發(fā)人員是否感到快速交付代碼很有壓力?
- 有哪些處理技術(shù)債務(wù)的流程?
- 進(jìn)行了哪些類型的代碼評(píng)審?
- 你的團(tuán)隊(duì)是否具備相應(yīng)的重構(gòu)技能?
- 公司針對(duì)文檔的標(biāo)準(zhǔn)是什么?
如果不解決導(dǎo)致需要重構(gòu)的根本問題,問題只會(huì)擴(kuò)散。
08 高級(jí)管理層對(duì)重構(gòu)的支持
在你的公司,基礎(chǔ)設(shè)施和維護(hù)方面的投資可能不受待見。有些人會(huì)想當(dāng)然地認(rèn)為,花費(fèi)在重構(gòu)上的時(shí)間就是占用了做新工作的時(shí)間。但我們有必要著眼于重構(gòu)所帶來的更大好處,以及它們與工作流、客戶、收入和業(yè)務(wù)增長(zhǎng)之間的關(guān)系。重構(gòu)如果做得好,可以改進(jìn)代碼,使其能夠很好地運(yùn)行,從而交付有效的更新和趨勢(shì)特性,從而吸引新客戶和回訪客戶。這就是軟件公司如何在成功發(fā)布產(chǎn)品后保持競(jìng)爭(zhēng)力的方式。
更好的做法是,量化團(tuán)隊(duì)當(dāng)前花費(fèi)了多少時(shí)間修復(fù)原始代碼中的錯(cuò)誤或 bug,從而從高級(jí)管理人員那里獲得對(duì)重構(gòu)的支持。具體一點(diǎn),是每天一個(gè)小時(shí)嗎?還是一天兩個(gè)小時(shí)?堅(jiān)持記錄至少一周,你可能會(huì)驚訝地發(fā)現(xiàn)你的團(tuán)隊(duì)每年花費(fèi)了好幾周甚至好幾個(gè)月的時(shí)間來修復(fù)遺留代碼。
09 團(tuán)隊(duì)支持和重構(gòu):沖刺還是馬拉松?
你的團(tuán)隊(duì)很難接受重構(gòu)嗎?一提到它,大家就會(huì)抱怨嗎?成功重構(gòu)的最顯著標(biāo)志是有計(jì)劃的、有目的的和文檔化的措施。Ron Jeffries 是極限編程軟件開發(fā)方法論的三位創(chuàng)始人之一,他把重構(gòu)比作清理一塊地):“我們先犁好土地,清除雜草,然后再去播種,也就是構(gòu)建下一個(gè)功能,而不是繞過所有的雜草和灌木叢?!?/p>
https://ronjeffries.com/xprog/articles/refactoring-not-on-the-backlog/
然而,他強(qiáng)調(diào),糟糕的代碼需要很長(zhǎng)時(shí)間來清理,他建議首先要經(jīng)過充分地思考,而不是一頭直接扎進(jìn)去:“我們改進(jìn)我們當(dāng)前用得到代碼,忽略那些用不到的代碼。很可能,我們下一次會(huì)再回來看這塊代碼。通常在同一個(gè)沖刺中,我們會(huì)發(fā)現(xiàn)后續(xù)功能實(shí)際上使用了我們之前清理過的區(qū)域。我們馬上就從增量重構(gòu)中獲益了。如果我們等著大規(guī)模地實(shí)施,就需要投入更多的精力,同時(shí)也推遲了產(chǎn)出收益的時(shí)間,很可能會(huì)把精力浪費(fèi)在不會(huì)帶來收益的地方?!?/p>
產(chǎn)品工程師和 CTO Andreas Klinger 是“周五處理”的粉絲?!爸芪逄幚淼脑瓌t很簡(jiǎn)單:除非你當(dāng)前的項(xiàng)目很忙,否則就利用周五做一些小的改進(jìn)。讓工程師選擇他們要做的工作。不要因?yàn)樘^細(xì)致的管理導(dǎo)致大家失去工作的樂趣。一些人會(huì)嘗試新的類庫(kù)。有些人會(huì)消除待辦事務(wù)中的缺陷。這兩個(gè)都很好。試著促使任務(wù)平衡?!?/p>
無論你的方法是什么,都需要用心思考。問問你的團(tuán)隊(duì)什么代碼最妨礙他們的效率。
- 修改什么代碼對(duì)其他代碼的影響最大?
- 修改什么將帶來最大的回報(bào)?
誰都不可能在重構(gòu)上花費(fèi)大量的時(shí)間而犧牲其他項(xiàng)目,但是不要低估常規(guī)的、一貫的、專門的小型重構(gòu)的影響。積沙成塔,一點(diǎn)一滴堆積起來就會(huì)帶來巨大的好處。
10 文檔和重構(gòu)
標(biāo)準(zhǔn)化命名約定之類的文檔可以確保每個(gè)人形成共同的認(rèn)知。施樂高級(jí)開發(fā)人員在研究重構(gòu)時(shí)發(fā)現(xiàn),缺乏文檔是最大的挑戰(zhàn)之一。
將你重構(gòu)所做的工作記錄下來,可以跟蹤所花費(fèi)的時(shí)間,并為未來的團(tuán)隊(duì)成員提供上下文。同時(shí),把你取得的成功記錄下來——重構(gòu)中取得的最大的勝利是什么?這些可以進(jìn)行同行評(píng)審嗎?
原文鏈接:
https://www.stepsize.com/blog/the-ultimate-engineers-guide-to-refactoring
本文轉(zhuǎn)載自微信公眾號(hào):架構(gòu)頭條。
文章看完,還不過癮?
更多精彩內(nèi)容歡迎關(guān)注百度開發(fā)者中心公眾號(hào)
總結(jié)
以上是生活随笔為你收集整理的工程师必知的代码重构指南的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 百度工程师手把手教你实现代码规范检测工具
- 下一篇: 前端性能优化实践 | 百度APP个人主页