0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

「重構(gòu):改善既有代碼的設(shè)計(jì)」實(shí)戰(zhàn)篇

京東云 ? 來源:jf_75140285 ? 作者:jf_75140285 ? 2024-08-14 10:42 ? 次閱讀

背景

在軟件開發(fā)的世界里,代碼重構(gòu)是提升項(xiàng)目質(zhì)量、適應(yīng)業(yè)務(wù)變化的關(guān)鍵步驟。最近,我重新翻閱了《重構(gòu):改善既有代碼的設(shè)計(jì) 第二版》,這本書不僅重新點(diǎn)燃了我對(duì)重構(gòu)的熱情,還深化了我的理解:重構(gòu)不僅僅是代碼層面的整理,它更是一種軟件開發(fā)的哲學(xué),強(qiáng)調(diào)持續(xù)改進(jìn)和適應(yīng)變化的重要性。

?

書中通過詳細(xì)的案例分析和代碼示例,將理論與實(shí)踐巧妙地融合在一起。我尤其贊賞作者如何將復(fù)雜的重構(gòu)任務(wù)拆解成一系列的小步驟,每一步都被精心設(shè)計(jì)和考慮,大大降低了重構(gòu)過程中的風(fēng)險(xiǎn),同時(shí)提高了整個(gè)過程的可控性。

?

在這篇文章中,我將通過《重構(gòu):改善既有代碼的設(shè)計(jì) 第二版》書中知識(shí)、以及結(jié)合在過去幾年中的重構(gòu)經(jīng)歷(大到系統(tǒng)架構(gòu)、核心接口、底層數(shù)據(jù)存儲(chǔ)、小到簡(jiǎn)單的一個(gè)方法),分享一些關(guān)于重構(gòu)的感悟和心得。通過有真實(shí)的場(chǎng)景、實(shí)際重構(gòu)案例的剖析,我們可以更深刻地理解重構(gòu)不僅是代碼層面的改進(jìn),更是一種思維方式,指引我們?nèi)绾卧诓粩嘧兓臉I(yè)務(wù)需求面前,持續(xù)優(yōu)化和提升軟件的質(zhì)量與效能。

一、重構(gòu)的定義與理念

正確定義問題,比解決問題重要一百倍。那我們首先來搞清楚什么叫重構(gòu)?

作為(名詞),重構(gòu)是指在不改變軟件外在功能的前提下,調(diào)整其內(nèi)部結(jié)構(gòu)的過程。這樣的調(diào)整旨在提高軟件的可理解性和降低修改成本。

作為(動(dòng)詞),重構(gòu)意味著通過一系列細(xì)微的步驟,不斷地調(diào)整軟件結(jié)構(gòu),以保持其設(shè)計(jì)的整潔和可維護(hù)性。

重構(gòu)是一種精練的技藝,它通過小的、計(jì)劃好的修改來減少引入錯(cuò)誤的風(fēng)險(xiǎn)。本質(zhì)上,重構(gòu)是對(duì)已完成的代碼進(jìn)行設(shè)計(jì)上的改進(jìn)。

開展高效有序的重構(gòu),關(guān)鍵的心得是:小的步子可以更快前進(jìn),請(qǐng)保持代碼永遠(yuǎn)處于可工作狀態(tài),小步修改累積起來也能大大改善系統(tǒng)的設(shè)計(jì)。

二、重構(gòu)邊界與時(shí)機(jī)

1)重構(gòu)邊界

在進(jìn)行代碼重構(gòu)時(shí),明確邊界是至關(guān)重要的,以確保重構(gòu)的效果能夠提升代碼質(zhì)量而不引入新的問題

在軟件架構(gòu)中,API(應(yīng)用程序編程接口)和數(shù)據(jù)庫(DB)的設(shè)計(jì)至關(guān)重要,因?yàn)樗鼈兎謩e代表了系統(tǒng)的外部交互界面和內(nèi)部數(shù)據(jù)存儲(chǔ)機(jī)制。良好的設(shè)計(jì)不僅能夠提高系統(tǒng)的穩(wěn)定性、可擴(kuò)展性和可維護(hù)性,而且在未來進(jìn)行代碼重構(gòu)或系統(tǒng)升級(jí)時(shí),也能大大減少對(duì)上游服務(wù)和數(shù)據(jù)遷移的影響。

wKgaoma8GXmAMO9OAAE_PqHz0mw292.png

1.1)API設(shè)計(jì)的重要性

1.抽象層次:API作為系統(tǒng)與外界交互的接口,提供了一層抽象,隱藏了底層的業(yè)務(wù)邏輯和實(shí)現(xiàn)細(xì)節(jié)。這意味著,只要API的接口保持不變,系統(tǒng)內(nèi)部的實(shí)現(xiàn)可以自由變化而不影響外部調(diào)用者。

2.穩(wěn)定性與兼容性:良好設(shè)計(jì)的API應(yīng)該考慮到向后兼容性,即使在系統(tǒng)升級(jí)或重構(gòu)時(shí),也能保證對(duì)現(xiàn)有客戶端的支持。這減少了上游服務(wù)調(diào)整的需要,使得系統(tǒng)的迭代更加平滑。

1.2)數(shù)據(jù)庫設(shè)計(jì)的重要性

1.擴(kuò)展性和可維護(hù)性:隨著系統(tǒng)的發(fā)展,數(shù)據(jù)量會(huì)增加,業(yè)務(wù)需求也會(huì)變化。一個(gè)設(shè)計(jì)良好的數(shù)據(jù)庫能夠更容易地進(jìn)行擴(kuò)展和維護(hù),比如通過合理的索引設(shè)計(jì)、分表分庫等策略來提高性能。

2.數(shù)據(jù)遷移的便利性:在系統(tǒng)升級(jí)或重構(gòu)過程中,可能需要進(jìn)行數(shù)據(jù)遷移。如果數(shù)據(jù)庫設(shè)計(jì)考慮了未來可能的變化,那么數(shù)據(jù)遷移的工作會(huì)相對(duì)容易和安全。合理的數(shù)據(jù)版本控制和遷移腳本也是重要的一環(huán)。

1.3)代碼重構(gòu)的考慮

?分離關(guān)注點(diǎn):即使內(nèi)部代碼結(jié)構(gòu)復(fù)雜或混亂,通過良好設(shè)計(jì)的API和數(shù)據(jù)庫,也可以將內(nèi)部重構(gòu)的影響限制在系統(tǒng)內(nèi)部,避免波及到外部調(diào)用者或?qū)е聰?shù)據(jù)丟失、不一致等問題。

?迭代開發(fā):在保持API接口穩(wěn)定和數(shù)據(jù)庫設(shè)計(jì)前瞻性的前提下,可以更自由地對(duì)內(nèi)部代碼進(jìn)行迭代開發(fā)和重構(gòu),逐步改進(jìn)系統(tǒng)的內(nèi)部質(zhì)量而不影響外部使用者。

?上游和下游的協(xié)調(diào):良好的API和數(shù)據(jù)庫設(shè)計(jì),可以減少在系統(tǒng)升級(jí)或重構(gòu)時(shí)對(duì)上游服務(wù)的影響和對(duì)數(shù)據(jù)庫的數(shù)據(jù)遷移需求。這意味著,即使需要進(jìn)行較大的內(nèi)部修改,也能保障系統(tǒng)的整體穩(wěn)定性和數(shù)據(jù)的一致性。

總之,API和底層數(shù)據(jù)庫的設(shè)計(jì)是軟件架構(gòu)中的關(guān)鍵部分,它們的良好設(shè)計(jì)是確保系統(tǒng)長(zhǎng)期健康發(fā)展的基石。通過投入足夠的時(shí)間和資源來設(shè)計(jì)和實(shí)現(xiàn)高質(zhì)量的API和數(shù)據(jù)庫,可以在系統(tǒng)的整個(gè)生命周期中節(jié)省大量的時(shí)間和成本,尤其是在進(jìn)行必要的代碼重構(gòu)時(shí)。

?

2)為什么要重構(gòu)

提高開發(fā)效率:通過改善代碼的可讀性和可維護(hù)性,重構(gòu)不僅提高了開發(fā)團(tuán)隊(duì)的效率,使其能更快地理解和修改代碼,而且還增強(qiáng)了代碼的靈活性和易修改性,支持敏捷開發(fā)的核心要求——快速響應(yīng)變化。這樣,當(dāng)業(yè)務(wù)需求變動(dòng)時(shí),經(jīng)過良好重構(gòu)的代碼庫能夠迅速適應(yīng)新需求,從而有效促進(jìn)敏捷開發(fā)流程,而不會(huì)阻礙變更。

?

減少后期成本:未經(jīng)重構(gòu)的代碼會(huì)隨著時(shí)間推移越來越難以維護(hù)。在敏捷開發(fā)中,這種情況會(huì)導(dǎo)致迭代速度下降和成本上升。通過定期重構(gòu),可以持續(xù)優(yōu)化代碼結(jié)構(gòu),減少后期的維護(hù)成本。

3)什么時(shí)候重構(gòu)

3.1)線上痛點(diǎn)&風(fēng)險(xiǎn)可控

書中給了一條準(zhǔn)則:第一次做某件事時(shí)只管去做;第二次做類似的事會(huì)產(chǎn)生反感,但無論如何還是可以去做;第三次再做類似的事,你就應(yīng)該考慮重構(gòu)。重構(gòu)的節(jié)奏是小步前進(jìn),保持代碼始終處于可工作狀態(tài),從而大幅改善系統(tǒng)設(shè)計(jì)。

案例:訂單中間件xml節(jié)點(diǎn)解析代碼重構(gòu) 背景:代碼解析xml節(jié)點(diǎn)到處都是,根據(jù)業(yè)務(wù)不同解析不同節(jié)點(diǎn),每次修改的點(diǎn)比較多,并且有時(shí)候容易遺漏,導(dǎo)致線上問題 重構(gòu)前代碼:解析xml代碼各種散亂

重構(gòu)后:節(jié)點(diǎn)解析統(tǒng)一收口

重構(gòu)后效果: 1、重構(gòu)后節(jié)點(diǎn)解析獨(dú)立,每個(gè)節(jié)點(diǎn)對(duì)應(yīng)1個(gè)方法,通用性強(qiáng),以前門檻高,只能專人修改,現(xiàn)在團(tuán)隊(duì)都可修改 2、系統(tǒng)穩(wěn)定性更健壯 3、需求迭代效率更高

?

3.2)預(yù)備性重構(gòu):新需求功能更容易

預(yù)備性重構(gòu)可以讓添加新功能變得更加容易,而幫助理解的重構(gòu)則使代碼更易懂,重構(gòu)的最佳時(shí)機(jī)就在添加新功能之前。在動(dòng)手添加新功能之前,看看現(xiàn)有的代碼庫,此時(shí)經(jīng)常會(huì)發(fā)現(xiàn):如果對(duì)代碼結(jié)構(gòu)做一點(diǎn)微調(diào),未來需求的工作會(huì)容易得多

案例:XXX業(yè)務(wù)層重構(gòu)建設(shè) 背景:現(xiàn)在業(yè)務(wù)識(shí)別散亂在各個(gè)模塊,導(dǎo)致每次業(yè)務(wù)需求,需要了解并修改所有模塊的相關(guān)部分,同時(shí)測(cè)試也需要全模塊覆蓋,增加需求消耗,同時(shí)結(jié)構(gòu)混雜,維護(hù)和新人接收都有一定的困難。

重構(gòu)前代碼方法混亂(總共470行)

重構(gòu)后代碼主方法(52行)職責(zé)清晰

重構(gòu)后效果: 1、長(zhǎng)期價(jià)值:代碼結(jié)構(gòu)清晰、可讀性強(qiáng)、不容易出錯(cuò)、穩(wěn)定性更健壯 2、長(zhǎng)期價(jià)值:需求交付周期提升60+%,之前需求5+人日(需要修改N個(gè)地方),可提升到2人日(統(tǒng)一收口)

3.3)預(yù)備性重構(gòu):數(shù)據(jù)優(yōu)化減負(fù)

在面對(duì)不斷變化的業(yè)務(wù)需求時(shí)。預(yù)備性重構(gòu)不僅僅是對(duì)代碼的改進(jìn),也包括對(duì)數(shù)據(jù)的優(yōu)化和減負(fù)。隨著業(yè)務(wù)的發(fā)展和數(shù)據(jù)的積累,系統(tǒng)中的數(shù)據(jù)量會(huì)不斷增加。這不僅會(huì)增加存儲(chǔ)成本,還可能導(dǎo)致數(shù)據(jù)處理效率下降,進(jìn)而影響系統(tǒng)的響應(yīng)速度和用戶體驗(yàn)。通過預(yù)備性重構(gòu)中的數(shù)據(jù)優(yōu)化減負(fù),我們可以提前解決這些潛在問題,確保系統(tǒng)的可擴(kuò)展性和性能。

案例:X緩存數(shù)據(jù)瘦身 背景:xxx 重構(gòu)前: 緩存:存儲(chǔ)空間使用率60%

重構(gòu)后:存儲(chǔ)空間使用率30% 重構(gòu)效果: 1、提高資源利用率,解決緩存數(shù)據(jù)量大問題(內(nèi)存使用率從60%降低到30%)

2、增強(qiáng)業(yè)務(wù)擴(kuò)展性,為未來的業(yè)務(wù)擴(kuò)展打下堅(jiān)實(shí)的基礎(chǔ)。

?

4)什么時(shí)候不需要重構(gòu)

上面講解了什么時(shí)候時(shí)候重構(gòu),但大部分情況下是不需要重構(gòu)的。比如我看見一堆凌亂的代碼,但日常并不需要修改它而且它也比較穩(wěn)定,那么我就不需要重構(gòu)它。如果丑陋的代碼能被隱藏在一個(gè) API 之下,我就可以容忍它繼續(xù)保持丑陋。只有當(dāng)我有痛點(diǎn)、需要去改動(dòng)的時(shí)候,并且業(yè)務(wù)支撐擴(kuò)展性、改動(dòng)很費(fèi)勁的時(shí)候,有痛點(diǎn)了對(duì)其進(jìn)行重構(gòu)才有價(jià)值。

歸根結(jié)底一句話:有痛點(diǎn)(線上問題、需求開發(fā)復(fù)雜、未來擴(kuò)展性問題)并且重構(gòu)風(fēng)險(xiǎn)可控的前提下,才需要重構(gòu)

案例回顧:xxx重構(gòu)嘗試 背景簡(jiǎn)述: xxx的代碼基礎(chǔ)歷史悠久,承載著復(fù)雜的業(yè)務(wù)邏輯,這些邏輯是經(jīng)過多代開發(fā)人員的手逐漸疊加與優(yōu)化的。隨著時(shí)間的推移,雖然功能日益強(qiáng)大,但代碼結(jié)構(gòu)也變得愈加復(fù)雜,從而提升了維護(hù)的難度和風(fēng)險(xiǎn)。 重構(gòu)目標(biāo): 本次重構(gòu)的主要目標(biāo)是實(shí)現(xiàn)代碼結(jié)構(gòu)的清晰化,以便于后續(xù)的維護(hù)和擴(kuò)展。我們希望通過重構(gòu),將混亂的代碼邏輯整理得更加條理清晰,同時(shí)保持現(xiàn)有功能的穩(wěn)定性。 結(jié)論與決策: 盡管重構(gòu)初衷良好,希望能為后續(xù)的維護(hù)和開發(fā)鋪平道路,但在實(shí)際執(zhí)行過程中,我們遇到了預(yù)期之外的挑戰(zhàn)。在深入測(cè)試重構(gòu)后的代碼時(shí),我們發(fā)現(xiàn)存在多個(gè)之前未被充分考慮的使用場(chǎng)景,這些場(chǎng)景的復(fù)雜性和多樣性超出了原先的預(yù)期。隨著更多場(chǎng)景的出現(xiàn),整體的重構(gòu)風(fēng)險(xiǎn)逐漸升高,不再處于一個(gè)可控的范圍內(nèi)。 經(jīng)過慎重考慮,團(tuán)隊(duì)決定叫停此次重構(gòu)嘗試。我們認(rèn)識(shí)到,在當(dāng)前階段繼續(xù)推進(jìn)重構(gòu),可能會(huì)引入更多不確定性和潛在的風(fēng)險(xiǎn),從而影響到核心業(yè)務(wù)的穩(wěn)定運(yùn)行。雖然這一決定意味著短期內(nèi)仍需應(yīng)對(duì)現(xiàn)有代碼結(jié)構(gòu)的挑戰(zhàn),但從長(zhǎng)遠(yuǎn)來看,確保業(yè)務(wù)的連續(xù)性和穩(wěn)定性是我們的首要任務(wù)。 未來展望: 雖然這次重構(gòu)未能如期完成,但它為我們提供了寶貴的經(jīng)驗(yàn)和教訓(xùn)。我們將繼續(xù)尋找合適的時(shí)機(jī)和方法,以更加細(xì)致和周全的計(jì)劃來逐步優(yōu)化代碼結(jié)構(gòu)。同時(shí),我們也會(huì)加強(qiáng)對(duì)現(xiàn)有代碼的理解和文檔的完善,為未來的重構(gòu)工作奠定堅(jiān)實(shí)的基礎(chǔ)。

?

三、重構(gòu)的實(shí)踐與步驟

軟件重構(gòu)是一個(gè)系統(tǒng)性的過程,涉及到對(duì)現(xiàn)有代碼的一系列改進(jìn)。以下是進(jìn)行重構(gòu)的一些常見實(shí)踐和步驟

1)清晰的重構(gòu)目標(biāo)

明確重構(gòu)的目的和目標(biāo),需要改進(jìn)的區(qū)域。確保團(tuán)隊(duì)成員理解本次重構(gòu)的價(jià)值。比如是因?yàn)榫€上老出問題,還是業(yè)務(wù)支撐復(fù)雜等。

2)逐步重構(gòu)

梳理清晰:在進(jìn)行逐步重構(gòu)的過程中,深入理解現(xiàn)有代碼的功能和設(shè)計(jì)是前提。這不僅包括對(duì)代碼邏輯的把握,還要理解代碼背后的業(yè)務(wù)邏輯和設(shè)計(jì)初衷。只有全面理解了現(xiàn)有系統(tǒng),我們才能確保重構(gòu)的方向和步驟是正確的,同時(shí)避免對(duì)現(xiàn)有功能造成意外的影響。

逐步重構(gòu)的精髓:重構(gòu)并不意味著要一次性進(jìn)行大規(guī)模的改動(dòng)。相反,它是一個(gè)持續(xù)的、逐步的過程,通過細(xì)小且有序的改進(jìn)來優(yōu)化程序的結(jié)構(gòu)。正確的做法是在完全理解現(xiàn)有代碼的基礎(chǔ)上,有條不紊地進(jìn)行改進(jìn),每一次改動(dòng)后都要通過嚴(yán)格且可靠的測(cè)試來確保這些改動(dòng)沒有引入新的錯(cuò)誤。這種方法既可以提高代碼質(zhì)量,又能最大限度地減少對(duì)項(xiàng)目進(jìn)度的影響。

大模型AI輔助重構(gòu):在這個(gè)過程中,充分利用大模型AI技術(shù),可以為重構(gòu)提供有力的支持。AI可以幫助我們快速理解復(fù)雜代碼、發(fā)現(xiàn)潛在的重構(gòu)機(jī)會(huì),甚至直接提供重構(gòu)建議。然而,需要注意的是,AI提供的建議并非總是完全準(zhǔn)確。因此,使用AI技術(shù)輔助重構(gòu)時(shí),應(yīng)將其視為一種參考和輔助工具。我們需要結(jié)合自己對(duì)項(xiàng)目的深入理解,對(duì)AI的建議進(jìn)行評(píng)估和篩選,以確保最終的重構(gòu)方案既符合項(xiàng)目需求,又能有效提升代碼質(zhì)量。

案例:2個(gè)重復(fù)代碼的方法重構(gòu)合并一個(gè) 重構(gòu)前代碼:

AI建議重構(gòu)后代碼如下:

AI詳細(xì)過程如下:

AI生成單測(cè)用例

3)測(cè)試和比對(duì)

在進(jìn)行代碼重構(gòu)時(shí),需要遵循一個(gè)不變的初始步驟:確保待修改代碼具備一套可靠的測(cè)試。這一步至關(guān)重要,因?yàn)殡m然遵循精心設(shè)計(jì)的重構(gòu)策略能夠規(guī)避大多數(shù)引入錯(cuò)誤的風(fēng)險(xiǎn),但作為工程師,出錯(cuò)的可能性始終存在。隨著程序規(guī)模的擴(kuò)大,不經(jīng)意間破壞其他代碼部分的風(fēng)險(xiǎn)也隨之增加。

編寫測(cè)試:確保有充分的測(cè)試覆蓋,涵蓋單元測(cè)試、集成測(cè)試和系統(tǒng)測(cè)試。這些測(cè)試在整個(gè)重構(gòu)過程中,是保障功能穩(wěn)定不受影響的關(guān)鍵。

持續(xù)集成與自動(dòng)化測(cè)試:通過自動(dòng)化測(cè)試和持續(xù)集成,可以確保在重構(gòu)過程中能夠及時(shí)發(fā)現(xiàn)并修正錯(cuò)誤,從而降低引入新錯(cuò)誤的可能性。

R2引流測(cè)試比對(duì)重構(gòu)的測(cè)試本質(zhì)上是一種比對(duì)過程。由于每個(gè)系統(tǒng)的業(yè)務(wù)屬性不盡相同,對(duì)于讀操作,通過引流比對(duì)來驗(yàn)證功能是比較方便的方法。如果涉及到寫操作,如訂單保存等,則需要對(duì)數(shù)據(jù)的各個(gè)關(guān)鍵環(huán)節(jié)進(jìn)行比對(duì)。

回歸測(cè)試:完成上述步驟后,進(jìn)行回歸測(cè)試以確保所有現(xiàn)有功能仍然如預(yù)期般正常工作。

通過這樣一套全面的測(cè)試和驗(yàn)證流程,能夠確保重構(gòu)不僅提升了代碼的可維護(hù)性和清晰度,同時(shí)也保持了系統(tǒng)的穩(wěn)定性和可靠性。這種方法在追求更好代碼結(jié)構(gòu)的同時(shí),也最大限度地減少了對(duì)現(xiàn)有系統(tǒng)功能的影響。

4)切量驗(yàn)證

在進(jìn)行重構(gòu)后的切量驗(yàn)證時(shí),我們可以依據(jù)不同的維度來進(jìn)行靈活的驗(yàn)證,例如用戶標(biāo)識(shí)(pin)、訂單的百分比、倉(cāng)庫等。這樣的切量驗(yàn)證確保了全鏈路的一致性和穩(wěn)定性。

為了更加謹(jǐn)慎地進(jìn)行切量,我們建議采用漸進(jìn)式的計(jì)劃,從較小的比例和較長(zhǎng)的時(shí)間開始,逐步增加。具體的切量步驟可以是:首先從1個(gè)或100個(gè)開始,然后按照1%、5%、10%、30%、50%、80%直至100%的順序逐步擴(kuò)大覆蓋范圍。這種方法可以幫助我們?cè)诿恳徊襟E中細(xì)致地觀察和評(píng)估變更的影響,從而確保重構(gòu)的穩(wěn)定性和效果。

如果在切量過程中遇到任何問題,我們可以利用DUCC開關(guān)快速切換回舊有功能。這種快速回退機(jī)制為我們的重構(gòu)提供了一個(gè)安全網(wǎng),確保了在任何不確定性出現(xiàn)時(shí),我們能夠迅速恢復(fù)服務(wù)的穩(wěn)定性和可靠性,最大限度地減少對(duì)用戶體驗(yàn)的影響。

通過這樣細(xì)致且靈活的切量驗(yàn)證策略,我們不僅能夠確保重構(gòu)的質(zhì)量和穩(wěn)定性,還能夠在發(fā)現(xiàn)問題時(shí)快速響應(yīng),確保服務(wù)的持續(xù)可用性。

5)重構(gòu)后評(píng)估

在完成重構(gòu)工作后,對(duì)重構(gòu)成果進(jìn)行全面評(píng)估是確保目標(biāo)達(dá)成的關(guān)鍵一步。這不僅涉及到驗(yàn)證重構(gòu)是否滿足了預(yù)定目標(biāo),還包括了對(duì)系統(tǒng)性能、代碼可維護(hù)性和可讀性的綜合評(píng)估。

性能評(píng)估:首先,我們需要對(duì)系統(tǒng)的性能進(jìn)行再評(píng)估。這是為了確保重構(gòu)工作沒有導(dǎo)致任何性能上的退步。重構(gòu)的目的往往是為了優(yōu)化和改進(jìn),因此,驗(yàn)證性能是否至少保持不變(如果不是有所提升的話)是至關(guān)重要的。

維護(hù)性評(píng)估:接下來,我們要評(píng)估重構(gòu)是否有效提高了代碼的可維護(hù)性和可讀性。代碼的可維護(hù)性是軟件質(zhì)量的關(guān)鍵指標(biāo)之一,優(yōu)化代碼結(jié)構(gòu)、減少?gòu)?fù)雜度和增強(qiáng)代碼的可讀性都是重構(gòu)的常見目標(biāo)。通過評(píng)估這些方面的改進(jìn),我們可以確定重構(gòu)是否達(dá)到了預(yù)期的效果。

通過遵循這些評(píng)估步驟,重構(gòu)可以以一種有序和系統(tǒng)化的方式進(jìn)行,這不僅最小化了引入新問題的風(fēng)險(xiǎn),還有助于提升軟件的整體質(zhì)量。最終,這將使得軟件更加健壯、易于維護(hù),并且能夠更好地適應(yīng)未來的變化和需求。

四、重構(gòu)的挑戰(zhàn)

盡管重構(gòu)對(duì)維持和提升軟件質(zhì)量至關(guān)重要,但它也伴隨著一定的成本和風(fēng)險(xiǎn)挑戰(zhàn)。理解這些成本和風(fēng)險(xiǎn)對(duì)于成功實(shí)施重構(gòu)計(jì)劃至關(guān)重要。

1)重構(gòu)的成本

1.1)時(shí)間和資源消耗

重構(gòu)是軟件開發(fā)過程中一項(xiàng)至關(guān)重要的工作,但它確實(shí)需要投入相當(dāng)?shù)臅r(shí)間和人力資源,特別是在處理大型項(xiàng)目時(shí)。這種投入有時(shí)可能會(huì)對(duì)新功能的開發(fā)進(jìn)度產(chǎn)生暫時(shí)的影響。開發(fā)團(tuán)隊(duì)必須在維護(hù)既有代碼的穩(wěn)定性和引入新功能之間尋找一個(gè)恰當(dāng)?shù)钠胶恻c(diǎn)。

在重構(gòu)階段,一些新功能可能需要在兩個(gè)不同的代碼基礎(chǔ)上實(shí)施:一是現(xiàn)有的未重構(gòu)代碼,二是正在重構(gòu)的新代碼。以一個(gè)為期三個(gè)月的重構(gòu)周期為例,這期間上線的新功能不僅要在原有的代碼架構(gòu)中實(shí)現(xiàn),還需要在新重構(gòu)的代碼中進(jìn)行相應(yīng)的集成。這實(shí)際上意味著同一個(gè)功能點(diǎn)需要被開發(fā)兩次,以確保功能的連續(xù)性和系統(tǒng)的整體穩(wěn)定性。

這種做法雖然在短期內(nèi)增加了工作量,但從長(zhǎng)遠(yuǎn)來看,是確保軟件質(zhì)量和可持續(xù)發(fā)展的必要步驟。通過這樣的策略,我們可以在不犧牲軟件穩(wěn)定性和用戶體驗(yàn)的前提下,逐步提升代碼質(zhì)量,同時(shí)確保新功能能夠及時(shí)地交付給用戶。

1.2)延緩新功能開發(fā)

尤其是在緊迫的項(xiàng)目截止日期前,重構(gòu)可能會(huì)對(duì)業(yè)務(wù)產(chǎn)生短期內(nèi)的負(fù)面影響。在緊張的開發(fā)周期中,分配資源給重構(gòu)可能會(huì)導(dǎo)致耗時(shí)較長(zhǎng)的新功能延遲開發(fā)。

案例:XXX架構(gòu)升級(jí) 重構(gòu)目標(biāo): 1)打造更清晰的業(yè)務(wù)邊界和更純凈的內(nèi)核計(jì)算邏輯。引入一套高效的時(shí)效計(jì)算緩存機(jī)制,成功地節(jié)省了高達(dá)一半的硬件資源費(fèi)用。 2)增強(qiáng)了系統(tǒng)的復(fù)用性,同一套核心計(jì)算模式能夠適應(yīng)預(yù)約和非預(yù)約兩種不同的業(yè)務(wù)場(chǎng)景,包括結(jié)算、商詳以及下單前后的處理 重構(gòu)成本挑戰(zhàn):面臨的最大挑戰(zhàn)之一是重構(gòu)工作本身的成本,這不僅包括直接的開發(fā)、測(cè)試成本,還有可能因?yàn)橹貥?gòu)而推遲開發(fā)新功能的機(jī)會(huì)成本。時(shí)間成本:從xxxx到xxxx時(shí)候。由于需求的迭代和調(diào)整,我們不得不將上線時(shí)間推遲至N月份,這意味著在這期間新需求需要再重構(gòu)前和重構(gòu)后兩邊都進(jìn)行開發(fā)。

2)重構(gòu)的風(fēng)險(xiǎn)

2.1)引入新的錯(cuò)誤

盡管重構(gòu)的根本目的是提升代碼質(zhì)量,但在修改現(xiàn)有代碼的過程中,總存在引入新錯(cuò)誤的風(fēng)險(xiǎn)。為了盡量避免這種情況,建立嚴(yán)格的測(cè)試流程至關(guān)重要,以確保重構(gòu)過程不會(huì)損害現(xiàn)有功能的正確性和穩(wěn)定性。

在面對(duì)復(fù)雜的歷史代碼和豐富的業(yè)務(wù)場(chǎng)景時(shí),單靠人工梳理和自動(dòng)化測(cè)試可能還不夠,因?yàn)檫@些方法可能會(huì)遺漏一些細(xì)節(jié)。在這種情況下,重構(gòu)測(cè)試的一個(gè)基本原則是進(jìn)行精確的比對(duì):確保重構(gòu)前后,相同的輸入(入?yún)ⅲ?huì)產(chǎn)生相同的輸出(出參)。為了實(shí)現(xiàn)這一點(diǎn),可以充分利用泰山R2流量錄制回放技術(shù)。

通過靈活設(shè)定回放結(jié)果的比對(duì)策略,我們可以有效地減少排錯(cuò)的工作量。例如,確定哪些字段可以忽略不計(jì),哪些輸出字段是核心關(guān)注的點(diǎn)。這要求測(cè)試團(tuán)隊(duì)對(duì)API接口的輸入輸出參數(shù)以及業(yè)務(wù)邏輯非常熟悉,以便能夠制定出合理的比對(duì)策略。根據(jù)不同的測(cè)試場(chǎng)景,可以靈活采用關(guān)鍵字段對(duì)比、結(jié)構(gòu)對(duì)比等多種策略。

R2流量回放的優(yōu)勢(shì)在于,它能夠利用線上的實(shí)際流量來豐富測(cè)試用例,從而使測(cè)試更加精準(zhǔn)和全面。這種方法不僅提高了測(cè)試的效率,還大大增強(qiáng)了測(cè)試的覆蓋范圍,使得重構(gòu)過程更加穩(wěn)健,有效降低了引入新錯(cuò)誤的風(fēng)險(xiǎn)。

?

五、重構(gòu)小技巧

書中通過具體的代碼示例展示了如何執(zhí)行重構(gòu),并解釋了每種重構(gòu)的動(dòng)機(jī)、做法和效果。以下是一些重要的重構(gòu)技術(shù)和案例:

1)提煉函數(shù)(Extract Function)

提煉函數(shù)(Extract Function)是一種重構(gòu)技術(shù),它的目的是將一個(gè)大的函數(shù)拆分成若干個(gè)小的、功能單一的函數(shù)。這樣做可以提高代碼的可讀性、可維護(hù)性,并且可以復(fù)用那些小的函數(shù)。

讓我們通過一個(gè)簡(jiǎn)單的例子來說明這個(gè)概念。假設(shè)我們有一個(gè)函數(shù),它的任務(wù)是為一個(gè)在線商店的用戶創(chuàng)建一個(gè)賬戶,并發(fā)送一封歡迎郵件。

重構(gòu)前:

public class AccountService {
    public void createAccount(String email, String username, String pwd) {
        if (email == null || email.isEmpty()) {
            throw new IllegalArgumentException("Email cannot be empty.");
        }
        if (username == null || username.isEmpty()) {
            throw new IllegalArgumentException("Username cannot be empty.");
        }
        if (pwd == null || pwd.isEmpty()) {
            throw new IllegalArgumentException("pwd cannot be empty.");
        }
        
        // 在這里插入數(shù)據(jù)庫操作代碼,創(chuàng)建賬戶
        
        // 發(fā)送歡迎郵件
        String welcomeMessage="Dear " + username + ", welcome to our service!";
        // 在這里插入郵件發(fā)送代碼
    }
}

在這段代碼中,createAccount方法同時(shí)負(fù)責(zé)驗(yàn)證輸入、創(chuàng)建賬戶和發(fā)送郵件。我們可以通過提煉函數(shù)來拆分這個(gè)方法。

重構(gòu)后:

public class AccountService {
    public void createAccount(String email, String username, String pwd) {
        validateAccountDetails(email, username, pwd);
        insertAccountIntoDatabase(email, username, pwd);
        sendWelcomeEmail(username);
    }

    private void validateAccountDetails(String email, String username, String pwd) {
        if (email == null || email.isEmpty()) {
            throw new IllegalArgumentException("Email cannot be empty.");
        }
        if (username == null || username.isEmpty()) {
            throw new IllegalArgumentException("Username cannot be empty.");
        }
        if (pwd == null || pwd.isEmpty()) {
            throw new IllegalArgumentException("pwd cannot be empty.");
        }
    }

    private void insertAccountIntoDatabase(String email, String username, String password) {
        // 在這里插入數(shù)據(jù)庫操作代碼,創(chuàng)建賬戶
    }

    private void sendWelcomeEmail(String username) {
        String welcomeMessage="Dear " + username + ", welcome to our service!";
        // 在這里插入郵件發(fā)送代碼
    }
}

在重構(gòu)后的代碼中,我們將createAccount方法中的三個(gè)主要任務(wù)分別提煉到了三個(gè)獨(dú)立的私有方法中。每個(gè)方法都有明確的職責(zé):驗(yàn)證賬戶信息、插入賬戶到數(shù)據(jù)庫和發(fā)送歡迎郵件。這樣的代碼更加清晰,每個(gè)部分都更容易理解和測(cè)試。此外,如果將來我們需要在其他地方驗(yàn)證賬戶信息或發(fā)送郵件,我們可以復(fù)用這些已經(jīng)提煉出來的方法,增加了代碼的可重用性。

2)內(nèi)聯(lián)函數(shù)(Inline Function)

內(nèi)聯(lián)函數(shù)(Inline Function)是一種重構(gòu)技術(shù),用于將一個(gè)函數(shù)的內(nèi)容移動(dòng)到該函數(shù)被調(diào)用的地方,然后移除原函數(shù)。這種技術(shù)通常用于當(dāng)一個(gè)函數(shù)的體積非常小,而且只被使用一次或者函數(shù)的內(nèi)容幾乎和它的名字一樣清晰時(shí)。

下面我們通過一個(gè)例子來說明內(nèi)聯(lián)函數(shù)的重構(gòu)過程。

重構(gòu)前的代碼

在這個(gè)例子中,我們有一個(gè)LogisticsService類,它有一個(gè)calculateShippingCost方法,這個(gè)方法只是簡(jiǎn)單地調(diào)用了另一個(gè)方法getBaseShippingCost。如果getBaseShippingCost方法只在這里被調(diào)用,我們就可以考慮使用內(nèi)聯(lián)函數(shù)。

public class LogisticsService {
    public double processOrder(Order order) {
        // 其他處理邏輯...
        doubleshippingCost= calculateShippingCost(order);
        // 其他處理邏輯...
        return shippingCost;
    }

    private double calculateShippingCost(Order order) {
        return getBaseShippingCost(order);
    }

    private double getBaseShippingCost(Order order) {
        doublebaseCost=0.0;
     
        return baseCost;
    }
}

重構(gòu)后的代碼

現(xiàn)在我們將calculateShippingCost方法內(nèi)聯(lián)到processOrder方法中,并移除calculateShippingCost方法。

public class LogisticsService {
    public double processOrder(Order order) {
        // 其他處理邏輯...
        double shippingCost= getBaseShippingCost(order);
        // 其他處理邏輯...
        return shippingCost;
    }

    private double getBaseShippingCost(Order order) {
        double baseCost=0.0;
        
        return baseCost;
    }
}

在這個(gè)重構(gòu)后的例子中,我們直接在processOrder方法中調(diào)用getBaseShippingCost來計(jì)算運(yùn)費(fèi),從而去除了多余的calculateShippingCost方法。這樣做簡(jiǎn)化了代碼結(jié)構(gòu),減少了一層不必要的抽象,使得代碼更加直接和清晰。

內(nèi)聯(lián)函數(shù)是一種微妙的重構(gòu)手法,需要謹(jǐn)慎使用,因?yàn)槿绻^度使用,可能會(huì)導(dǎo)致代碼重復(fù)或者降低代碼的可讀性。通常只有當(dāng)一個(gè)函數(shù)不再提供有用的抽象,或者它的內(nèi)容和名稱幾乎同樣描述性時(shí),才應(yīng)該考慮內(nèi)聯(lián)。

3)提煉變量(Extract Variable)

?將表達(dá)式的結(jié)果賦給一個(gè)臨時(shí)變量,以提高表達(dá)式的清晰度。

重構(gòu)前:

if (order.getTotalPrice() - order.getDiscounts() > 100) {
    // 邏輯處理
}

重構(gòu)后:

doublenetPrice= order.getTotalPrice() - order.getDiscounts();
if (netPrice > 100) {
    // 邏輯處理
}

4)內(nèi)聯(lián)變量(Inline Variable)

?如果一個(gè)臨時(shí)變量只被賦值一次,然后被直接使用,可以將其替換為直接使用賦值表達(dá)式。

重構(gòu)前:

doublebasePrice= order.basePrice();
return (basePrice > 1000);

重構(gòu)后:

return order.basePrice() > 1000;

5)引入?yún)?shù)對(duì)象(Introduce Parameter Object)

?將多個(gè)函數(shù)參數(shù)替換為一個(gè)對(duì)象,當(dāng)多個(gè)函數(shù)共享幾個(gè)參數(shù)時(shí)尤其有用,常用context上下文數(shù)據(jù)傳遞

重構(gòu)前:

public void trest(String logPrefix, A a,B b,C c) {
 //業(yè)務(wù)邏輯處理
}


重構(gòu)后:

public void trest(Context context) {
  //業(yè)務(wù)邏輯處理
}


6)分解條件表達(dá)式(Decompose Conditional)

?將復(fù)雜的條件邏輯分解為更清晰的邏輯塊,提高其可讀性。

重構(gòu)前:

public void applyFee(Account account) {
    if (account.getBalance() < 0 && account.isOverdraftEnabled()) {
        account.addFee(OVERDRAFT_FEE);
    }
}

重構(gòu)后:

public void applyFee(Account account) {
    if (shouldApplyOverdraftFee(account)) {
        account.addFee(OVERDRAFT_FEE);
    }
}
private boolean shouldApplyOverdraftFee(Account account) {
    return account.getBalance() < 0 && account.isOverdraftEnabled();
}

7)合并條件表達(dá)式(Consolidate Conditional Expression)

?將多個(gè)條件表達(dá)式合并為一個(gè),簡(jiǎn)化邏輯判斷。

重構(gòu)前:

if (isSpecialDeal()) {
    total = price * 0.95;
} else {
    total = price * 0.98;
}

重構(gòu)后:

total = price * (isSpecialDeal() ? 0.95 : 0.98);

8)移除死代碼(Remove Dead Code)

?刪除不再被使用的代碼,減少維護(hù)負(fù)擔(dān)。

重構(gòu)前:

重構(gòu)后:

?重構(gòu)切量驗(yàn)證完成后,確保老代碼無用,可直接刪除主贈(zèng)老邏輯calcTransferTimeForGift方法以及下面依賴的方法(前提是這些方法沒有其他地方依賴使用)。

書中強(qiáng)調(diào)重構(gòu)不僅僅是改善代碼的過程,也是一種發(fā)現(xiàn)代碼潛在問題、提高設(shè)計(jì)質(zhì)量和促進(jìn)團(tuán)隊(duì)理解的手段。

六、總結(jié)

《重構(gòu):改善既有代碼的設(shè)計(jì) 第二版》是一本值得每位專業(yè)程序員閱讀的指南。這本書深入探討了重構(gòu)的概念、過程、技術(shù)和案例,旨在指導(dǎo)開發(fā)者如何通過一系列小的、控制風(fēng)險(xiǎn)的代碼修改來逐步改進(jìn)代碼的內(nèi)部結(jié)構(gòu),而不改變其外部行為。這不僅提升了軟件的業(yè)務(wù)價(jià)值和靈活性,也使我們成為了能夠?qū)懗鋈祟愐子诶斫獯a的優(yōu)秀程序員。

如果您有任何其他關(guān)于重構(gòu)的建議或想法,歡迎評(píng)論交流,謝謝!

審核編輯 黃宇

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 軟件開發(fā)
    +關(guān)注

    關(guān)注

    0

    文章

    586

    瀏覽量

    27278
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4671

    瀏覽量

    67771
  • 代碼重構(gòu)
    +關(guān)注

    關(guān)注

    0

    文章

    2

    瀏覽量

    1353
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    代碼整潔之道-大師眼中的整潔代碼是什么樣

    幾個(gè)月前寫了一文章“如何寫出難以維護(hù)的代碼”,從中能大概了解到不好維護(hù)的代碼是什么樣,有哪些壞味道,那肯定有人會(huì)反問,難以維護(hù)的代碼見的太多了,也知道長(zhǎng)什么樣,但是對(duì)于好維護(hù)的
    的頭像 發(fā)表于 09-09 16:30 ?139次閱讀
    <b class='flag-5'>代碼</b>整潔之道-大師眼中的整潔<b class='flag-5'>代碼</b>是什么樣

    工廠高精度人員定位系統(tǒng)改善了哪些方面呢?

    工廠高精度人員定位系統(tǒng)的改善對(duì)于現(xiàn)代工廠管理和生產(chǎn)效率提升具有重要意義。那么,滄穹就在這一文章中便給各位朋友簡(jiǎn)單聊聊這些改善主要體現(xiàn)在以下幾個(gè)方面
    的頭像 發(fā)表于 05-08 14:21 ?192次閱讀
    工廠高精度人員定位系統(tǒng)<b class='flag-5'>改善</b>了哪些方面呢?

    Prometheus實(shí)戰(zhàn)篇:Exporter知識(shí)概述

    所有可以向Prometheus提供監(jiān)控樣本數(shù)據(jù)的程序都可以被稱為一個(gè)Exporter.而Exporter的一個(gè)實(shí)例稱為target,如圖下所示
    的頭像 發(fā)表于 12-25 09:57 ?622次閱讀
    Prometheus<b class='flag-5'>實(shí)戰(zhàn)篇</b>:Exporter知識(shí)概述

    emWin 實(shí)戰(zhàn)指南

    電子發(fā)燒友網(wǎng)站提供《emWin 實(shí)戰(zhàn)指南.pdf》資料免費(fèi)下載
    發(fā)表于 12-22 11:03 ?5次下載

    實(shí)戰(zhàn)篇—戴維南等效電路的驗(yàn)證

    先將所求電路內(nèi)電源“置零”(電壓源短路,電流源開路),然后外加電源,測(cè)量端口電壓和電流,比值即為等效電阻,電路圖如下(以電壓源為例,外加恒流源)
    的頭像 發(fā)表于 12-06 11:03 ?2762次閱讀
    <b class='flag-5'>實(shí)戰(zhàn)篇</b>—戴維南等效電路的驗(yàn)證

    實(shí)戰(zhàn)篇—LM317實(shí)現(xiàn)恒流源輸出25mA電流

    兩種封裝的管腳使用是一致的,從上圖可以看出三個(gè)管腳分別被命名了I、O、A
    的頭像 發(fā)表于 12-06 10:57 ?6183次閱讀
    <b class='flag-5'>實(shí)戰(zhàn)篇</b>—LM317實(shí)現(xiàn)恒流源輸出25mA電流

    新能源電源設(shè)計(jì)磁技術(shù)實(shí)戰(zhàn)應(yīng)用最前沿

    電子發(fā)燒友網(wǎng)站提供《新能源電源設(shè)計(jì)磁技術(shù)實(shí)戰(zhàn)應(yīng)用最前沿.pdf》資料免費(fèi)下載
    發(fā)表于 11-07 16:57 ?1次下載

    STM32Cube CubeIDE添加代碼點(diǎn)亮LED

    前一已經(jīng)生成了CubeIDE的工程代碼,接下來就要用CubeIDE打開,添加點(diǎn)亮LED燈的代碼了。
    的頭像 發(fā)表于 11-06 14:40 ?1103次閱讀
    STM32Cube CubeIDE添加<b class='flag-5'>代碼</b>點(diǎn)亮LED

    STM32庫開發(fā)實(shí)戰(zhàn)指南

    STM32庫開發(fā)實(shí)戰(zhàn)指南-劉火良,電子 epub格式,清晰非掃描
    發(fā)表于 10-27 16:25 ?20次下載

    LabVIEW入門與實(shí)戰(zhàn)開發(fā)100例

    LabVIEW入門與實(shí)戰(zhàn)開發(fā)100例,實(shí)用例子
    發(fā)表于 10-26 15:25 ?39次下載

    HIP失效分析、HIP解決對(duì)策及實(shí)戰(zhàn)案例

    本文涵蓋HIP失效分析、HIP解決對(duì)策及實(shí)戰(zhàn)案例。希望您在閱讀本文后有所收獲,歡迎在評(píng)論區(qū)發(fā)表您的想法。
    的頭像 發(fā)表于 10-16 15:06 ?540次閱讀
    HIP失效分析、HIP解決對(duì)策及<b class='flag-5'>實(shí)戰(zhàn)</b>案例

    電阻維修檢測(cè)實(shí)戰(zhàn)

    電阻維修檢測(cè)實(shí)戰(zhàn)
    發(fā)表于 10-15 11:23 ?3次下載

    實(shí)戰(zhàn)篇:IO設(shè)備

    通常我們認(rèn)為以計(jì)算機(jī)CPU為核心,其外部的所有的設(shè)備都可以稱為是外部輸入輸出設(shè)備。
    的頭像 發(fā)表于 10-11 10:13 ?369次閱讀
    <b class='flag-5'>實(shí)戰(zhàn)篇</b>:IO設(shè)備

    ZigBee無線網(wǎng)絡(luò)技術(shù)入門與實(shí)戰(zhàn)代碼

    電子發(fā)燒友網(wǎng)站提供《ZigBee無線網(wǎng)絡(luò)技術(shù)入門與實(shí)戰(zhàn)代碼.rar》資料免費(fèi)下載
    發(fā)表于 10-09 17:11 ?0次下載
    ZigBee無線網(wǎng)絡(luò)技術(shù)入門與<b class='flag-5'>實(shí)戰(zhàn)</b><b class='flag-5'>代碼</b>

    FreeRTOS內(nèi)核實(shí)現(xiàn)與應(yīng)用開發(fā)實(shí)戰(zhàn)指南

    本書是野火嵌入式教學(xué)叢書“RTOS 內(nèi)核實(shí)現(xiàn)與應(yīng)用開發(fā)實(shí)戰(zhàn)指南的”FreeRTOS 版本,其中機(jī)械工業(yè)出版社出版的《RT-Thread 內(nèi)核實(shí)現(xiàn)與應(yīng)用開發(fā)實(shí)戰(zhàn)指南—基于 STM32》是該書的姐妹
    發(fā)表于 09-28 08:05