[Clean Code] 函式 Function

這又是另外一個有趣的問題,在我腦海裡,不知道哪來的錯誤認知,曾經以為只有在該段程式碼被重複使用時,才會被擷取為 Function。然而,在 Clean Code 的世界中,擷取 Function 對於改善程式碼的可讀性,是一個非常重要且必要的方式。我摘取了幾項重要的準則。

  • 好好的命名以提高可讀性,別害怕長名稱。

現在的 IDE 都很強大,並不會因為你的 Function 名稱太長而削弱你 coding 的速率。反而會因為名稱很長,更容易「選取」到該 Funciton。若你的 IDE 在長名稱的狀況不易操作,那表示你該更換 IDE 了...。

  • 一個 Function 只做一件事

或許會納悶,​何謂一件事?抽抽看就知道了,當你可以從該 Function 中抽離出第二件事,那就表示該 Function 不只做了一件事。

  • 無副作用

該 Function 的名稱為何,就應該只做那件事,不可以「順道」修改其他變數,或是進行其他作業。最常見的例如某個名為 FindXXXItem() 的 Function,目的是為了從某個 List 中找尋某項元素,但也「順便」修改了 List 中所有元素的屬性。

  • 該 Function 所做的事應該屬於同一階層抽象概念

換言之,不同抽象階層的行為,應該切分到更小的 Function 去進行,不會在同一個 Function 內展開。

  • 保持簡短

簡短,那是多短才算是符合標準?書中的建議約莫是在 10~20 行之間。

  • Function 的參數個數不要太多

那多少算是不要太多?書中的建議是 1 至 2 個...@0@
個人道行不夠,這是我個人最無法接受的規範之一,但前面說過,團隊有共識才是重點。

  • 避免使用旗標參數

往往在重構的過程中,為了將兩個很相似的功能寫進同一個 Function,會傳入一個「旗標參數」,當旗標為 True 時,在分支點執行某個動作;為 False 時,執行另一項動作。然而,這表示你在 Function 中做了不只一件事,應該要避免。

  • 避免使用輸出型的參數

x appendFooter(report);
o report.appendFooter();

雖然是說避免使用輸出型的參數,但我的解讀是「從呼叫端,應該要可以清楚瞭解具體是哪個參數值可能會被修改」,以便閱讀,因為在 C# 中,具有 ref out 等保留字可使用。
appendFooter(reportForError, reportForWarning);
。 o appendFooter(out reportForError, out reportForWarning); 

  • 指令與查詢應分離

這與前面「只做一件事」其實是同一件事,但這個情況實在太常見,故作者特別再次提出。
x SetAttribute 所回傳的布林值,意義含糊不明。False 是表示「找不到該數值」或是「找到了該數值但寫入失敗」?

o

  • 結構化設計

Edsger Dijkstra 大師曾經提過三個結構化設計的準則:

  1. 一個函式只有一個進入點、一個離開點
  2. 迴圈內不能有任何 break、Continue
  3. 永遠不能有 goto

但從 Uncle Bob. 的字裡行間似乎透露著不是非常認同,所以他也下了一個結論:「只要 Function 夠簡短,這應該都不是什麼問題。」
上述前兩點我覺得有些誇張,Uncle Bob. 的這結論我是買單了。

  • DRY (Don’t Repeat Yourself. 極度乾燥

這是最常見的壞味道,我想應該不用多作說明。

 

總結

書中也特別提出上述種種規範要達成的確不容易。工程師在開發功能時,一次專注一件事,一開始只思考將功能的正確性給達成,這是相當正確的。最重要的是別忽略了可讀性與正確性同等重要,應該回過頭來修正程式碼的可讀性,到達到上述的總總規範。讓程式碼維持可讀性。