為啥開發人員都覺得 TDD 好,卻又覺得在實務上有些彆扭,也有很多說法把它講得有些不切實際、太理想化呢?
你以為它是測試,但其實在它的本質上,同時兼具了「Specification」與「Test」兩種維度的身份。
隨筆記錄下來想法,這個「測試驅動開發」的「測試」,可能跟你想得不一樣。
為什麼 TDD 距離感覺這麼遠
絕大部分的團隊或開發人員,對於 TDD 覺得彆扭的原因,通常是因為他們拙於寫測試,而更糟糕的是,他們覺得「測試驅動開發」的「測試」真的只是「拿來測試用的測試程式」。
上面這樣說起來有些弔詭,待我娓娓道來。
測試不是測試?你在說什麼?
大家常提出的疑問是:「為什麼我寫 production code 之前要先寫測試?我寫 production code 都沒時間了。何況,我先寫完 production code 後,如果有時間的話,我再來寫測試,不是很好?先完成 must have, 再來完成 should have 的部分,合情合理。」
這樣講,也沒錯。如果測試驅動開發的測試,只是測試的話。
但,如果是先有需求規格再寫 production code 呢?大家都覺得別人的規格開得很爛,那就不如給自己開規格
吧。而且這樣的規格文件可以被自動產生出來,被自動執行,還可以看到執行的結果是成功還是失敗。
如果是為了先想好自己的目的跟驗證方式,再寫 production code 呢?就算你寫 production code的過程被中斷了,或是需要暫時停止,或是需要迭代式的交付,那你的目標隨時會告訴你,是否偏離方向了,是否已經完成需求了。
如果是先想清楚,使用者、使用端到底要怎麼用我接下來提供的功能或產品,才會比較好用?是不是其實是先想好 do the right thing 跟 eat your own dog food 呢?
這一些都不是「測試」(CHECKING)在做的事,反而比較像是 需求描述、目標捕捉、建立邊界、迭代演進,只把力氣精準地花在目標上而不浪費。
我們只是「恰巧」用了模樣長得像是「測試程式」的方式來進行上面這幾件事罷了。
但是因為用了「測試程式」來進行上面這幾件事,在 production code 開發完成時,它又恰巧可以真正扮演「自動測試」的工作,例如驗證程式運作是否符合預期,驗證有沒有改 A 壞 B 的情況,再透過測試覆蓋的路徑來觀察是否多寫了不必要的程式碼,或是遺漏了描述需求的測試案例。
所以 Kent Beck 以一篇「RIP TDD」來反串說明,TDD 可以「一次滿足你哪些需求跟解決哪些問題」,你不一定要使用 TDD,只是這是目前能只花一份工,卻可以同時滿足這些要求的最有效益的開發方式。如果你有更好的方式,歡迎你公開提出來,造福世人。(有比 TDD 更適合、更好的方式,傻子才抱著 TDD 不放。)
總結
測試驅動開發的「測試」,精髓在先定好想要的目標,強迫自己先想清楚最終目標,以終為始,避免自己走偏、迷惘、花時間在不必要的功能上。測試驅動開發的測試,不只是測試,更是一種需求的描述。