第 3 章 函式 | Clean Code

敏捷軟體開發技巧守則

Leo Chiu
手寫筆記
4 min readJun 8, 2019

--

簡短!

關於函式的首要準則,就是要簡短。第二項準則,就是要比第一項的簡短函式還要更簡短。

區塊 (Blocks) 和縮排 (Indenting)

If、else、while 及其他敘述都應該只有一行,這意味者,函式不應該大到包含巢狀結構。因此,除非有特殊的需求,否則函式裡的縮排程度應該只能包含 1 ~ 2 層。

避免輸出型的參數

如果你已經有多年寫程式的經驗,一定會遇到輸出型的參數,例如:

如果看到這段程式碼,第一時間你會覺得邏輯很直覺,因為你是一個喜歡傳遞 reference 的工程師。這麼寫的目的也許是為了效能,也許是為了節省空間,然而,作者說道我們應該盡量避免這種寫法,因為這種寫法會讓我們容易分心。

容易分心的原因是,我們不知道 game_board 傳遞進去函式後,究竟是否會修改 game_board 的值,或者只是把 game_board 的值給予另一個變數。我們無法第一時間知道 game_board的用途是什麼,因此會花費更多時間思考這個問題,容易導致開發時分心。

作者期望,假設我們使用物件導向的程式語言,應該盡量使用物件導向的優點 this 而不是傳遞 reference。

所以,可以把程式修改成以下這種形式:

經過修改後,我們可以明確地知道是對 game_board 增加新的地雷格子。

一點點的修改就可以大幅提高可讀性,所以如果非必要,作者建議不要使用輸出型的參數

只做一件事情

「一件事情」其實很難定義,作者也提到很難用論文或是資料佐證,但是他還是根據自己的親身經驗提出了一個方法。

如果我們以文字的方式描述一個函式,看到其中包含了「不同層次」的抽象概念步驟,就可以判斷這個程式包含了不只一件事。

聽起來超級抽象的吧!我們用在第 2 章看到的程式碼舉例,你認為 get_flagged_cells() 做了幾件事?

我們將程式碼的概念抽象化,也就是用「文章」描述這個函式。

建立儲存「插旗」地雷格子的 flagged_cells ,接著,走訪 game_board 上所有的地雷格子,並判斷是否插旗。如果已被插旗,則把該地雷格子放入 flagged_cells 中。最後,回傳被插旗的地雷格子。

我們很明顯地看見這個函式,沒有突然岔開做其他事情,所以我們可以判定 get_flagged_cells() 是一個只做一件事情的函式。

生活上的實際例子

如果現在的你正在洗澡,想想有哪些事情要做?你需要洗頭髮、洗臉、洗身體,甚至淋浴、泡澡。但是,一般人在洗澡的時候不會突然衝出浴室,跑去喝一杯咖啡。

所以,我們就可以知道,如果是洗澡的話,洗頭髮、洗臉、洗身體、淋浴、跑早都可以算得上是「洗澡」這件事情,而喝咖啡就不是。

程式碼是否做兩件事情

假設 get_flagged_cells() 做的事情除了取得被插旗的格子外,同時做了建立資料庫連線、存取資料庫的檔案,我們就可以知道 get_flagged_cells()不只做一件事。

小結

從這個章節,我們學到一個函式應該愈簡短愈好,而且函式除了簡短之外,還必須只能做一件事情,如果超出一件事情,應該把它們拆開變成不同的函式。

至於,如何判斷一個函式包含幾件事情,作者提到可以使用函式的所有行為是否在「同個層級」,藉由把程式碼抽象為文章的形式,讓我們可以用高層次的觀點檢查這個函式。

以及,我們要避免輸出型函式,輸出型函式不僅僅會影響閱讀性,而且還有可能會影響其他的程式碼,但難以發覺問題所在。因此,應該盡量使用物件導向的方法,像是 thisself 等可以直接指向該類別的關鍵字,如此一來,便能夠避免撰寫輸出型函式

✋ 延伸閱讀

--

--

Leo Chiu
手寫筆記

每天進步一點點,在終點遇見更好的自己。 Instragram 小帳:@leo.web.dev