開發者何時需要重構?

      網友投稿 679 2022-05-30

      在我編程的每個小時,我都會做重構。有幾種方式可以把重構融入我的工作過程里。

      {三次法則}

      Don Roberts給了我一條準則:第一次做某件事時只管去做;第二次做類似的事會產生反感,但無論如何還是可以去做;第三次再做類似的事,你就應該重構。

      正如老話說的:事不過三,三則重構。

      ###預備性重構:讓添加新功能更容易

      重構的最佳時機就在添加新功能之前。在動手添加新功能之前,我會看看現有的代碼庫,此時經常會發現:如果對代碼結構做一點微調,我的工作會容易得多。也許已經有個函數提供了我需要的大部分功能,但有幾個字面量的值與我的需要略有沖突。如果不做重構,我可能會把整個函數復制過來,修改這幾個值,但這就會導致重復代碼——如果將來我需要做修改,就必須同時修改兩處(更麻煩的是,我得先找到這兩處)。而且,如果將來我還需要一個類似又略有不同的功能,就只能再復制粘貼一次,這可不是個好主意。所以我戴上重構的帽子,使用函數參數化(310)

      。做完這件事以后,接下來我就只需要調用這個函數,傳入我需要的參數。

      這就好像我要往東去100公里。我不會往東一頭把車開進樹林,而是先往北開20公里上高速,然后再向東開100公里。后者的速度比前者要快上3倍。如果有人催著你“趕快直接去那兒”,有時你需要說:“等等,我要先看看地圖,找出最快的路徑。”這就是預備性重構于我的意義。

      {--:}——Jessica Kerr

      修復bug時的情況也是一樣。在尋找問題根因時,我可能會發現:如果把3段一模一樣且都會導致錯誤的代碼合并到一處,問題修復起來會容易得多?;蛘?,如果把某些更新數據的邏輯與查詢邏輯分開,會更容易避免造成錯誤的邏輯糾纏。用重構改善這些情況,在同樣場合再次出現同樣bug的概率也會降低。

      ###幫助理解的重構:使代碼更易懂

      我需要先理解代碼在做什么,然后才能著手修改。這段代碼可能是我寫的,也可能是別人寫的。一旦我需要思考“這段代碼到底在做什么”,我就會自問:能不能重構這段代碼,令其一目了然?我可能看見了一段結構糟糕的條件邏輯,也可能希望復用一個函數,但花費了幾分鐘才弄懂它到底在做什么,因為它的函數命名實在是太糟糕了。這些都是重構的機會。

      看代碼時,我會在腦海里形成一些理解,但我的記性不好,記不住那么多細節。正如Ward Cunningham所說,通過重構,我就把腦子里的理解轉移到了代碼本身。隨后我運行這個軟件,看它是否正常工作,來檢查這些理解是否正確。如果把對代碼的理解植入代碼中,這份知識會保存得更久,并且我的同事也能看到。

      重構帶來的幫助不僅發生在將來——常常是立竿見影。我會先在一些小細節上使用重構來幫助理解,給一兩個變量改名,讓它們更清楚地表達意圖,以方便理解,或是將一個長函數拆成幾個小函數。當代碼變得更清晰一些時,我就會看見之前看不見的設計問題。如果不做前面的重構,我可能永遠都看不見這些設計問題,因為我不夠聰明,無法在腦海中推演所有這些變化。Ralph Johnson說,這些初步的重構就像掃去窗上的塵埃,使我們得以看到窗外的風景。在研讀代碼時,重構會引領我獲得更高層面的理解,如果只是閱讀代碼很難有此領悟。有些人以為這些重構只是毫無意義地把玩代碼,他們沒有意識到,缺少了這些細微的整理,他們就無法看到隱藏在一片混亂背后的機遇。

      ###撿垃圾式重構

      幫助理解的重構還有一個變體:我已經理解代碼在做什么,但發現它做得不好,例如邏輯不必要地迂回復雜,或者兩個函數幾乎完全相同,可以用一個參數化的函數取而代之。這里有一個取舍:我不想從眼下正要完成的任務上跑題太多,但我也不想把垃圾留在原地,給將來的修改增加麻煩。如果我發現的垃圾很容易重構,我會馬上重構它;如果重構需要花一些精力,我可能會拿一張便箋紙把它記下來,完成當下的任務再回來重構它。

      當然,有時這樣的垃圾需要好幾個小時才能解決,而我又有更緊急的事要完成。不過即便如此,稍微花一點工夫做一點兒清理,通常都是值得的。正如野營者的老話所說:至少要讓營地比你到達時更干凈。如果每次經過這段代碼時都把它變好一點點,積少成多,垃圾總會被處理干凈。重構的妙處就在于,每個小步驟都不會破壞代碼——所以,有時一塊垃圾在好幾個月之后才終于清理干凈,但即便每次清理并不完整,代碼也不會被破壞。

      ###有計劃的重構和見機行事的重構

      上面的例子——預備性重構、幫助理解的重構、撿垃圾式重構——都是見機行事的:我并不專門安排一段時間來重構,而是在添加功能或修復bug的同時順便重構。這是我自然的編程流的一部分。不管是要添加功能還是修復bug,重構對我當下的任務有幫助,而且讓我未來的工作更輕松。這是一件很重要而又常被誤解的事:重構不是與編程割裂的行為。你不會專門安排時間重構,正如你不會專門安排時間寫if語句。我的項目計劃上沒有專門留給重構的時間,絕大多數重構都在我做其他事的過程中自然發生。

      骯臟的代碼必須重構,但漂亮的代碼也需要很多重構。

      還有一種常見的誤解認為,重構就是人們彌補過去的錯誤或者清理骯臟的代碼。當然,如果遇上了骯臟的代碼,你必須重構,但漂亮的代碼也需要很多重構。在寫代碼時,我會做出很多權衡取舍:參數化需要做到什么程度?函數之間的邊界應該劃在哪里?對于昨天的功能完全合理的權衡,在今天要添加新功能時可能就不再合理。好在,當我需要改變這些權衡以反映現實情況的變化時,整潔的代碼重構起來會更容易。

      每次要修改時,首先令修改很容易(警告:這件事有時會很難),然后再進行這次容易的修改。

      {--:}——Kent Beck

      長久以來,人們認為編寫軟件是一個累加的過程:要添加新功能,我們就應該增加新代碼。但優秀的程序員知道,添加新功能最快的方法往往是先修改現有的代碼,使新功能容易被加入。所以,軟件永遠不應該被視為“完成”。每當需要新能力時,軟件就應該做出相應的改變。越是在已有代碼中,這樣的改變就越顯重要。

      不過,說了這么多,并不表示有計劃的重構總是錯的。如果團隊過去忽視了重構,那么常常會需要專門花一些時間來優化代碼庫,以便更容易添加新功能。在重構上花一個星期的時間,會在未來幾個月里發揮價值。有時,即便團隊做了日常的重構,還是會有問題在某個區域逐漸累積長大,最終需要專門花些時間來解決。但這種有計劃的重構應該很少,大部分重構應該是不起眼的、見機行事的。

      我聽過的一條建議是:將重構與添加新功能在版本控制的提交中分開。這樣做的一大好處是可以各自獨立地審閱和批準這些提交。但我并不認同這種做法。重構常常與新添功能緊密交織,不值得花工夫把它們分開。并且這樣做也使重構脫離了上下文,使人看不出這些“重構提交”的價值。每個團隊應該嘗試并找出適合自己的工作方式,只是要記?。悍蛛x重構提交并不是毋庸置疑的原則,只有當你真的感到有益時,才值得這樣做。

      ###長期重構

      大多數重構可以在幾分鐘——最多幾小時——內完成。但有一些大型的重構可能要花上幾個星期,例如要替換一個正在使用的庫,或者將整塊代碼抽取到一個組件中并共享給另一支團隊使用,再或者要處理一大堆混亂的依賴關系,等等。

      即便在這樣的情況下,我仍然不愿讓一支團隊專門做重構??梢宰屨麄€團隊達成共識,在未來幾周時間里逐步解決這個問題,這經常是一個有效的策略。每當有人靠近“重構區”的代碼,就把它朝想要改進的方向推動一點。這個策略的好處在于,重構不會破壞代碼——每次小改動之后,整個系統仍然照常工作。例如,如果想替換掉一個正在使用的庫,可以先引入一層新的抽象,使其兼容新舊兩個庫的接口。一旦調用方已經完全改為使用這層抽象,替換下面的庫就會容易得多。(這個策略叫作Branch By Abstraction[mf-bba]。)

      ###復審代碼時重構

      一些公司會做常規的代碼復審(code review),因為這種活動可以改善開發狀況。代碼復審有助于在開發團隊中傳播知識,也有助于讓較有經驗的開發者把知識傳遞給比較欠缺經驗的人,并幫助更多人理解大型軟件系統中的更多部分。代碼復審對于編寫清晰代碼也很重要。我的代碼也許對我自己來說很清晰,對他人則不然。這是無法避免的,因為要讓開發者設身處地為那些不熟悉自己所作所為的人著想,實在太困難了。代碼復審也讓更多人有機會提出有用的建議,畢竟我在一個星期之內能夠想出的好點子很有限。如果能得到別人的幫助,我的生活會滋潤得多,所以我總是期待更多復審。

      我發現,重構可以幫助我復審別人的代碼。開始重構前我可以先閱讀代碼,得到一定程度的理解,并提出一些建議。一旦想到一些點子,我就會考慮是否可以通過重構立即輕松地實現它們。如果可以,我就會動手。這樣做了幾次以后,我可以更清楚地看到,當我的建議被實施以后,代碼會是什么樣。我不必想象代碼應該是什么樣,我可以真實看見。于是我可以獲得更高層次的認識。如果不進行重構,我永遠無法得到這樣的認識。

      開發者何時最需要重構?

      重構還可以幫助代碼復審工作得到更具體的結果。不僅獲得建議,而且其中許多建議能夠立刻實現。最終你將從實踐中得到比以往多得多的成就感。

      :在編程的過程中持續不斷地進行代碼復審。

      ###怎么對經理說

      “該怎么跟經理說重構的事?”這是我最常被問到的一個問題。毋庸諱言,我見過一些場合,“重構”被視為一個臟詞——經理(和客戶)認為重構要么是在彌補過去犯下的錯誤,要么是不增加價值的無用功。如果團隊又計劃了幾周時間專門做重構,情況就更糟糕了——如果他們做的其實還不是重構,而是不加小心的結構調整,然后又對代碼庫造成了破壞,那可就真是糟透了。

      如果這位經理懂技術,能理解“設計耐久性假說”,那么向他說明重構的意義應該不會很困難。這樣的經理應該會鼓勵日常的重構,并主動尋找團隊日常重構做得不夠的征兆。雖然“團隊做了太多重構”的情況確實也發生過,但比起做得不夠的情況要罕見得多了。

      當然,很多經理和客戶不具備這樣的技術意識,他們不理解代碼庫的健康對生產率的影響。這種情況下我會給團隊一個較有爭議的建議:不要告訴經理!

      這是在搞破壞嗎?我不這樣想。軟件開發者都是專業人士。我們的工作就是盡可能快速創造出高效軟件。我的經驗告訴我,對于快速創造軟件,重構可帶來巨大幫助。如果需要添加新功能,而原本設計卻又使我無法方便地修改,我發現先重構再添加新功能會更快些。如果要修補錯誤,就得先理解軟件的工作方式,而我發現重構是理解軟件的最快方式。受進度驅動的經理要我盡可能快速完成任務,至于怎么完成,那就是我的事了。我領這份工資,是因為我擅長快速實現新功能;我認為最快的方式就是重構,所以我就重構。

      本文摘自《重構:改善既有代碼的設計》(第2版)

      譯者:熊節, 林從羽

      ● 重構20年,世界軟件開發大師MartinFowler的不朽經典

      ● 生動闡述重構原理和具體做法

      ● 普通程序員進階到編程高手的修煉秘笈和代碼整潔之道

      這本備受關注的第2 版在第1 版的基礎上做了全面修訂,反映了編程領域業已發生的許多變化。第2 版中介紹的重構列表更加內聚,并用JavaScript 語言重寫了代碼范例。此外,第2 版中還新增了與函數式編程相關的重構范例,旨在教會讀者如何在沒有類的環境下開展重構。

      新版沿襲了第1 版的結構,依次解釋什么是重構,為什么要重構,如何通過“壞味道”識別出需要重構的代碼,以及如何在實踐中成功實施重構(無論用的是什么編程語言)。

      這本書讀者雖然已經很廣泛,但還是有許多人不知道它,請幫我擴散給需要的朋友們吧!

      本文轉載自異步社區。

      軟件開發

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:丁哥對如何做好軟件開發工作的思考(共識,復雜度,審查,重構,測試)
      下一篇:容器與虛擬化的結合:淺談“安全容器”技術發展趨勢(關于容器技術與虛擬化技術的對比)
      相關文章
      亚洲av无码成人黄网站在线观看 | 亚洲免费网站在线观看| 国产亚洲精品a在线观看app| 亚洲无码高清在线观看| 亚洲成a人片在线观看久| 亚洲欧美日韩中文字幕一区二区三区| 亚洲国产av一区二区三区丶| 亚洲性猛交xx乱| 亚洲大香伊人蕉在人依线| 91亚洲国产成人久久精品| 亚洲免费观看网站| 国产精品高清视亚洲一区二区| 亚洲中文字幕一二三四区| 亚洲国产成人久久精品大牛影视| 久久综合亚洲色hezyo| 国产精品亚洲色图| JLZZJLZZ亚洲乱熟无码| 亚洲精品美女久久久久99| 亚洲AV无码专区国产乱码电影| 亚洲av成人无码久久精品| 精品亚洲aⅴ在线观看| 亚洲理论精品午夜电影| 亚洲AV色吊丝无码| 亚洲另类无码一区二区三区| 亚洲国产成人AV网站| 亚洲日韩中文字幕日韩在线| 夜夜春亚洲嫩草影院| 亚洲成AV人片在线观看WWW| 亚洲天堂视频在线观看| 亚洲xxxxxx| 亚洲人成网站免费播放| 偷自拍亚洲视频在线观看99| 久久久久亚洲AV无码专区网站 | 亚洲大成色www永久网址| 亚洲国产成人无码AV在线影院| 亚洲成a人片在线播放| 国产亚洲色婷婷久久99精品| 亚洲AV永久无码区成人网站| 亚洲首页在线观看| 99亚偷拍自图区亚洲| 国产精品自拍亚洲|