淺談遺留代碼的重構(gòu)

背景

《重構(gòu)》誕生至今有近17個年頭了,日常開發(fā)中大家談到重構(gòu),要么非常隨意,認(rèn)為重構(gòu)就是改代碼;要么非常謹(jǐn)慎,把重構(gòu)描述成焦油坑,像瘟神一樣敬而遠(yuǎn)之。針對最具挑戰(zhàn)性的遺留代碼重構(gòu),有哪些需要注意的呢?

談?wù)撊魏问虑?,都該有它的上下文。本文談?wù)摰募夹g(shù)背景是大型通信類產(chǎn)品,對于互聯(lián)網(wǎng)產(chǎn)品不一定適用。另外,本文也不會涉及重構(gòu)技術(shù),有興趣讀者可以讀《重構(gòu)》或者《Effective Refactoring in C++》。

遺留代碼重構(gòu)決策表

遺留代碼的重構(gòu)屬于《重構(gòu)與收拾屋子》提到的“大掃除”或“裝修”場景。對遺留代碼進行重構(gòu),很容易形成“吃力不討好”的局面,究其原因,我們先回顧下重構(gòu)的目的:

  • 提高可理解性
  • 降低修改成本

這兩點,無論從可驗證性,還是可被度量角度都比較困難。如果項目僅以短期結(jié)果度量,重構(gòu)成果很難自證明。再加之改動較大,可能引入一系列不確定因素,無功還有過,自然吃力不討好。所以我們在進行遺留代碼重構(gòu)時要充分考慮收益和風(fēng)險,收益盡量考慮可被驗證、被度量要素,風(fēng)險充分考慮成本、時間、范圍等項目關(guān)注要素。在一個工程師話語權(quán)不是那么大的公司,這一點尤為重要。

基于上述場景分析,定義了遺留代碼重構(gòu)決策表:

refactor-decision-list

從重構(gòu)帶來的收益和風(fēng)險兩個維度,綜合考量、打分,給出一個簡單、可度量、易被執(zhí)行的決策表。下面我們逐一分析下每條決策項:

收益

  1. 性能瓶頸

看到這條,你一定很不解:一些經(jīng)驗也告訴我們,軟件的擴展性,常會犧牲一些性能;再看看《重構(gòu)》書中一段描述:

為了讓軟件易于理解,你常會做出一些使程序運行變慢的修改

而更好的可讀性及好的擴展性,恰是重構(gòu)追求的,豈不是自相矛盾?

關(guān)于性能優(yōu)化,我會在另一篇文章中詳細(xì)闡述,我們先看結(jié)果,重構(gòu)會給我們帶來如下在性能方面的改善:

  • 結(jié)構(gòu)良好的代碼,在性能分析時有更細(xì)的粒度,更容易發(fā)現(xiàn)性能瓶頸
  • 邏輯清晰的軟件,更容易反映軟件業(yè)務(wù)本質(zhì),而清楚我們真正要解決的問題,對性能往往有意想不到的提升
  • 對軟件結(jié)構(gòu)的調(diào)整,使得對象及對象之間的關(guān)系更合理,可以大量減少內(nèi)存浪費
  • 多核、分布式場景下,性能的瓶頸往往不是計算本身,而是不合理的調(diào)度,對軟件結(jié)構(gòu)的調(diào)整,可以從根本上解除該部分約束

另外,性能優(yōu)化成果很容易被度量。

  1. 高危、高頻故障

看到這條,你又開始不解了,重構(gòu)是“在不改變軟件可觀察行為的前提下”進行的,而故障本身就是軟件在特定場景下的錯誤行為,所以重構(gòu)是改變不了故障本身的。那對高危、高頻故障模塊,重構(gòu)的價值在哪里呢?

  • 某模塊故障總是消滅一波,又來一波,攻不死,殺不完,一方面,說明該模塊需求變化還是很頻繁的,另一方面,說明模塊設(shè)計出了問題,要么是邏輯混亂,要么是內(nèi)部耦合太大,這些都可以通過重構(gòu)來消除。
  • 重構(gòu)的一個目的是“提高可理解性”,邏輯清晰、整潔的代碼,使故障就像白墻上的蒼蠅,很容易發(fā)現(xiàn),解決。
  • 重構(gòu)的另一個目的是“降低修改成本”,軟件容易修改,需要軟件遵循開放封閉原則,修改代碼不影響原有功能,也就避免了增加功能、修改故障引入的新問題。
  • 故障數(shù)是一個容易度量的指標(biāo),效果很容易可視化。
  1. 新功能擴展困難

軟件之所以需要設(shè)計,而不僅僅實現(xiàn)功能,一方面可以被復(fù)用;另一方面容易增加功能。新增功能困難,并非是無法增加功能,而是,增加功能需要改動很多代碼,從而帶來更多風(fēng)險,更大維護成本。

重構(gòu)通過對軟件內(nèi)部結(jié)構(gòu)的調(diào)整,不斷消除重復(fù),局部化影響,使得新增功能對原有功能影響盡量小。

  1. 代碼邏輯混亂,可讀性差

編寫易讀、易理解的代碼,并不像說的那么容易,因為它是反直覺的,它產(chǎn)生的價值不是對當(dāng)下的自己,而是以后的自己或者其他人,需要換位思考。

簡單分享下自己對編碼認(rèn)識的幾個階段:

  1. 實現(xiàn)功能,追求性能
  2. 考慮擴展性,增加功能比較容易
  3. 考慮易理解,維護代碼比較容易
  4. 考慮易復(fù)用,除了自己,期望他人也可以用

重構(gòu)對代碼易理解性帶來的收益:

  • 對代碼重構(gòu)的過程,是對代碼所表述業(yè)務(wù)邏輯再理解的過程。
  • 易理解的代碼,更容易發(fā)現(xiàn)業(yè)務(wù)本質(zhì)
  1. 人員能力提升

這里的人員能力提升包括兩個方面:

  1. 業(yè)務(wù)能力提升。重構(gòu)過程中是對業(yè)務(wù)邏輯再理解的過程,通過一層層抽絲剝繭,我們也更了解業(yè)務(wù)本身。
  2. 技術(shù)能力提升。無論是重構(gòu)到Clean Code,還是重構(gòu)到模式,我們的抽象能力、設(shè)計能力會伴隨著這個過程逐漸提升。

風(fēng)險

任何一件事,當(dāng)我們看到收益的同時,應(yīng)該評估它帶來的風(fēng)險。對于遺留代碼的重構(gòu),在動工之前,我們需要回答如下問題:

  • 重構(gòu)的主要目標(biāo)是什么?因為在重構(gòu)過程中,難免會遇到抉擇和舍棄,如果沒想清楚我們的主要目標(biāo),容易搖擺不定或者迷失了方向。
  • 重構(gòu)的范圍是什么?重構(gòu)最容易掉入的一個陷阱就是,重構(gòu)范圍越來越大,大到無法收手。
  • 重構(gòu)的計劃是什么?雖然重構(gòu)過程中,有太多的不確定因素,極端場景下,重構(gòu)的結(jié)果給當(dāng)初認(rèn)為的完全不一樣,但我們確實需要一個時間盒,在它的約束下,我們更容易集中精力達(dá)成我們預(yù)期的目標(biāo)。
  • 重構(gòu)真的必要嗎?有沒有低成本的替代方案?雖然我們鼓勵用技術(shù)解決問題,但生活中的確存在很多在研發(fā)來看很重要,從商業(yè)角度“然并卵”的事。

想清楚上面的問題后,繼續(xù)考慮如下維度:

  1. 人員支撐情況

人是重構(gòu)的核心資源,靠譜的人才能做出靠譜的產(chǎn)品。一方面,重構(gòu)的質(zhì)量、完成的速度依賴人,另一方面,重構(gòu)過后代碼的維護及架構(gòu)的演進也依賴人。需考慮如下幾個方面:

  • 重構(gòu)要求不能改變軟件的外部行為,我們還期望通過重構(gòu)可以簡化設(shè)計,縮小業(yè)務(wù)與實現(xiàn)之間的Gap,這就需要有熟悉業(yè)務(wù)人員。你可能會說:“業(yè)務(wù)全在代碼里了,自己看不就行了”,說的沒錯,只是太累了
  • 嚴(yán)格按照重構(gòu)手法,基本可以做到重構(gòu)前后業(yè)務(wù)邏輯的一致,這就需要至少有人熟悉重構(gòu)技法。
  • 高效率來自專注,如果不能全身心投入,或者任務(wù)不斷切換,結(jié)果往往勞力又勞心。
  • 團隊中有Tech Lead,不但可以幫助提升團隊重構(gòu)技能,在團隊產(chǎn)生技術(shù)爭執(zhí)時,還可以進行裁決。
  • QA是團隊交付產(chǎn)品質(zhì)量的最后一道防線,如果重構(gòu)過程中,能不斷得到對重構(gòu)質(zhì)量的反饋,可以大大降低重構(gòu)帶來的風(fēng)險。
  1. 重構(gòu)周期

每個產(chǎn)品都有版本計劃及市場使命。如果產(chǎn)品即將退市,對它進行的重構(gòu),無疑是沒有任何意義的,因為重構(gòu)后的軟件已經(jīng)沒有上場表演的機會。重構(gòu)需要根據(jù)市場需求和重構(gòu)時間,選擇能切入的時機。比較有效的一個方法是Small Step重構(gòu),把重構(gòu)任務(wù)進行拆解,切分到一個個迭代中增量完成。

遙遙無期的重構(gòu),由于項目看不到短期收益,容易動搖支持重構(gòu)的決心;另外,在重構(gòu)期間,可能還不斷有新功能加入,為了做到可以替代原有產(chǎn)品,在重構(gòu)同時,還需要不斷追趕這些功能,巨大的壓力,容易使團隊身心疲憊。

  1. 代碼度量數(shù)據(jù)

平均圈復(fù)雜度、函數(shù)平均行數(shù)、代碼總行數(shù)、重復(fù)度等代碼度量,可以作為是否進行重構(gòu)的參考,也是預(yù)估重構(gòu)周期的一個重要指標(biāo)。另外,重構(gòu)過程中,在CI部署代碼度量檢查,可以看到代碼復(fù)雜度不斷下降,提升堅持重構(gòu)的信心。

  1. 自動化測試包圍情況

保證重構(gòu)“不改變軟件可觀察行為”最有效的舉措,就是待重構(gòu)代碼已經(jīng)有大量自動化測試用例包圍??紤]如下情況:

  • 測試用例最好是基于業(yè)務(wù)進行拆分,并且覆蓋場景比較全面
  • 測試框架支持不同平臺,可以減少重構(gòu)對平臺環(huán)境的依賴,自由選擇
  • 如果已有測試用例執(zhí)行速度較快,可以保證重構(gòu)有更好的節(jié)奏感。

如果測試用例覆蓋場景較少,不推薦補充完所有場景測試用例后再進行重構(gòu)。一個推薦的做法是,按照重構(gòu)計劃,先補充某個場景用例,然后對其進行重構(gòu),交付后繼續(xù)進行下一個場景,循環(huán)迭代,直到所有場景都完成。

另外,在CI中部署分支覆蓋率監(jiān)控工具,可以感知到分支覆蓋情況逐漸變好,在代碼重構(gòu)完成同時,也交付了一份自動化測試用例(當(dāng)然,分支覆蓋率僅能保證分支被跑到,并不能保證邏輯正確)。

遺留代碼重構(gòu)決策表(Excel版)

下載地址:
https://github.com/liyongshun/refactor/blob/master/refactor_decision_list.xlsx

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,316評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,481評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,241評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,939評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,697評論 6 409
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,182評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,247評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,406評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,933評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,772評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,973評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,516評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,638評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,866評論 1 285
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,644評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,953評論 2 373

推薦閱讀更多精彩內(nèi)容