跳至頁尾內容
Iron Academy Logo
C#常見問題

讀50行程式碼還是使用方法提取重構?- 來自Derek Comartin的見解

[[academy-video-youtube({"vid": "MtVqasDREkg", "start_time": "0", "title": "I'd rather read 50 lines than \"Extract Method\" Refactoring", "creator": "Derek Comartin", "length": "9m 16s"})]]

在軟體開發的世界中,重構是必不可少的。 其中一種最常見且受推崇的技術是擷取方法重構——將大型程式碼片段分解為較小的、可重用的方法以提高可讀性和可重用性。 雖然理論上聽起來很理想,但Derek Comartin在他的视频《我寧願讀50行而不是擷取方法重構》中提供了一個新鮮而批判性的觀點。

本文將帶您了解Derek對擷取方法重構的分解,提供現實世界的背景和實用建議。我們將遵循他的準確推理和程式碼結構,當他引導我們何時以及如何應用提取重構時,還會詳細說明其實施細節和潜在缺點。

範例:聊天室系統中的使用者註冊

在影片一開始,Derek展示了一個範例:聊天室系統的註冊功能。 這是一個大約50行的緊湊而現實的程式碼塊,其執行多項任務:

  • 檢查使用者名是否不為空

  • 驗證使用者名是否已被佔用

  • 處理年齡限制的頻道

  • 保存新使用者物件

  • 發送帶有激活連結的電子郵件

這段程式碼存在於一個函式中,乍看之下,它似乎是擷取方法重構的理想候選。 但正如Derek所警告的,盲目重構而不了解影響可能會降低清晰度。

從重構開始:選擇擷取方法

Derek從許多開發者開始的地方開始——將程式碼片段分解成較小的部分。 他展示了如何在大多數IDE或程式碼編輯器中,通過上下文選單或鍵盤快捷鍵選擇擷取方法。

他提取出:

  • validateUsername用於驗證使用者名不為空

  • existingSignUpNotActivated用於檢查未激活賬戶

  • validateExistingUser用於處理所有現有使用者檢查

  • filterAgeRestrictedChannels用於處理未成年使用者的頻道

  • sendEmail用於發送歡迎電子郵件

他為每個新函式賦予有意義的名稱,這是乾淨程式碼實踐中經常提升的頂尖提示之一。 但正當他介紹這些修改版本時,Derek開始指出邏輯中的裂痕——不是在功能上,而是在可讀性和控制流程上。

問題1:隱藏的實施細節

Derek強調的第一個紅旗是實施細節現在隱藏在擷取出的方法後面。

例如,validateUsername和validateExistingUser方法實際上會拋出異常。 但作為讀取重構程式碼的開發人員,您除非存取其內部,否則不會知道這一點。

這種重構會隱藏控制邏輯,導致錯誤或漏掉的驗證。 範圍和流程不再明顯。 與其說讓程式碼更清晰,您建立了一個抽象的迷宮,像異常或變數修改這樣的副作用在最初編寫邏輯的形式中不再可見。

問題2:間接和鏈式擷取

接下來,Derek指出間接的問題——當一個擷取方法調用另一個,依此類推。 他展示了validateExistingUser方法本身由existingSignUpNotActivated組成。

您不再從上到下閱讀一個簡單的程式碼塊。 您正在方法、文件和類之間來回跳轉,只為了追蹤發生了什麼。 儘管編輯器可能幫助導航這個流程,但這增加了讀者的認知負荷。

這在涉及多個文件或組件的更大系統中變得更加痛苦。 突然間,您的"乾淨程式碼"看起來比原來的"雜亂"50行更加難以追踪。

問題3:局部變數和狀態突變

此影片中最重要的課程之一來自處理局部變數和狀態突變。

Derek強調了filterAgeRestrictedChannels方法。 它並不返回結果——它直接改變傳入的channels列表。 這意味著您正在從不同的方法中修改局部狀態,除非您仔細檢查方法,否則此更改是隱藏的。

這打破了函式要麼是純操作,要麼明確指明正在改變的預期。 當您用一個不返回值但在內部更改它們的新方法替換邏輯時,您引入了風險和混亂。

Derek的重構替代方案

那麼Derek實際上如何重構舊程式碼的呢?

他提出了一個更簡單的方法:

  1. 保持自解釋的邏輯內嵌。 最初的空使用者名檢查保持在主方法中,因為它容易理解且不會佔用程式碼庫。

  2. 返回結果而不是突變。 與其更改channels列表,filterAgeAppropriateChannels函式現在返回過濾後的列表。這讓資料流變得清晰,並防止意外的副作用。

  3. 使用簡單、可預測的擷取方法。 唯一另一個提取的方法是isExistingUserAlreadyActivated,它明確返回一個布林值,沒有拋出異常。 它封裝邏輯而不隱藏細節。

  4. 避免內嵌副作用如發送郵件。 Derek為示範保留郵件邏輯,但建議在真正的系統中,這應通過在單獨的流程或執行緒中處理的事件來處理——而不是直接綁定到使用者表單提交。

總之,Derek僅使用兩個提取方法,並將其餘邏輯保留在內嵌——因為這更容易閱讀、推理和控制。

關於提取方法重構的最後提示

Derek的影片為我們提供了一些有效使用提取方法重構的實用指南:

  • 使用有意義的名稱,準確描述方法的功能。

  • 避免副作用如狀態突變或拋出異常,除非它們是顯而易見的。

  • 返回值而不是修改輸入參數。

  • 不要將邏輯隱藏在多層抽象後面。

  • 如果一個方法在其原始形式下顯得可讀,不要為了重構而強行將其編成多個函式。

有時,最好的抽象是不抽象——尤其當它以清晰度和範圍感知為代價時。

結論

Derek Comartin的方法挑戰了重構總是改善程式碼的觀念。 在提取方法重構的情況下,少即是多。 與其過度使用選擇提取方法來切分邏輯,應評估什麼能增加價值、什麼讓程式碼更易理解,及什麼隱藏了重要細節。

通過清晰的例子和對現實世界程式碼的直接洞察,Derek在他的影片中展示,有時一個方法中的50行,自上而下如故事般閱讀,勝過分散在程式碼庫的十個小方法。

如果您曾經使用鍵盤快捷鍵來建立新方法,記住Derek的建議:暫停、評估,並確保重構是為了讀者服務,而不僅僅是IDE。

Hero Worlddot related to 讀50行程式碼還是使用方法提取重構?- 來自Derek Comartin的見解
Hero Affiliate related to 讀50行程式碼還是使用方法提取重構?- 來自Derek Comartin的見解

分享您所愛以賺取更多報酬

您是否為使用 .NET、C#、Java、Python 或 Node.js 的開發者建立內容?將您的專業知識轉化為額外收入!

Iron 支援團隊

我們線上24小時,每週5天。
聊天
電子郵件
給我打電話