AI x BDD 軟體全自動化開發術 - (2): 靠「可執行規格」,未來的程式語言就是中文和英文沒錯!

就是這「可執行規格」,讓行為驅動開發 (BDD) 變成 Vibe Coding 時代下的寵兒!如果一份「需求規格」可以作為測試被執行,那只要我們訂好規格,就能命令 AI 開發出完全符合規格的程式碼,你不再需要花一堆時間擔心 AI 寫錯 Code,因為全部都被「可執行規格」這份「測試」給保護了。

上一篇文我們介紹了 行為驅動開發 (Behavior-Driven Development, BDD) 開發方法中最關鍵的「實例化需求(Spec by Example)」以及它在軟體開發中的關鍵價值。

這一篇,我們要實際動手,將前面提到的實例化需求,轉化為「可執行規格(Executable Specification)」。未來,人類只需要撰寫這種規格,就能讓 AI 自動產出正確的程式碼,不再需要手動寫程式。

可執行規格 (Executable Specification) 是什麼?

首先,長話短說,可執行規格是一種黑箱的自動化測試 (Automated Test)

所謂黑箱測試,指的是:「這種測試不會涉及任何程式細節或技術實作」,它只關心一件事:當系統收到某個輸入時,輸出的結果和系統在執行行為後的狀態是不是對的。

正因為它不涉及技術細節,所以你可以試著把讓這些測試寫好看一點,讓它們看起來就像是在寫業務邏輯、像在描述需求一樣

換句話說啊,如果讓沒技術背景的人來看你寫的「測試」,這些人還能完全看得懂、不只看得懂還知道怎麼修改的話,那這樣的測試就叫做「可執行規格」(Executable Specification)!

所以,你現在應該懂「可執行規格」這個名字為什麼這樣取了吧?

因為它有兩個特點:

  1. 可以被執行(就像一般自動化測試那樣)
  2. 長得像需求規格(而不是像難懂的程式)

這兩個特點合在一起,就是「可執行規格」。

快跟我說:「可執行規格」長什麼樣子?


「如果你希望測試長得像需求規格,那你就真的去寫一份需求規格就好啦!」

可執行規格——其實就是大家想像中未來世界的模樣。
不都說未來的程式語言就是「中文」和「英文」嗎?你只要動動嘴、說出需求,AI 就會幫你寫好整套系統。

沒錯,可執行規格就是用中文/英文「說出來的一口好測試」。
它不需要你寫程式,只要把需求說清楚、寫明白,AI 就能照著實作。

不過啊,話雖如此,科技還沒厲害到能聽你亂說話還能幫你寫出對的東西。
所以你不能真的「隨便說」,而是要「用統一、結構化的格式」來描述需求,AI 才能準確理解並正確執行。

這時候,就該登場的就是 Gherkin Language
它是一種標準化的語法規格,專門用來撰寫這種可被執行的需求描述。雖然是用自然語言寫的,但格式非常清晰有邏輯,讓人和機器都能讀得懂、跑得動。

Gherkin Language 是什麼?

Gherkin Language 認定了系統的每一道功能 (Feature),可以拆解成多種情境 (Scenario),而每個情境又可以拆解成三個行為部分:「給定 (Given)」、「當 (When)」、「結果 (Then)」:

  • Given:描述前提條件
  • When:描述使用者的操作(也是你想要測試的操作)
  • Then:描述操作執行之後預期的結果

只靠這三個部分,就能描述大多數的系統功能情境。

範例:訂單優惠的可執行規格

例如,下面是一個電商優惠邏輯「滿 1000 折 100 元」的可驗收規格,用 Gherkin 寫成的可驗收規格長這樣:

Feature: 滿額折扣

  Scenario: 滿 1000 折 100
    Given 購物車內包含以下商品
      | 商品名稱 | 數量 | 單價 |
      | T-shirt | 2   | 500 |
      | 褲子    | 1   | 600  |
    When 結帳
    Then 訂單總金額應為 1500
    And 訂單應包含以下商品
      | 商品名稱 | 數量 |
      | T-shirt | 2   |
      | 褲子    | 1    |

翻譯成中文的話就是:

  1. 這個功能 (Feature) 叫做「滿額折扣」
  2. 滿額折扣中的第一個實例情境 (Scenario) 是:
    1. 給定 (Given):購物車中有兩件 500 元的 T-shirt,和 1 件 600 元的褲子。
    2. 當 (When):我結帳之後
    3. 結果 (Then):
      1. 訂單總金額應為 1500
      2. 訂單應包含兩件 T-shrt 和 1 間褲子

這就是把「實例化需求」撰寫成「可執行規格」的樣子。

好,其實我現在只解釋了一半而已,你大概也只覺得「啊這不就只是一種帶著實際資料的規格驗收文件」,你憑什麼說他「可以執行」?

你說啊,水球,明明就只是個 Spec,你憑什麼說他 Executable!?

那規格要怎麼才能「執行」起來呢?靠的當然是技術!其中最關鍵的,就是 Cucumber —— 最知名的 BDD 測試框架。

Cucumber 實作可執行規格

Cucumber 是目前最知名的 BDD 測試框架,Gherkin Language 便是 Cucumber 採用的格式,而採用了 Gherkin Language 格式所撰寫的規格文件稱之為 Feature file

Cucumber 會幫助你把這個 Feature file 中,每一個 Scenario 底下的 Given / When / Then 全部綁定到對應的「測試函數」上。

好比你可以使用底下這種描述方式來綁定:

@given('購物車內包含以下商品')
def given_cart_items_contains(context):
    ...

@when('結帳')
def when_checkout(context):
    ...

@then('訂單總金額應為 {expected_total:d}')
def then_total_amount_should_be(context, expected_total):
    ...

@then('訂單應包含以下商品')
def then_items_should_contain(context):
    ...

這些函數經過 Cucumber 的配置後,就能自動「綁定」到 Feature file 中對應的 Given / When / Then 步驟。舉例來說,當 Cucumber 執行 "Given 購物車內包含以下商品" 這行時,就會自動呼叫你程式中 given_cart_items_contains 這個函數。

這些與 Gherkin 步驟綁定的函數,我們稱之為 Step Definitions
我自己習慣把它們叫做 Test Step(中文可以翻成「測試步驟」,懶一點就直接說「測試步」)。

所以你只需要依照 Given / When / Then 的順序,填入你原本測試程式中會寫的 Arrange、Act、Assert 的程式碼邏輯,就能把這份規格「變成真的、能執行的測試」。

from behave import given, when, then

@given('購物車內包含以下商品')
def given_cart_items_contains(context):
    # 清空購物車資料(假設是測試用 DB)
    db_session.query(CartItem).delete()
    db_session.commit()

    # 將給定商品加入購物車中
    for row in context.table:
        item = CartItem(
            name=row['商品名稱'],
            quantity=int(row['數量']),
            price=int(row['單價']),
        )
        db_session.add(item)
    db_session.commit()

@when('結帳')
def when_checkout(context):
    # 呼叫後端結帳 API,例如 POST /api/checkout
    response = requests.post("http://localhost:8000/api/checkout")
    assert response.status_code == 200, f"結帳 API 呼叫失敗,狀態碼 {response.status_code}"

    # 取得 API 的回應
    data = response.json()

    # 將回應塞進去 Cucumber context 中,用於 @then 中驗證
    context.order_total = data['total']
    context.order_items = data['items']

@then('訂單總金額應為 {expected_total:d}')
def then_total_amount_should_be(context, expected_total):
    assert context.order_total == expected_total

@then('訂單應包含以下商品')
def then_items_should_contain(context):
    for expected in context.table:
        found = any(
            item['name'] == expected['商品名稱'] and item['quantity'] == int(expected['數量'])
            for item in context.order_items
        )
        assert found, f"未找到商品:{expected['商品名稱']} × {expected['數量']}"

這就是「可執行規格」的程式實作方式。

而且你要知道——測試步驟的綁定,跟測試的層級是沒有關係的
你可以拿來寫 End-to-End 測試、Unit 測試,甚至是前端的 Component-level 測試都行,觀念通了,用在哪裡都可以套得上。

像我上面舉的範例,就是一個典型的 後端 End-to-End 測試

  • Given 裡,我把給定購物車商品資料塞進資料庫
  • When 裡,我呼叫後端的結帳 API endpoint
  • Then 裡,我驗證 API 回傳的訂單金額與商品明細是否正確

雖然這是後端系統的測試步驟實作,但只要你掌握這套思維模式,就能輕鬆應用到任何技術場景裡。

蛤?你說這些測試步看起來寫起來有點麻煩?

哎呀,那你一定還沒聽過「先苦後甘」這個道理!

我跟你說,這些測試步驟的程式碼,只要你寫過一次,之後可以重複用個好幾十次。每一段 GivenWhenThen測試步,就像是你未來所有可執行規格裡的「積木模組」,直接組合、快速覆蓋各種情境。

這些測試步驟的實作,其實可以被反覆使用超多次

別被上面的程式碼嚇到啦,雖然一開始你得自己寫 Feature file,寫完還要自己去綁定對應的測試步驟,看起來好像有點麻煩對吧?

但你有沒有注意到——上面那幾段短短的 Given / When / Then 測試步驟,其實就已經能支援超多驗收情境了

我們來實作看看吧!

就以「訂單優惠」這個功能為例,假如我們把這份可執行規格中所有的六個業務情境通通寫進同一個 Feature file。來,你看看底下這個完整的 Feature file,每一個情境都是真正可執行的規格,而你只寫了一次測試步驟:

Feature: 電商訂單計價優惠
  作為一位購物者
  我希望系統能根據優惠規則計算訂單總金額
  讓我清楚知道要付多少錢,以及會收到哪些商品

  Scenario: 購買單一商品,未套用任何優惠
    Given 購物車內包含以下商品
      | 商品名稱 | 數量 | 單價 |
      | T-shirt | 1    | 500  |
    When 結帳
    Then 訂單總金額應為 500
    And 訂單應包含以下商品
      | 商品名稱 | 數量 |
      | T-shirt | 1    |

  Scenario: 滿 1000 折 100
    Given 購物車內包含以下商品
      | 商品名稱 | 數量 | 單價 |
      | T-shirt | 2    | 500  |
      | 褲子     | 1    | 600  |
    And 已設定滿額折扣活動
      | 門檻金額 | 折扣金額 |
      | 1000     | 100      |
    When 結帳
    Then 訂單總金額應為 1500
    And 訂單應包含以下商品
      | 商品名稱 | 數量 |
      | T-shirt | 2    |
      | 褲子     | 1    |

  Scenario: 化妝品買一送一(不同商品)
    Given 購物車內包含以下商品
      | 商品名稱 | 類別   | 數量 | 單價 |
      | 口紅     | 化妝品 | 1    | 300  |
      | 粉底液   | 化妝品 | 1    | 400  |
    And 化妝品買一送一優惠已啟用
    When 結帳
    Then 訂單總金額應為 700
    And 訂單應包含以下商品
      | 商品名稱 | 數量 |
      | 口紅     | 2    |
      | 粉底液   | 2    |

  Scenario: 化妝品買一送一(相同商品)
    Given 購物車內包含以下商品
      | 商品名稱 | 類別   | 數量 | 單價 |
      | 口紅     | 化妝品 | 2    | 300  |
    And 化妝品買一送一優惠已啟用
    When 結帳
    Then 訂單總金額應為 600
    And 訂單應包含以下商品
      | 商品名稱 | 數量 |
      | 口紅     | 3    |

  Scenario: 化妝品買一送一(與其他類別混合)
    Given 購物車內包含以下商品
      | 商品名稱 | 類別   | 數量 | 單價 |
      | 襪子     | 服飾   | 1    | 100  |
      | 口紅     | 化妝品 | 1    | 300  |
    And 化妝品買一送一優惠已啟用
    When 結帳
    Then 訂單總金額應為 400
    And 訂單應包含以下商品
      | 商品名稱 | 數量 |
      | 襪子     | 1    |
      | 口紅     | 2    |

  Scenario: 滿額折扣 + 買一送一 同時套用
    Given 購物車內包含以下商品
      | 商品名稱 | 類別   | 數量 | 單價 |
      | T-shirt | 服飾   | 3    | 500  |
      | 口紅     | 化妝品 | 1    | 300  |
    And 已設定滿額折扣活動
      | 門檻金額 | 折扣金額 |
      | 1000     | 100      |
    And 化妝品買一送一優惠已啟用
    When 結帳
    Then 訂單總金額應為 1700
    And 訂單應包含以下商品
      | 商品名稱 | 數量 |
      | T-shirt | 3    |
      | 口紅     | 2    |

你會發現,這些情境一被寫完全部就都可以被執行了,而且通通共用你剛剛寫的那一份測試步驟程式。你看看,你有需要為了這些更多不同的訂單優惠情境,去額外實作不同的測試步驟程式嗎?不需要啊。

而且啊,擴充規格的搞不好不是你,有可能是你老闆手賤自己修改,或是業務同事想要增加需求,但這些「缺乏技術背景」的夥伴卻完全不需要了解程式碼,就能獨立修改規格書了呢!

這件事聽起來很普通?不!你得再想一想,這件事其實是個突破。正是因為這份規格本身能執行、能驗證,加上 AI 的能力,行為驅動開發(BDD)才成為 Vibe Coding 時代的寵兒。

可執行規格,就是 Vibe Coding 的核心突破!

Vibe Coding 的核心主張是:

「我們不再需要寫程式,只要跟 AI 說清楚需求,AI 自己會寫完並確保通過測試。寫出來後我們覺得哪裡想改,再回頭改一下就好。」

而你仔細想想,這句話成立的前提,是什麼?就是「可執行規格」。

如果你手上沒有這種 Feature file,請問你到底怎麼跟 AI 說清楚你要什麼?
又要怎麼在完全不看程式碼的情況下,讓 AI 準確知道你想修改哪一段邏輯?

你試試看不用 Feature file,光要描述「某個功能想改」,你 prompt 不知道要下多少字,還不一定講得清楚,講完還要擔心 AI 誤會你。但如果你有幾十個 Scenario 已經列在 Feature file 裡,你只要打開對的情境,直接修改 Given / When / Then 就好了

只要測試情境改了,AI 就知道該怎麼改程式碼,改到通過所有驗收為止。這就是可執行規格的威力。這也是為什麼我們說:可執行規格不只是規格,更是一種「黑箱測試」

一份文件,兩種功能。它既能驅動 AI 去實作符合規格的程式,又能在實作完成後,自動驗證結果是否正確。而且這份可執行規格文件,不可能過時,因為它會和程式碼一起被維護,畢竟他是測試,這種文件又被稱之為「活文件 (Living Documentation)」。

不只是你(工程師)可以改 Scenario,
所有職能角色、所有 Stakeholder 都可以透過這份「可執行規格」,精準地把需求交給 AI。像是行銷想要新增活動、PM 想要取消某個優惠,都可以直接改規格,測試一跑,行為就變了。

總結:可執行規格的五大好處

最後,我們回頭來總結「可執行規格」到底在 AI 時代下,為我們帶來了哪些巨大的好處:

  1. 沒有技術細節,任何人都看得懂
    不再只有工程師看得懂測試,連業務、PM、設計、老闆都能直接讀懂每一個系統行為的「情境 + 結果」。
  2. 促進跨部門需求溝通及協作
    可執行規格並不是技術文件,而是所有 Stakeholder 都能參與維護的「活的規格書 (Living Document)」。不用來回溝通改需求,直接改 Feature file。
  3. 需求變更快速安全
    想改某個行為?直接改對應的 Scenario 就好!當你跑測試時,整份系統的驗收規格會一次性告訴你、告訴 AI 哪些測試出問題,哪些已經正確實作。
  4. 測試步驟高度重用
    先苦後甘,花點時間寫好測試步驟(Step Definitions),可以支援上百種情境規格。Scenario 越多,反而越划算。
  5. AI 全自動化開發的切入點
    Feature file 就是未來 AI 開發的語言橋樑。人類只要懂得維護可執行規格,剩下的測試步驟和程式實作全部交給 AI。

朋友們,就是這個「可執行規格」的技術實現,讓你從「與 AI 協作」的低效率開發方式,晉升成「結果導向」的開發方式。

這個可執行規格不只是規格,還是份測試呢。不管 AI 開發的過程長什麼樣子,隨便啦,只要他結果對就好了啊,只要 AI 開發的結果通過這個「可執行規格」的測試,就代表他寫的程式碼是正確的啊。

因此啊,Code Review 時,我們首先要讀的是 AI 寫的測試步驟,讀完測試步驟之後確定測試寫對之後,其實你對 production code 的 review 就不必這麼歇斯底里了。

你看你同事的 Code 肯定也不是用肉眼去看他寫的業務邏輯是不是全對,一定是大致看看有沒有超出預期、看起來就明顯不合理的業務處理,順便確定沒有效能上的問題。

畢竟肉眼又不像是自動化測試,我們怎麼可能靠眼睛抓到所有錯誤,一定是靠測試確保程式無誤,如果在 AI 時代下你還不心力花在測試步驟上,而是花在 Code Review 上,效率也仍然低落。

好,你是否開始可以想像到了呢?軟體工程師不再需要花一堆時間與 AI 協作,而是將可執行規格書寫好,剩下的全部交給 AI 來幫你實現。

OK,這樣你知道下一篇文我要講什麼了嗎?

沒錯,接下來我要來講清楚,你到底要怎麼樣在訂定完可執行規格之後,讓 AI 幫你完整實作剩下的程式碼,不只是實作,連測試步驟也全部都交給 AI 實現,你一行程式碼都不用寫!

當你知道何謂「實例化需求」,也知道什麼叫「可執行規格」之後,最後一步就是要把所有拼圖拼起來——用測試驅動開發來命令 AI 做到全自動化開發吧!


如果想要在六個小時內立刻掌握 AI x BDD,該怎麼做?

要在六個小時內掌握 AI x BDD 全自動化開發的做法,只靠自己摸石頭前進是不可能的。

就算讀完了《BDD in Action》這本書,就算對於 BDD 的各個工程環節都有所掌握,也仍距離 AI 全自動化開發有一大距離。

如果真的想要讓 AI 能夠依照 BDD 的指示,精準且可靠地把每一步驟做好,有太多的細節需要留意:

  1. 該怎麼做實例化需求,寫到什麼程度才能保證 AI 看得懂?
  2. 看懂實例之後?用什麼測試架構,才能保證 AI 產出絕對與需求一致的測試?
  3. 測試架構的設計如何釋放 AI 的效率?AI Agent 把測試寫得越來越肥,效率越來越差了,該怎麼辦!
  4. 實例化需求的重用該怎麼做?規格上做「情境重用」,可是技術上該如何讓 AI 也懂得「情境重用」?
  5. AI 寫完 given / when / then 之後要做什麼?如何讓 AI 自己寫 code、自己試錯、自己修正,做到獨立作業?
  6. 就算 AI 已經能做到 BDD 獨立開發了,到底又要怎麼樣讓他不眠不休地連續工作好幾十個小時?做到「全自動化開發」?

這些全部都是智慧的結晶啊!每一個環節都需要花費超級大量時間研究,才能找出正確的方法。如果你不想花費半年時間來研究的話,那就直接上課吧!

《AI 時代的 1% 工程師:用「行為驅動開發 (BDD)」 實現百倍效率的 Vibe Coding 》是水球老師精心製作的一日工作坊課程,現正熱賣中。

⚠️
場次有限、票卷有限,6/28 開賣後至今已經賣出了 200 多張票了,如果錯過早鳥時段就會再漲價 NT3000,請有興趣的工程師夥伴多多留意!

如果要想要用 6 小時工作坊的時間,立刻速成學會如何用 BDD 來讓 AI 全自動化開發?那就上課吧!

實體場:https://www.accupass.com/event/2506110435103759406480
線上場:https://www.accupass.com/event/2506160524377577825710

訂閱 水球軟體學院:部落格

立即訂閱水球軟體學院部落格的電子報,接收最前沿的軟體工程方法學問
jamie@example.com
訂閱