函數長度

2016 年 11 月 30 日

在我的職涯中,我聽過許多關於函數長度應該多長的論點。這是更重要問題的代理人 - 我們什麼時候應該將程式碼封裝在自己的函數中?其中一些準則基於長度,例如函數不應大於能顯示在螢幕上 [1]。有些則基於重複使用 - 任何使用超過一次的程式碼都應該放入自己的函數中,但只使用一次的程式碼應該保留在內聯程式中。然而,對我來說最有道理的論點是意圖和實作之間的分離。如果您必須花費力氣檢視程式碼片段才能找出它在做什麼,那麼您應該將它萃取到一個函數中,並將函數命名為那個「什麼」。這樣一來,當您再次閱讀它時,函數的目的就會立刻跳出來,而且大部分時間您不需要關心函數如何實現其目的 - 也就是函數的主體。

一旦我接受了這個原則,我就養成了撰寫非常小的函數的習慣 - 通常只有幾行長 [2]。任何超過半打的程式碼行的函數對我來說都會開始有異味,而且我經常有單行程式碼的函數 [3]。Kent Beck 從原始 Smalltalk 系統向我展示的一個範例讓我了解到大小並不重要。那時候的 Smalltalk 執行於黑白系統上。如果您想突顯一些文字或圖形,您會反轉影片。Smalltalk 的圖形類別有一個名為「highlight」的方法,其實作只是一個呼叫「reverse」方法 [4]。該方法的名稱比其實作還長 - 但這並不重要,因為程式碼的意圖和其實作之間有很大的距離。

有些人擔心函式太短,因為他們擔心函式呼叫的效能成本。在我年輕的時候,那偶爾會是一個因素,但現在已經很少見了。最佳化編譯器通常在較短的函式上運作得更好,因為它們可以更輕鬆地快取。一如往常,效能最佳化的通用準則才是重點。有時,稍後內嵌函式是你需要執行的動作,但通常較小的函式會建議其他加速的方法。我記得人們反對在清單中使用 isEmpty 方法,因為常見的慣用語法是使用 aList.length == 0。但這裡在函式上使用揭示意圖的名稱也可能支援更好的效能,如果找出集合是否為空比確定其長度更快的話。

像這樣的函式只有在名稱良好的情況下才有效,因此你需要特別注意命名。這需要練習,但一旦你擅長了,這種方法可以讓程式碼顯著地自文件化。較大規模的函式可以像故事一樣閱讀,而讀者可以選擇在需要時深入了解哪些函式以取得更多詳細資訊。

致謝

Brandon Byars、Karthik Krishnan、Kevin Yeung、Luciano Ramalho、Pat Kua、Rebecca Parsons、Serge Gebhardt、Srikanth Venugopalan 和 Steven Lowe 在我們的內部郵件清單上討論了這篇文章的草稿。

Christian Pekeler 提醒我,巢狀函式不符合我的大小觀察。

備註

1: 或在我的第一份程式設計工作中:兩頁列印紙 - 約 130 行 Fortran IV

2: 許多語言允許你使用函式來包含其他函式。這通常用作範圍縮減機制,例如使用 函式作為物件 模式來實作類別。此類函式自然大得多。

3: 我的函式長度

最近,我對建置這個網站的工具鏈中的函式長度感到好奇。它主要是 Ruby,執行約 15 KLOC。以下是方法主體長度的累積頻率圖

正如你所見,那裡有很多小方法 - 我的程式碼庫中有一半的方法是兩行或更少。(這裡的行是非註解、非空白,且不包括 defend 行。)

以下是粗略表格形式的資料(我懶得將其轉換成適當的 HTML 表格)。

              lines.freq lines.cumfreq lines.cumrelfreq
[1,2)          875           875        0.4498715
[2,3)          264          1139        0.5856041
[3,4)          195          1334        0.6858612
[4,5)          120          1454        0.7475578
[5,6)          116          1570        0.8071979
[6,7)           69          1639        0.8426735
[7,8)           75          1714        0.8812339
[8,9)           46          1760        0.9048843
[9,10)          50          1810        0.9305913
[10,15)         98          1908        0.9809769
[15,20)         24          1932        0.9933162
[20,50)         12          1944        0.9994859
      

4: 範例在 Kent 出色的 Smalltalk 最佳實務模式 中的揭示意圖訊息