jim yeh on 一月 5th, 2010

在 Facebook 的 Scrum Community in Taiwan 看到 David Ko 提到:

聽到有人說 TDD 是個測試的 practice,跟 RD 不是那麼有關,我想這是誤會了。TDD是一種設計的活動,它並不是單純在做 verification,它是一種 spec 確認的活動。

David Ko 還分享了一篇探討 TDD 的文章供大家參考。這讓同人想到我之前曾經對 InfoQ 的一篇有關軟體開發信仰問題的文章做過的評論

在那篇文章的評論當中,同人認為作者不應該拿 TDD驗收測試相提並論,因為 TDD 並不是測試的 practice,而是設計的活動。如果這兩種實務可以相提並論,似乎就像是爭論有了良好品質的設計就可以省略測試,或是增加測試的效率就可以取代設計的重要性。同人當時在我的評論中提到:

測試的涵蓋面要夠廣,軟體開發所需的開發成本與時間就要增加,所以與其靠檢驗來控制品質,還不如把設計做好。所以,品質是設計出來的,而非檢驗出來的。

不過,雖然品質並不是檢驗出來的,但軟體要具備足以信賴的品質,卻不能省略測試。舉個例子來說,不管開發者如何確保他的開發所產出的品質,驗收測試是絕對不可能省略的,否則客戶是很難信任軟體是合乎他們需求的。良好的軟體設計可以減輕測試的負擔與壓力,但它絕對無法否定軟體測試的價值。

因此,同人認為不該拿 TDD 來與各種形式的測試來做比較,但在 David Ko 提出這個主題後面的討論,我卻看到一個我不太認同的說法。Steven Mak 提到:

世上總有些傻人愛做傻事,阻止不了他們的 :) 不單是由測試去訂定功能規格,更不要忘了 Refactoring!

同人以為由測試去訂定功能這個觀點不符合 TDD 的精神,因為正如同我之前一直強調的,TDD 並不是測試。至於 Refactoring 是不改變功能的情況下使程式的結構可以更有彈性或是更簡單,它也無法用來訂定功能規格。但 Steven Mak 卻說:

TDD 就是由測試去驅動開發功能,寫測試就是第一步,到底有什麼不符合 "TDD 精神"?還有,Refactoring 本身是 TDD 三步之中其中必要的一步,沒有訂定功能用的。但我相信把 TDD 以為是測試的人是忘掉了 Refactoring 這一步。

看來 Steven Mak 以測試驅動開發的第一步就是寫測試程式為理由,以為測試並沒有不符合 TDD 的精神,只是認為人們忘卻去做 refactoring,才會以為 TDD 只是用測試來訂定功能規格。同人認為這樣的觀點混淆了測試驅動開發的目的不在測試驅動本身,而是主導開發過程中可以具體落實簡單設計。也就是說測試並非目的,而只是手段而已!

事實上功能不是由測試來訂定的,而是由使用者實際需求來決定。測試程式只是讓開發者找到更具體的方法,來具體驗證使用者的實際需求,這也就是 David Ko 所說確認規格的活動。因此,測試驅動開發的目的是讓我們開發的程式碼能夠符合實際的需要,用可驗證的程式來確定我們開發的程式是符合實際需要的,以避免 over-engineering 或是 under-engineering,所以其目的是為了讓我們發現更符合實際需要的設計。

運用測試驅動開發,可以讓開發者的設計儘量簡單,因為開發的目標很具體地呈現在眼前。開發者已經事先對需求的確認花過一番心思考量,把現階段已經確認而且最重要的需求寫成測試程式,一旦開發的程式符合測試程式的要求,那就代表程式已然滿足實際的使用者需求,而使開發者不致浪費心力在不重要或是目前無法確定的需求上。

因此測試驅動開發可以讓開發者立即用最簡明而單純的設計完成開發工作,好處是讓開發者知道自己在做什麼,而非浪費時間在做沒有意義或無關緊要的事。但任何一開始簡明而單純的設計,在系統不斷演進及需求不斷改變之下,也可能會使架構或設計愈來愈複雜而變得難以維護。這時候單靠 TDD 的簡明與單純也可能沒辦法容納這種複雜性,而是要運用 Refactoring 來增加設計的彈性;也就是在不改變系統功能的情況下,改善系統設計的結構,使它可以因應未來增加需要的功能。

因此 Refactoring 與 TDD 是兩個相互獨立的 practice,雖然 TDD 可以讓重構更為可行。但兩者不必要要混為一談,也就是 Refactoring 並不必然是 TDD 的必要的步驟。

在大部分的情況下,用 TDD 落實簡單的設計就已經夠用了,除非我們真的發現到我們需要更大的彈性才需要進行 Refactoring 的行動。敏捷開發不是強調方法論的教條,因此不管是 TDD 或是 Refactoring,都是為了真實世界的問題的需要,而非方法論的信仰,這也是同人之前評論 InfoQ 那篇文章,最主要想要批判的重點。

因此,雖然 TDD 這三個字母或是測試驅動開發這六個字當中,測試驅動就佔掉了這個名詞的 2/3,但切莫以為 TDD 就是以測試去訂定功能規格,這只是對 TDD 流於表相的認識,而看不清楚這個名詞最重要的兩個字「開發」的真相。

測試驅動開發的精神,不應該用一般機械論的觀點來進行工作或任務的化約,而是基於複雜理論的重要觀念;維持穩定與變化的動態平衡,不在於掌握系統核心而在於邊緣,讓變動限定在人們可以掌握的範圍內,這或許才是測試驅動開發最關鍵的精神吧!



     

3 Responses to “測試驅動開發的精神”

  1. [...] 同人在〈測試驅動開發的精神〉中,提到「Refactoring 並不必然是 TDD 的必要的步驟」的觀點。David Ko 回應他猜測 Steven 是根據 Kent 在《Test-driven Development》一書的前言中提到的說法,來認為測試和 Refactoring 也是TDD很重要的一環。他說: …here’s what we do: we drive development with automated test, a style of development called Test-Driven Development(TDD). In Test Driven Development: * Write new code only if an automated test has failed * Eliminate duplication …… [...]

  2. [...] 測試驅動開發的精神 測試驅動開發要徹底重構? [...]

  3. [...] TDD 並非不做設計,而是把做更周詳的設計的時間延後到可以得到更佳設計決策的時候。或者更根本地來說,TDD 本身就是一種設計手法;而不是因為它以寫測試案例開始,而就把它當做開發的測試過程,這樣的誤解反而違反 TDD 的基本精神。 [...]

Leave a Reply

You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="">