有一個很危險的誤解,流傳很久了:把 BDD 情境(那些 Given-When-Then)當成「需求」,然後以為可以外包給某個人去寫,寫完交給下一棒去實作。
寫完就傳、傳完就做。這個流程看起來很順,但它剛好把 Specification by Example 最值錢的東西丟掉了——它值錢的地方在「釐清的過程」,不在最後那份文件。
這篇文章想把這個觀念的來龍去脈講清楚,也想提醒你:進到 AI coding 時代之後,這個誤用不但沒消失,反而被放大了。
這套想法從哪來的
1980 年代末,Gerald Weinberg 跟 Donald Gause 寫了一本《Exploring Requirements》。他們的觀察很簡單:需求天生就抽象、複雜、不好推理。
為什麼?因為需求要在比較高的層次界定工作範圍,所以它必然抽象。也因為抽象,你很難拿它來吵架、很難驗證對錯。可是要確定我們真的在做對的東西,我們偏偏就得能針對需求細細地推理、爭論。
他們給的解法是:針對需求寫 black-box test。測試案例通常很具體、很細節,具體到大家可以拿它來推理、可以吵。
於是就有了一個很有用的槓桿——用測試案例反推需求好不好。需求好,推導出來的測試案例大家會有共識;測試案例含糊、或複雜到談不下去,那就是在告訴你需求根本沒定義清楚。
$9.99 對 $10 的故事
講一個真實案例,這是整件事的核心。
有一個數位平台,使用者先買點數,再用點數下載資源。其中一條關鍵需求寫的是:「帳戶點數足夠(enough)才能下載。」
表面上每個人都覺得懂了。簡單嘛。直到測試人員丟出一個 edge case:
使用者帳戶裡有 $9.99,想下載的東西要 $10,會怎樣?
現場一堆人,包含開發者,直覺都說:當然拒絕啊,$9.99 買不起 $10 的東西。
只有業務總監愣住了。他說這明顯應該放行。大家問他為什麼,他指著規格上「enough」那個字:$9.99 對 $10 來說,就是「夠了」。
追下去才發現,業務總監腦子裡的「enough」,跟開發者理解的「enough」,根本是兩回事。他開始解釋漏斗流失率、購物車完成率,還有在大量交易的前提下,容許一點小額落差,雖然會壓低單筆利潤,卻能拉高整體成交量,讓整盤生意更賺。
這條複雜的商業規則,原本只存在他一個人腦袋裡。是那個具體例子把它逼出來、逼著大家定義下來。那條規則才是真正的需求,而不是規格上「enough」那個字。
為什麼「例子」這麼好用:因為抱怨比說明容易
Weinberg 跟 Gause 的書裡有一句話很值得記住:一般人很難清楚說出自己要什麼,但很會抱怨。
利害關係人講不清楚「好看的 app」是什麼意思,可是給他看到醜的東西,他一眼就能挑出來。業務總監事前定義不出 enough,但你把 $9.99 那個畫面擺在他面前,他馬上知道自己不喜歡。接著再丟 $9.98、$9.50、$9.70 幾個例子,大家幾分鐘就一起把規則拼出來了。
要抱怨,得先有具體的東西可以抱怨。
問題是,多數人第一次拿到「具體的東西」,往往是等軟體真的做出來、開始用了。這也是為什麼迭代交付有效——快點把東西擺到使用者面前,收回饋、再調整。
但做出來的軟體,是很貴的學習方式。
《Exploring Requirements》的核心主張就是:寫 black-box test 幾乎能拿到一樣的效果,而寫測試比寫軟體快太多了。所以測試存在的意義,是它「具體到足以讓人抱怨」。如果一組測試大家很容易就達成共識,代表需求清楚;如果一組測試怎麼看都吵不攏,那就是需求本身有問題。
Happy path 是沒用的
順著這個邏輯,就會踩到一個很常見的反模式。
開發者堅持要業務去寫 BDD,結果業務寫出來的,幾乎都是 happy path。這種情境沒什麼價值,因為大家本來就會同意。
會逼出抱怨的,是那些棘手的例子——邊界、edge case、大家可能各執一詞的地方。而巧的是,這些邊界、edge case、奇怪行為的例子,剛好也就是好的測試案例。
所以你要的不是「大家都點頭」的例子,是「有人會皺眉頭」的例子。
技巧一:USE 演算法
Gojko Adzic 在做顧問、幫很多公司加速這種討論時,發明了一個方法叫 USE。
USE 是 Usual(常見)、Structure(結構)、Edge cases(邊界) 的縮寫。有趣的是,實際操作要倒著走。
U — 先給幾個常見的簡單例子。 用下載那個案例來說,就是兩個顯而易見的情境:帳戶 $10、資源 $5,當然放行;帳戶 $5、資源 $10,當然拒絕。這種不用討論就有共識的例子,就是第一步。
S — 從常見例子裡找出領域結構。 把例子整理成表格,結構就浮出來了:這裡有「帳戶餘額」、「資源成本」、「放不放行的決策」這幾個欄位。這是第二步。
E — 對結構套用測試啟發法,把邊界逼出來。 這裡是數字,那就試大數字、小數字;有兩個數字要比較,那就試兩數很接近、兩數差很遠。$9.99 對 $10,就是這樣幾分鐘冒出來的。
啟發法有一大堆現成的,測試書跟網路上到處都是:
- 遇到字串,試空字串、只有空白、超長字串、特殊字元、tab。
- 遇到日期,試月初、月底、年底、閏日、24:00、23:59:59。
- 遇到多個同型別的元素,試相同值、差很多的值、很接近的值、差很遠的值。
有些適用你的情況,有些不適用,挑著用。
這裡最重要的一句話:Usual 例子只是第一步,不是討論的終點。
多數團隊的 BDD 就是卡在 usual 例子然後交出去了,尤其是業務寫的那種。它們不是好的邊界,不是能讓人抱怨的東西。別停在那裡,往結構走、往 edge case 走,然後開始吵。
技巧二:Feedback Exercise
第二個技巧來自 Gary Klein 的《Sources of Power》。
這本書談的是:當一群人的領域知識深淺不一、又得在時間壓力下做重要決策時,怎麼改善決策品質。Gojko 順帶吐槽了一句——這幾乎就是今天軟體開發的日常。
做法是這樣:有人先講出整體目標,再丟出可能有爭議的情境,然後每個人各自寫下自己認為該發生什麼,再一起攤開來對照。
關鍵的操作細節:先別喊出結論,別急著宣稱誰對。 討論例子的時候,把答案寫下來,大家同時攤開比對。
這個動作有兩個作用。第一,它強迫每個成員真的動腦去想那個情境。第二,它防止大家互相影響,也防止大家直接倚賴某個領域專家的答案。
如果答案全都一樣,恭喜,你們有扎實的共識。如果答案不一樣,那就是沒共識——而且要去挖為什麼。「你為什麼覺得 $9.99 該放行?」把這些追問攤開來討論,才會慢慢逼近共識。換幾個情境重複幾輪,直到答案收斂。
為什麼一定要「寫下來」?因為如果只是聽領域專家講,你很容易一晃就過去了,根本沒發現有人其實想法不一樣。只要每個人都得交出一個書面答案——哪怕只是便利貼上一個數字,或貼進 Zoom 聊天室的一行字——每個人的理解就被迫外顯出來,這樣才有東西可以吵。
兩個技巧合起來用
Klein 講的其實跟 Weinberg、Gause 是同一件事:具體情境比抽象需求好吵、好抱怨,能把分歧和誤解逼出來。Klein 多給的,是「全隊討論時,讓每個人先各自寫下答案」這個機制。
實務上合起來就是:
- U 跟 S 一起做,快速給出常見例子、找出結構。
- 到了 E,輸入(inputs)由大家一起想,但輸出(outputs)先不要當場討論——讓每個人各自寫下自己認為的結果,再翻開來對照。
這個流程很快,又能實實在在量測出共識到什麼程度、暴露分歧、暴露盲點,最後產出一組更完整的例子,直接拿來當驗收條件。
提醒:AI coding 時代,很多人正在用錯 BDD
前面講的這套誤用——把情境當需求、寫完就傳、傳完就做——三十年前就存在了。到了 AI coding 時代,它換了張臉,而且更容易犯。
第一,「外包給某個人去寫」變成了「丟給 AI 去寫」。 以前是業務寫完 BDD 交給開發者,現在是有人隨手把幾條模糊的規格丟給 AI,讓它生一堆 scenario 和測試。生成的速度很快,快到你根本沒時間去吵。但 SBE 的價值從頭到尾都在「吵」這個過程,你把吵的過程省掉了,剩下的就只是一份沒有經過釐清的文件,只是這次是機器生的。
第二,AI 最會生的,正好是最沒用的 happy path。 你叫 AI 補測試案例,它會很樂意生給你一大批,而且大多是漂亮、順暢、大家都會同意的常見情境。看起來覆蓋率很高,實際上全是 U,沒有 E。真正會引發抱怨、暴露分歧的那些邊界,AI 不會主動幫你想,因為那些規則根本不在程式碼裡、也不在需求文字裡——它們藏在某個業務總監的腦袋裡。$9.99 那條規則,AI 生一萬條測試也生不出來。
第三,AI 遇到「enough」這種模糊字眼,會直接幫你選一個解釋,而且講得很有自信。 以前開發者跟業務對 enough 的理解不同,至少還會在會議上撞出來。現在 AI 拿到「點數足夠才能下載」,會自己挑一個看起來合理的解釋、寫成程式,然後很流暢地告訴你做完了。那個藏在業務腦中的商業規則,連被逼出來的機會都沒有。誤解沒有消失,只是被自動化、被埋得更深。
第四,程式碼寫得越快,瓶頸就越往前移到「我們到底有沒有共識」。 AI 讓寫程式這件事變便宜了,於是「做出錯的東西」也變便宜了、變快了。真正貴的,變成「發現我們對需求的理解根本不一樣」這件事。這正好是 USE 演算法和 feedback exercise 要解決的問題。你越是用 AI 加速產出,就越需要在動手之前,把 edge case 吵清楚。
所以在 AI coding 時代,該做的不是少開會、少討論、把一切丟給模型。恰恰相反——把 USE 演算法和 feedback exercise 用起來,先跟人把邊界吵清楚,形成共識,再讓 AI 去實作。順序錯了,AI 只會用更快的速度,把你們的誤解變成一堆能跑、但做錯事的程式。
最後
回到那句最該記住的話:BDD 情境不是需求。它是拿來釐清需求的工具,是拿來組織一場好架的手段,讓人比「等軟體做出來」更早開始抱怨。
別滿足於 usual 例子——那種一看就知道該過或不該過的情境。去找 edge case,去找那些大家會意見不同的邊界。業務願意給你這種例子當然很好,但那只是討論的起點,不是終點。
拿到例子之後,套上 USE 演算法、套上 feedback exercise,才有機會挖出真正的需求。
本文整理自 Gojko Adzic 談 Specification by Example 的內容,並加上 AI coding 時代的觀察。
發表迴響