為什麼從測試聞 Code Smell#

在團隊裡,如果身邊的人習慣寫難讀、難改的程式碼,待久了你也會慢慢被同化。專業開發者要避免這件事,就需要敏感度去察覺程式碼異味(Code Smell)。

而幫助我們察覺異味的最有效手段之一,並不是 Code Review,也不是昂貴的 IDE,而是夠密集的單元測試。當設計上有缺陷,寫測試時就會被「逼著」用同一種樣子重複寫,於是味道自然浮現。

「重複」是萬惡之淵藪#

程式世界的萬惡之源,當之無愧的就是重複(Duplication)。Andrew Hunt 與 David Thomas 在 The Pragmatic Programmer 中將此原則命名為「DRY — Don’t Repeat Yourself」。

大多數爛程式都是從「複製貼上」開始。在 Stack Overflow 抄答案、從舊專案搬運類似邏輯,當下確實能完成工作,但長期累積下來就是技術債。

當寫程式發現自己在重複時,大概代表兩件事:

  • 介面設計不好,使用者被迫一再做相同的事
  • 確實存在多個類似邏輯,重複程式碼是這個事實的展現

無論哪一種,都是進行重構或修改設計的好時機。

範例:成績單獎學金計算#

以「依照學生身份計算獎學金」為例。原本的 calculate 方法在不重構時,會依大學生、碩士生、博士生三種身份各寫一段邏輯,三段邏輯外觀非常類似。

只看「形狀」就能聞到味道:方法被切成三大塊,每一塊長得很像,那一定有共通的抽象邏輯被重複了。

如果在寫產品程式時沒注意到,還有第二次機會:寫測試的時候。

class ScholarshipServiceTest {

    @Test
    void bachelor_full_scholarship() { /* 略 */ }

    @Test
    void bachelor_half_scholarship() { /* 略 */ }

    @Test
    void bachelor_NO_courses() { /* 略 */ }

    @Test
    void bachelor_NO_scholarship() { /* 略 */ }

    @Test
    void master_full_scholarship() { /* 略 */ }

    @Test
    void master_half_scholarship() { /* 略 */ }

    @Test
    void master_NO_courses() { /* 略 */ }

    @Test
    void master_NO_scholarship() { /* 略 */ }

    @Test
    void PhD_full_scholarship() { /* 略 */ }

    @Test
    void PhD_half_scholarship() { /* 略 */ }

    @Test
    void PhD_NO_courses() { /* 略 */ }

    @Test
    void PhD_NO_scholarship() { /* 略 */ }
}

把所有細節隱藏,光看測試方法名稱就能看出重複:三種學生 × 四種場景。寫這些測試時你會大量「複製過來改一下」,覺得麻煩。

覺得麻煩,就是壞味道在說話#

覺得麻煩就對了,這意味著:

  • 介面設計可能有問題,應該回頭檢視
  • 邏輯確實是這個量級,那就回頭看看程式有沒有可以重構的地方

這是聞出重複的第二次機會。錯過這次,未來再回頭時,因為已忘記當初寫了什麼,重構成本會更高。

「如果我們沒發現,就給程式寫一點測試」── 測試會誠實揭露程式設計上的不足。

原文出處#

  • 原書/iThome:https://ithelp.ithome.com.tw/articles/10262134