1. 程式人生 > >Martin Fowler's Bliki 中文版

Martin Fowler's Bliki 中文版


原文:SpecificationByExample(譯註1)    敏捷        2006年6月16日            Bliki 索引

譯註1:以例為規,“例”即測試涉及到的例子,這裡主要是指驗收測試(Acceptance Testing);“規”即軟體規格說明書,以下簡稱“規格”;“以例為規”即以測試涵蓋的例子作為規格,後文也作“範例規格”。



Cedric Beust最近的一篇帖子批評了敏捷方法,引發了一場小規模的部落格論戰(請看Jeff LangrBob Martin對他觀點的反駁)。Cedric的批評之一是針對“測試即為規格”這一觀念的,下邊這篇Bliki文章雖然是我幾年前寫的,鑑於與這個話題比較相關,我想它值得用RSS feeder再發一遍。


我參加2002年XP/Agile Universe的一個研討會時,聽到“以例為規”作為測試在XP中所扮演角色之一的一種描述,這一提法一下子深入進了我的意識裡。

(今天再談“TDD與測試的關係”這個話題實在是跟不上形勢了(譯註2),但我和Jon一樣,都覺得TDD(除了驅動設計)還“附送”了一套廣覆蓋面的自動化測試套件,其價值超過了“副作用”(譯註3)這個詞所表達的程度。就好比若有人出一百萬美元讓我登一座山,我可以宣稱自己醉翁之意在乎山水之間,但錢包變鼓這個“副作用”的吸引力著實不可小覷也……

我們多數人憑第一感覺理解,所謂規格,應該是全面的,涵蓋了所有可能的情況;但範例規格並非如此,範例僅突出所有情況中的一點或幾點,要想達到普遍化,需要我們自己推而廣之。這也就意味著,在做需求分析時單靠範例規格這一種技術是不夠的,但這並非說“以例為規”不能用作捕獲需求的首要手段。

要求規格嚴密詳盡,目前占主導地位的思想是利用前置和後置條件,據此得出的規格能明確地判斷什麼情況通過什麼情況不通過。這種技術在規範化的方法中占主導地位,而且是
契約式設計(Design by Contract)
的支撐理論。這種技術有可取之處,但並不理想。一些情況下,前置和後置條件寫起來很輕鬆,有時候卻非常麻煩。我在幾個企業應用開發中嘗試過,我發現在很多情況下編寫前置和後置條件簡直和編寫實際工作程式碼一樣困難。而用舉例子的方式通常就容易多了——尤其是對那些不懂技術的人來說,畢竟我們編寫軟體是為了他們,這是以例為規的優勢之一。(Timothy Budd曾指出,雖然Stack的許多行為可以用前置和後置條件表示出來,但要描述出它的“後進先出 / LIFO”特性就很需要技巧了。)

TDD有一個重要特性:測試形成了一次複查。其實這“戳穿”了XP社群的一個有趣的小謊,他們一直非常強調“說事情只說一遍”(譯註4)
,事實上他們總是把事兒說兩遍:產品程式碼裡說一遍,測試程式碼裡又說一遍。Kent曾指出這條複查原則至關重要,是一條人類隨時隨地都在實踐著的原則。複查的價值很大程度上在於兩次分別採用不同的方法。範例規格與產品程式碼相結合,這樣就用完全不同的方式把兩件事都說了,也就更有利於發現錯誤。

在推崇規範化規格的社群,他們很難檢驗一個設計到底滿足沒滿足規格的要求,尤其因為做檢驗的是人,而人總是傾向於出錯的。然而對於範例規格,檢驗過程就輕鬆多了。這是以例為規實踐價值大於其理論價值的又一個案例。

一位DbC粉絲指出,如果規格是以測試的形式寫的,那麼只需針對那些特定的測試輸入以硬編碼的方式返回輸出,這樣就滿足規格要求了。我尖利地回答說:假如你連這個都擔心,那你還有精力去關心規格是用測試還是用DbC來描述的區別嗎?——但這兒有個很嚴肅的問題:測試永遠是不全面不完整的,因此不能單單以測試做規格,必須輔以其他機制。不過對我這種頭腦喜歡“轉圈兒”的人來說,這反倒是以測試做規格的一個優勢:既然已明確單以範例做規格還不夠,顯然就需要做更多工作,通過徹底的溝通互動,確保敲定需求中的每一件事。而以傳統的需求分析技術,人們總是想當然地以為把東西寫出來了,互動過程也就完成了 ——這真是一個致命缺點。

客戶與開發團隊不是在打架,雙方是合作的工作關係,只有這樣,範例規格才能發揮作用。這些範例激發設計團隊抽象問題,並起著保證所做出的抽象能有效解決問題的作用。這顯然還不夠,需輔以更多工作,如經常性的交流溝通、運用領域驅動設計技術,甚至還需要一定量的DbC工作。儘管我一直沒有機會充分全面地使用DbC(即用Eiffel),但我經常以契約角度來考慮介面設計。沒錯,範例規格很強大,可能是我用得最多的工具了,但絕不是我用的唯一工具。

(如果想找更多以例為規方面的思想,不要囿於是否叫這個名字,可以參考Brian Marick的文章。他那個站點有一個極好的頁面,上面總結了他對這個問題的觀點。當然了,找出這個頁面並不那麼重要,更有價值的是你試著找的過程中所讀到的東西。)

(上文原貼出於2004年3月18日。)

可能是受最近部落格論戰的刺激,Jeff Langr貼出了一個漂亮的例項,以Java的Math.pow函式為例,通過測試演示範例規格。



譯註2:這也是“一場小規模的部落格論戰”,Dan North先發文“TDD Is Not About Testing”,他認為TDD的重心不在測試,而在驅動開發;之後Jon Tirsén發文“TDD *Is* About Testing”,按重要性從高到低分別列舉了驗收測試和單元測試的作用,他認為,雖然兩種測試都可以驅動開發,單元測試的最後一個作用才是“在單元層級 驅動設計”,而驗收測試的首要作用即“捕獲、記錄並校對客戶的需求”。Jon和Martin兩年半前就說談那些“跟不上形勢”了,沒想到一年多後 Uncle Bob換了個角度又大談特談一番

譯註3:原文為“side-effect”,Aslak Hellesoy在對Jon那篇帖子的評論中先用了這個詞。無論是“side-effect”還是“副作用”,都常用來表示負面的附帶作用,但此處宜理解 為正面效果,即TDD除了驅動設計之外,還附帶產生出詳盡的測試套件——這些測試(尤其是驗收測試)是作為軟體規格捕獲並驗證客戶需求的首要技術手段,但 不是唯一手段——此為Martin這篇文章的主題。

譯註4:也叫做DRY(Don’t Repeat Yourself)原則。


       

    Ward Cunningham     Robert C. MartinUncle Bob)   Cedric Beust      Jon Tirsén


譯後記

敏捷宣言”提出者之一Ward Cunningham創造了Fit(Framework for Integrated Test 整合測試框架),他還是Wiki的發明人。Uncle Bob用Ward發明的瓶子裝上Cunningham造的酒,貼上新標籤“Fitnesse”,稱它為“驗收測試框架”。

聽到TestNG的作者Cedric Beust公開反對“測試即為規格”,Uncle Bob這樣講:

“Cedric is right that you cannot depend entirely upon tests for the system specification. But he is wrong to case aspersions on the whole discipline of specifying through tests. There is hardly a better way to be unambiguous and current, than to specify tests and require that they always pass.” (Cedric說系統的規格不能完全由測試充當是對的,但他詆譭通過測試明確並驗證需求的整條思路就不對了,很難找到比給出測試用例並保持它們全部通過更沒有歧義更通行的方法了。)