🔖 文章索引1. 簡短!
2. 區塊 (Blocks) 和縮排 (Indenting)
3. 避免輸出型的參數
4. 只做一件事情
5. 小結
簡短!
關於函式的首要準則,就是要簡短。第二項準則,就是要比第一項的簡短函式還要更簡短。
區塊 (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()
不只做一件事。
小結
從這個章節,我們學到一個函式應該愈簡短愈好,而且函式除了簡短之外,還必須只能做一件事情,如果超出一件事情,應該把它們拆開變成不同的函式。
至於,如何判斷一個函式包含幾件事情,作者提到可以使用函式的所有行為是否在「同個層級」,藉由把程式碼抽象為文章的形式,讓我們可以用高層次的觀點檢查這個函式。
以及,我們要避免輸出型函式,輸出型函式不僅僅會影響閱讀性,而且還有可能會影響其他的程式碼,但難以發覺問題所在。因此,應該盡量使用物件導向的方法,像是 this
、self
等可以直接指向該類別的關鍵字,如此一來,便能夠避免撰寫輸出型函式。