日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

好的重构方法才能摆脱“屎山”

發(fā)布時間:2023/12/4 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 好的重构方法才能摆脱“屎山” 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

大家好,我是Z哥。

最近在整理一些項(xiàng)目,所以相關(guān)的文章寫的多了些。之前的相關(guān)文章有《聊聊單元測試》,感興趣的話可以點(diǎn)擊文末鏈接去閱讀。

這次整理項(xiàng)目的時候,做了比較多的codereview和重構(gòu)。好久沒做這么高強(qiáng)度了重構(gòu)了,所以對重構(gòu)這件事有了新的思考和理解。

突然發(fā)現(xiàn)叫我們程序員“碼農(nóng)”還挺形象的,因?yàn)閷懘a和種田很像,想有個好收成,就要好好管理代碼,讓它們井井有條。

吳軍老師在《文明之光》里講到一個「壟耕種植法」,它由中國人發(fā)明,后發(fā)揚(yáng)到全球,影響了全世界的糧食生產(chǎn)。據(jù)說歐洲人民以前是把種子隨意地撒在地里,任其自由生長,結(jié)果收成很低,如果種下20斤,大概只能收獲60斤左右糧食。而中國早在先秦時期畝產(chǎn)最少都在240斤以上,最新的數(shù)據(jù)是今年11月初袁隆平的雜交水稻,早晚稻加起來達(dá)到3000斤,這都得益于「壟耕種植法」。

所以,當(dāng)你看到那些被隨意“播種”的糟糕代碼,是改,還是不改?改吧,花時間;不改吧,就像上面的歐洲人民。

其實(shí)很多人對「重構(gòu)」的理解還有些誤區(qū)。「重構(gòu)」僅僅是所謂的優(yōu)化代碼嗎?并不是。

Martin Fowler大神在他的《重構(gòu)》一書中對「重構(gòu)」的定義就非常準(zhǔn)確。

重構(gòu)(名詞):對軟件內(nèi)部結(jié)構(gòu)的一種調(diào)整,目的是在不改變軟件可觀察行為的前提下,提高其可理解性,降低其修改成本。?

重構(gòu)(動詞):使用一系列重構(gòu)手法,在不改變軟件可觀察行為的前提下,調(diào)整其結(jié)構(gòu)。

《重構(gòu)》Martin Fowler

所以,重構(gòu)不僅僅是修改代碼,是對軟件結(jié)構(gòu)的調(diào)整,修改代碼只是其中的一個手段而已。

那么具體應(yīng)該怎么做呢?在這之前,需要考慮清楚以下幾個問題。

/01 ?什么時候重構(gòu)?/

很多理想主義者認(rèn)為的理想情況自然是隨時發(fā)現(xiàn)壞代碼就重構(gòu)。但是這里存在兩個問題:

  • 有很多客觀因素導(dǎo)致了就算發(fā)現(xiàn)了壞代碼,也不一定有充足的時間來修改。

  • 不同的人代碼水平不一,一個人看起來沒毛病的代碼,可能在其他人眼里卻是需要重構(gòu)的代碼。

所以我們需要幾個更加客觀的外部標(biāo)準(zhǔn),Z哥建議你可以從以下三個方面來觀察,如果發(fā)現(xiàn)了類似的現(xiàn)象,說明它在給你發(fā)出需要重構(gòu)的信號。

  • 增加新功能的時候。此時,你發(fā)現(xiàn)既有的代碼無法讓你輕松添加新特性,需要花30%以上的時間做一些重復(fù)性的編碼。

  • 修bug的時候。此時,你發(fā)現(xiàn)排查邏輯非常困難,需要花費(fèi)半小時甚至是數(shù)小時才能搞清楚代碼在處理什么。

  • 當(dāng)從優(yōu)秀的程序員口中說出覺得某段的代碼寫的太shit。(普通人的shit可能是到了無可救藥的地步了,優(yōu)秀的人覺得shit大概率還有救,否則他估計就離職不干了~)

/02 ?怎么重構(gòu)?/

為了保證重構(gòu)的質(zhì)量,在你重構(gòu)的過程中,一定要關(guān)注以下4個關(guān)鍵點(diǎn):

  • 始終工作。這其實(shí)也是《重構(gòu)》中提到的理念,“「不改變軟件可觀察行為」的前提下”。如果你的重構(gòu)需要大刀闊斧的進(jìn)行,會導(dǎo)致很長一段時間軟件無法運(yùn)行起來,那么這就不是一個好的重構(gòu)方式,因?yàn)樵诤荛L一段時間里你都不知道它會不會走向萬劫不復(fù)的“深淵”。(有沒有遇到過越重構(gòu)越糟糕的經(jīng)歷?歡迎分享你的吐槽)

  • 持續(xù)集成:很多人會將重構(gòu)單獨(dú)作為一個版本去做,其實(shí)這樣會有一個新的問題,就是后續(xù)合版本是個痛苦的事情,而且容易出錯。所以,應(yīng)該就在平時的版本里去做重構(gòu),讓每一次重構(gòu)都可以跟著CI/CD持續(xù)進(jìn)行。

  • 隨時中止:不管你的重構(gòu)代碼寫到什么階段,只要編譯不報錯就可以隨時中止,立馬切換到功能開發(fā)。只有達(dá)到這個標(biāo)準(zhǔn),你的Leader才不會對重構(gòu)又愛又恨。

  • 過程可逆:假如我的重構(gòu)出現(xiàn)了重大缺陷,它是可以快速回退的,而不需要從之前的版本當(dāng)中去撈代碼。畢竟,誰都無法100%保證每一次的重構(gòu)都是perfect的。

可以回想一下,你之前做過的重構(gòu)是否都符合了以上的這些要求?反正Z哥最近做的重構(gòu)是不符合的,所以感覺很累很痛苦~

具體的重構(gòu)工作其實(shí)說起來很簡單,因?yàn)橐欢未a無非就是「輸入?yún)?shù)」、「輸出參數(shù)」、「方法體」3個東西,重構(gòu)也自然以這幾個地方展開。

/01 ?輸入?yún)?shù)/

對于輸入?yún)?shù)的重構(gòu),主要關(guān)注在參數(shù)的個數(shù)上。那些優(yōu)秀的開源項(xiàng)目里,你幾乎看不到參數(shù)很多的方法。

因?yàn)檫^多的參數(shù)個數(shù),不但不容易理解,而且你在寫調(diào)用這個方法的代碼的時候也會很頭疼,時不時要數(shù)一下這是第幾個參數(shù),對應(yīng)的參數(shù)說明是什么。

有一些工具推薦的默認(rèn)參數(shù)最大長度是7個(如SonarQube)。如果你沒有更好的定義和理解,那么不妨以“7”這個標(biāo)準(zhǔn)來執(zhí)行。

/02? 輸出參數(shù)/

輸出參數(shù)只有一個,能夠出亂子的空間也很小,所以一般來說不需要怎么優(yōu)化。

唯一值得提醒的兩點(diǎn)是:

  • 參數(shù)類型盡量用強(qiáng)類型。弱類型的返回值雖然讓你的Function向后兼容性很好,但是也帶來了很多無法在編譯期間被發(fā)現(xiàn)的問題。

  • 不返回不需要的參數(shù)。添加更多參數(shù)在最初肯定是為了“跑在業(yè)務(wù)前面”,但這份好心往往最終帶來的是更多“意料之外的耦合”,導(dǎo)致后續(xù)的重構(gòu)成本大增。

  • /03? 方法體/

    對于方法體的重構(gòu)是花費(fèi)時間最多的地方,具體的方式方法也很多。但是我建議你一定要堅(jiān)持一個核心要點(diǎn),我將它稱為「NRD重構(gòu)法」,這3個字母分別表示:New、Replace、Delete。也就是說,做重構(gòu)的時候不要直接在原來的方法體里改,重新建一個新的方法,然后等單測跑通之后再替換掉老方法,最后再把老方法刪除。

    只要做到這點(diǎn),要滿足前面提到的4個關(guān)鍵點(diǎn),就沒那么困難了。

    具體的重構(gòu)內(nèi)容自然是以減少復(fù)雜度為核心思路去做。衡量代碼復(fù)雜度有一個概念叫「圈復(fù)雜度」(也叫「循環(huán)復(fù)雜度」),在1976年由Thomas J. McCabe, Sr. 提出。現(xiàn)在有不少工具有統(tǒng)計這個指標(biāo)。

    復(fù)雜度大說明程序代碼可能質(zhì)量低且難于測試和維護(hù),根據(jù)經(jīng)驗(yàn),程序的可能錯誤和高的圈復(fù)雜度有著很大關(guān)系。

    復(fù)雜度大的代碼往往伴隨著大量的if/switch/for/foreach/try...catch/while等等。每一次試用都會讓「圈復(fù)雜度」+1,并且其中的條件判斷越多,增加的越快。

    所以,常見的重構(gòu)方式大多以降低代碼的圈復(fù)雜度為主。比如,

    • 將相同邏輯的代碼抽離并封裝到一處,可以避免在多個方法體里增加圈復(fù)雜度,只在一個方法體里增加。

    • 通過AOP技術(shù),不但可以將重復(fù)的代碼剔除出當(dāng)前方法體,還可以將try...catch之類的代碼剔除出去,以降低復(fù)雜度。

    • 通過一些語法糖或者框架,也可以降低復(fù)雜度。如,lambda表達(dá)式。

    • ……

    還有很多小眾的重構(gòu)技巧這里就不贅述了,真是覺得大家都應(yīng)該讀一讀《重構(gòu)》這本書。

    多說一句,不提倡刻意降低代碼行數(shù)的方法,因?yàn)槟愕膹?fù)雜度不下降,減少代碼行數(shù)只是“掩耳盜鈴”而已。

    另外,重構(gòu)有一個最佳伴侶,就是單元測試。你想象一個畫面,當(dāng)你重構(gòu)之前通過率100%的單元測試在重構(gòu)完成后跑一遍,發(fā)現(xiàn)了10%的失敗。此時你的心情肯定是“真香,否則一堆bug等著我修”。

    不過,如果你的代碼「圈復(fù)雜度」越高,單元測試寫起來越費(fèi)勁。如何寫好單元測試可以看我之前寫的文章《聊聊單元測試》。

    最后,怎么判斷重構(gòu)的效果好不好呢?自然是工作效率是否提高了。

    • 增加一個功能或者接口的時間是不是縮短了?

    • 測試那邊回歸測試的平均時間是不是縮短了?

    • ……

    好了,就這么多。如果你還是覺得無從下手,不妨試試《重構(gòu)》作者推薦的一種做法:

    隨機(jī)挑選一個目標(biāo),比如,“去掉一堆不必要的子類”。然后朝著目標(biāo)前進(jìn),沒把握就停下來。當(dāng)你無法證明自己所做的修改能夠保證原有程序的邏輯和語義時,立馬停下來思考:當(dāng)前做的重構(gòu)是改善了?還是毫無成果需要撤銷?

    最后再次強(qiáng)力推薦《重構(gòu)》這本書,里面有很多非常具體的代碼重構(gòu)方法,值得每一位程序員入手一本。

    好了,總結(jié)一下。

    這篇呢,Z哥和你分享了我對代碼重構(gòu)這件事的看法。要想提高你代碼的“產(chǎn)出”,那么就得好好重視重構(gòu)這件事。

    在重構(gòu)代碼的「輸入?yún)?shù)」、「輸出參數(shù)」、「方法體」的時候需要持續(xù)保持以下4個關(guān)鍵點(diǎn):

    • 始終工作

    • 持續(xù)集成

    • 隨時中止

    • 過程可逆

    這才能使得你的重構(gòu)工作平穩(wěn)的進(jìn)行,而不會是一場賭博。

    并且,重構(gòu)方法體的時候要以降低「圈復(fù)雜度」為目的,而不是代碼行數(shù)。如果條件允許,盡量多寫一些單元測試來保障重構(gòu)的穩(wěn)定性。

    希望對你有所啟發(fā)。

    重構(gòu)可以使軟件更容易地被修改和被理解,這個意義甚至大于所謂的“優(yōu)化和改進(jìn)”。Kent Beck大神曾也經(jīng)說過:首先讓代碼架構(gòu)易于改變,然后再進(jìn)行簡單的改進(jìn)。

    如果你想擺脫代碼越改越痛苦的困境,那么趕緊行動起來吧。

    推薦閱讀:

    • 做架構(gòu)也得講武德

    • 聊聊單元測試

    原創(chuàng)不易,如果你覺得這篇文章還不錯,就「在看」或者「分享」一下吧。鼓勵我的創(chuàng)作 :)

    如果你有關(guān)于軟件架構(gòu)、分布式系統(tǒng)、產(chǎn)品、運(yùn)營的困惑

    可以試試點(diǎn)擊「閱讀原文

    總結(jié)

    以上是生活随笔為你收集整理的好的重构方法才能摆脱“屎山”的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。