我們一直在尋找各種方法來清理代碼、降低復(fù)雜性和改善功能。而重構(gòu)為我們指明了前進的方向。
1、什么是重構(gòu)?
Martin Fowler曾出版了兩本有關(guān)重構(gòu)的書籍,他認為:
重構(gòu)指的是,在不改變代碼的外部行為,只改善其內(nèi)部結(jié)構(gòu)的方式下,修改軟件系統(tǒng)的過程。重構(gòu)是一種有條理的清理代碼的方式,可以最大程度地減少引入bug的機會。本質(zhì)上,重構(gòu)意味著在代碼編寫完成后,改進代碼的設(shè)計。
2、重構(gòu)有什么好處?
重構(gòu)源代碼有數(shù)不清的好處。首先,重構(gòu)可以將混亂、不正確和/或重復(fù)的代碼轉(zhuǎn)換成整潔的代碼。它可以解決多位開發(fā)人員協(xié)同工作時可能引發(fā)的代碼標準化問題。重構(gòu)可以提高可讀性,改善源代碼的可維護性以及整體結(jié)構(gòu)和功能。重構(gòu)可以使代碼更易于擴展和添加新功能。刪除不必要的代碼(比如重復(fù)代碼)可以減少代碼所使用的內(nèi)存,并加快執(zhí)行速度。
例如,在2014年,Kickstarter的工程師面臨著一個巨大的挑戰(zhàn):由于用戶數(shù)量呈指迅速增長,導(dǎo)致查詢性能下降。為此,他們將MySQL查詢重構(gòu)為Redis,減少了100毫秒的加載時間,從而減少了加載時間的差異并提高了網(wǎng)站的整體速度。
3、技術(shù)負債與重構(gòu)
簡而言之,重構(gòu)是消除或減少技術(shù)負債的一種方式。
重構(gòu)對于長期維持的代碼質(zhì)量、安全性和性能至關(guān)重要。如果沒有定期的重構(gòu),開發(fā)人員就會承受巨大的技術(shù)負債。重構(gòu)代碼的機會越少,技術(shù)負債就會越多,開發(fā)新功能也會變得越來越難。
4、重構(gòu)的指標
我們可以通過各種指標,衡量重構(gòu)代碼的優(yōu)先級。在指標的幫助下,我們可以有條不紊地計劃重構(gòu),每一次都專心完成最重要的任務(wù)。
此外,你需要通過指標來衡量重構(gòu)的效果。我們不僅需要重構(gòu)低效的代碼,而且還可以通過修改低效代碼增加價值。為了獲得真正的價值,你需要進行測試,包括單元測試和功能測試。除此之外,還有一些其他方面的指標,比如發(fā)現(xiàn)的bug數(shù)減少,以及降低循環(huán)復(fù)雜性(重構(gòu)的目標是降低復(fù)雜性)。高度復(fù)雜的方法或功能(比如超過350行的方法或功能)就是良好的重構(gòu)對象。
此外,我們還需要考慮,如何將重構(gòu)融合到更廣泛的團隊目標或有關(guān)工作流和任務(wù)的里程碑中。
5、代碼重構(gòu)示例
代碼重構(gòu)的示例非常多,為了簡潔起見,我們介紹以下幾種:
紅色,綠色和重構(gòu)
重構(gòu)與單元測試息息相關(guān)。最常見的形式之一就是敏捷方法固有的測試驅(qū)動開發(fā)(Test-Driven Development,即TDD)。你可以在編寫代碼之前先編寫測試。從本質(zhì)上來說,應(yīng)該由測試來驅(qū)動程序,說明代碼應(yīng)該執(zhí)行的操作。
紅色,綠色和重構(gòu)是測試驅(qū)動開發(fā)的一個示例:
紅色:編寫沒有實現(xiàn)代碼的測試套件,必然會失敗。
綠色:編寫實現(xiàn)代碼,剛剛好可以通過測試套件。
重構(gòu):尋找優(yōu)化和改進代碼的方法。
提取方法(又名提取函數(shù))
將代碼片段從現(xiàn)有方法移到新方法中,而新方法的名稱明確說明了其功能。這種技術(shù)有助于降低復(fù)雜性并提高代碼的可讀性,另外《Java開發(fā)手冊(嵩山版)》你需要好好看下。
提取變量
如果遇到難以理解的表達式,或者該表達式在整個代碼中重復(fù)了多次,則可以通過提取變量重構(gòu),將表達式或其中一部分放入一個復(fù)雜度較低且更易于理解的變量中。這樣可以減少復(fù)雜性和代碼重復(fù)。
按抽象建立分支
按抽象建立分支可以逐步對軟件系統(tǒng)進行大規(guī)模地修改,而你則可以一邊修改代碼,一邊定期發(fā)布系統(tǒng)。這種方法可以降低在分支上重構(gòu)代碼的復(fù)雜性,避免在合并代碼時出現(xiàn)問題。
方法組合
代碼過長不便于理解,而且也不方便修改。方法組合指的是一系列的操作,將方法改成順序結(jié)構(gòu)并刪除重復(fù)的代碼。這些操作包括內(nèi)聯(lián)方法、內(nèi)聯(lián)模板、用查詢代替模板、拆分臨時變量以及刪除對參數(shù)的賦值等。
6、重構(gòu)代碼的工具
你需要專業(yè)的重構(gòu)工具嗎?Martin Fowler表示,自動化的工具有幫助但不是必需的。另外,Java 工具系列教程全部整理好了,微信搜索互聯(lián)網(wǎng)架構(gòu)師,在后臺發(fā)送:2T,可以在線閱讀。
他指出:
“許多語言都有IDE,可以自動執(zhí)行許多常見的重構(gòu)。這些是非常有價值的工具,可以幫助我更快地重構(gòu)代碼。但是,這些工具不是必不可少的,我經(jīng)常在沒有工具支持的情況下編寫程序,每次只邁出一小步,并通過頻繁的測試來發(fā)現(xiàn)錯誤?!?/p>
許多開發(fā)環(huán)境都可以自動化重構(gòu),一些常見的重構(gòu)工具包括:
Visual studio intellicodeEclipse IDESpring Tool Suite 4RiderIntelliJ IDEASonarQube
7、重構(gòu)與工程經(jīng)理的難題
為了解決引發(fā)重構(gòu)需求的問題,首先我們需要弄清楚公司的運營方式。另外《Java開發(fā)手冊(嵩山版)》你需要好好看下。在著手重構(gòu)之前,請先回答下列幾個問題:
哪些任務(wù)最優(yōu)先?開發(fā)的速度如何?開發(fā)人員是否感覺到了快速交付代碼的壓力?解決技術(shù)負債的流程都有哪些?實施了哪些類型的代碼審核?團隊成員是否具備適當(dāng)?shù)闹貥?gòu)技能?公司的文檔標準是什么?
如果不解決引發(fā)重構(gòu)需求的根本問題,那么問題只會愈演愈糟。
8、高級管理層對重構(gòu)的支持
你們公司可能并沒有在基礎(chǔ)設(shè)施和維護上投入太多資金。
可能會有人說,應(yīng)該將花費在重構(gòu)上的時間投入到新功能開發(fā)上。
但是,我們?nèi)匀粦?yīng)該看一看重構(gòu)的好處,以及它們與工作流程、客戶、收入和業(yè)務(wù)增長的關(guān)系。重構(gòu)得當(dāng)可以改善代碼,交付有效更新以及急需的功能,從而吸引新客戶和回頭客。即使在成功發(fā)布產(chǎn)品之后,軟件公司也可以通過這種方式保持競爭力。
為了獲取高層管理的支持,還有一個更好的方法,即量化團隊當(dāng)前花費在修復(fù)原始代碼中的錯誤或bug上的時間。具體一點,比如每天一個小時?每天兩個小時?持續(xù)記錄一個星期,你就會驚訝地發(fā)現(xiàn)原來團隊每年需要花費數(shù)周或數(shù)月時間來修復(fù)遺留的代碼。
9、團隊支持與重構(gòu):一個Sprint還是馬拉松?
很難在團隊內(nèi)部開展重構(gòu)工作?提及重構(gòu)就會哀聲載道?順利開展重構(gòu)的最重要的標志就是有計劃、有目標以及有文檔記錄的行動。Ron Jeffries(極限編程的三大創(chuàng)始人之一)將重構(gòu)比喻為清道:
“花些時間清出一條道來,那么下一次我們就可以直奔我們要構(gòu)建的下一個功能,而無需繞過雜草和灌木叢?!?/p>
但是,他強調(diào)指出,糟糕的代碼需要花費很長的時間來清理,而且重構(gòu)應(yīng)該經(jīng)過深思熟慮:
“如果我們只改進手頭的代碼,而忽略目前不涉及的代碼,那么以后必然會走回頭路。”
在同一個Sprint中,我們經(jīng)常發(fā)現(xiàn)后面的功能用到了我們之前清理過的代碼。我們就會立即享受重構(gòu)的好處。如果我們等積攢了一堆技術(shù)負債,再開始重構(gòu),那么我們享受的好處會延遲,甚至可能會在一些沒大有用的地方浪費精力。
產(chǎn)品工程師兼首席技術(shù)官Andreas Klinger是Fix-it Friday的粉絲,他表示:
“Fix-it Friday的規(guī)則很簡單:除非當(dāng)前的項目十萬火急,否則周五的工作就應(yīng)該是重構(gòu)。讓工程師選擇他們的工作。我們不應(yīng)該因為微觀管理而抹殺這種樂趣。有些人會嘗試新的庫。有些人會修復(fù)積壓的bug。這兩種工作都很好。我們嘗試鼓勵大家平衡這些任務(wù)?!?/p>
無論采用哪種方法,你都需要慎重思考,詢問團隊哪些代碼最影響他們的效率。
修復(fù)哪些代碼對你的其他代碼產(chǎn)生的影響最大?解決哪些問題得到的回報最多?你不太可能找到一整塊專門的時間來重構(gòu)代碼,重構(gòu)代碼必然會犧牲你花費在其他項目上的時間,但請不要低估定期堅持開展小范圍的重構(gòu)帶來的影響。聚沙成塔,集腋成裘,最終你會獲得豐厚的回報。
10、文檔與重構(gòu)
標準化命名約定之類的文檔可以讓每個人都達成共識。Xerox的高級開發(fā)人員的研究發(fā)現(xiàn),缺乏文檔是重構(gòu)最大的難題之一。
記錄重構(gòu)的工作內(nèi)容不僅可以記錄花費的時間,而且還可以為將來的團隊成員提供說明。另外,關(guān)注公眾號互聯(lián)網(wǎng)架構(gòu)師,在后臺回復(fù):2T,可以獲取我整理的 Java 系列面試題和答案,非常齊全。
最后,你還通過文檔記錄下自己的成功:重構(gòu)帶來的最大成功是什么?這些可以成為代碼審核的考慮因素嗎?