關於函式的首要準則,就是要簡短。第二項準則,就是要比第一項的簡短函式還要更簡短。
憑空想像一下,一個超過 50 行的程式碼與 3 行的程式碼,什麼樣的函式式容易被理解的?
我們都理解,程式品質的一大要素就是意圖明確,而在這件事情上,沒有什麼比一個簡短函式所帶來的效益更高。
函式簡短的一大目的,就是使得程式的意圖明確、易讀。
程式界有一個公認的原則:
函式應該只做一件事情。它們應該把件事做好。而且他們應該只做這件事。
這個主張的問題在於,我們很難知道哪件事才是「這件事」
針對這個問題,作者提出了一項概念來幫助我們寫出只做一件事的函式。
如果函式只做了函式名稱下『同一層抽象概念』的幾個步驟,那麼,這個函式就算是只做了一件事。
然而這個概念本身也是有點抽象,讓我們用一點例子來說明。
如果我今天要寫段儲存並關閉視窗的功能,可能會在某一小段的程式碼中這樣寫:
// 4-1
const saveAndCloseModal = () => {
save();
closeModal();
}
const save = () => {
members.push(newMember);
......
}
那麼以這段例子來說,saveAndCloseModal 就是抽象概念的高層次,save 是中層次,members.push(newMember) 則是低層次。
若以這方法去界定會感到有些主觀,我們也可用另一個方法去思考:
......觀察函式是否做超過「一件事情」的另一種方法,是看你是否能夠從此函式中,提煉出另外一個新函式,但此新函式不能只是重新詮釋原函式的實現過程(實作)而已。
來看書中的一個例子:
// 4-2
public static String renderPageWithSetupAndTeardowns(PageData pageData, boolean isSuite)throw Exception{
if(isTestPage(pageData)) includesSetupAndTeardownPages(pageData, isSuite);
return pageData.getHtml();
}
對於這段程式碼,
我們可以將 if 敘述提至 includesSetupAndTeardownPagesIfTestPage 函式裡面,但這樣僅僅是重新陳述了原本的程式碼而已,並沒有改變程式碼的抽象層次。
這是作者提出讓抽象層次維持在同一層的技巧:
我們希望每個函式後面都緊接著『下一層次的抽象概念』,如此,我們在閱讀程式時,可依照看到的一連串函式,對應著抽象層次降層閱讀。
回到上面 4-1 的程式碼,saveAndCloseModal 下方緊接著降一層的 save ,這就是降層準則的應用。
函式這個議題非常的重要,今天只初步處理完該篇章的開頭,明天我們將會繼續聊聊關於函式撰寫的原則。