iT邦幫忙

2026 iThome 鐵人賽

DAY 12
0

Day 12

Day 11 把一個登入問題一路追到 Frontend state mapping,先回答了:

這次真正該改到哪裡?

但 Scope 正確,不代表功能就一定做對。

假設需求只有一句:

讓 ProxyAdmin 也可以幫別人點餐。

這句話放進真實系統後,立刻會多出一串產品決策:

  • 哪些日期可以代點?
  • 已截止後還能不能操作?
  • Admin 與 ProxyAdmin 規則是不是一樣?
  • 代點後訂單屬於誰?
  • 扣的是誰的餘額?
  • View-As 和代點餐是不是同一種權限?

如果這些問題沒有先回答,AI 還是可以很快做出一個「合理版本」。

只是合理,不等於符合這套系統真正的業務規則。

Acceptance Criteria 的價值,不是把需求寫得更正式,而是先決定什麼叫做做對。

Day 2 其實已經出現過 Acceptance Criteria。當時它主要用來從 Legacy 畫面反推需求;走到今天,角色、日期、截止時間與餘額都已經互相牽動,AC 開始多一個責任:在 AI 動手前,把行為契約固定下來。

一句需求裡,藏著很多沒有說出口的規則

Delegated ordering 最容易被誤解成:

多一個 target user 就好了。

畫面上可能真的只是多一個成員選擇器,但 Domain 至少同時在回答:

誰可以代點
+
哪一天可以代點
+
操作後誰的狀態被改變

這三件事如果各自由不同層自己猜,很容易得到一個很麻煩的結果:

每一段程式單獨看都合理,合起來卻不是同一套規則。

這次 repo 裡的測試就把角色差異寫得很具體。

ProxyAdmin:

  • 可以替別人點今天與未來的有效開團日期;
  • 今天仍受今天的 cutoff 限制;
  • 未來日期也必須在各自 cutoff 前;
  • 過去日期不能 delegated ordering;
  • 未開團的未來日期不能操作。

Admin 則不同:對有效訂餐日期具備更高的操作能力,測試也明確涵蓋 cutoff 之後的 delegated ordering。

這已經不是一個按鈕要不要顯示的問題。

它是角色、日期、Calendar 與 Deadline 共同形成的規則。

AC 要描述可觀察行為,不要先寫實作方式

我現在會把需求先改寫成可以直接判斷 PASS / FAIL 的句子。

例如 ProxyAdmin 的允許案例:

Given 使用者具備 ProxyAdmin 權限
And 指定日期是今天或未來
And 該日期已開團
And 尚未超過該日期 cutoff
When 替另一位可操作成員建立訂單
Then 系統接受操作
And 訂單歸屬於被代點成員

禁止案例則可以分開寫:

Given 使用者具備 ProxyAdmin 權限
And 指定日期是過去日期
When 嘗試建立 delegated order
Then 系統拒絕操作
And 不產生訂單
And 不改變任何餘額

以及:

Given 使用者具備 ProxyAdmin 權限
And 指定日期尚未開團
When 嘗試建立 delegated order
Then 系統拒絕操作

這裡刻意沒有寫:

  • 改哪個 React component;
  • 呼叫哪個 function;
  • 在哪一層加 if。

因為 AC 描述的是外部可觀察的行為契約,不是 implementation plan。

只要這份 observable behavior 沒變,底層未來仍有重構空間。反過來,如果 AC 一開始就綁死檔案與函式,測試很容易只是在保護目前寫法,而不是保護真正的 Business Rule。

Happy path 只證明「可以」,Boundary 才證明「規則」

AI 很擅長先把主要路徑打通。

真實系統比較容易踩坑的,反而是邊界。

類型 代點餐例子
Happy path ProxyAdmin、今天/未來、已開團、cutoff 前
Boundary Admin 與 ProxyAdmin 對 cutoff 的權限不同
Forbidden 過去日期、未開團、角色不符
State consistency 訂單與餘額必須落在 target user,而不是 actor

如果只驗 Happy path,很容易得到「功能已完成」的錯覺。

真正把規則寫清楚的,通常是第二、第三列。

例如測試裡甚至有一個很有意思的案例:

ProxyAdmin 可以讀取某個 target 的歷史 context,不代表它因此取得該日期的 mutation access。

也就是:

可以看
≠
可以改

這種規則如果沒有先進 AC,很容易只因為 UI 已經拿得到 target context,就不小心把 mutation 權限一起放大。

View-As 和 Delegated Ordering 為什麼不能混在一起

兩個功能表面都和「切換成別人」有關。

但語意完全不同。

View-As 的核心是:

用另一個人的視角查看系統

Delegated ordering 的核心則是:

由具備權限的人
代表另一個人
產生一筆會改變狀態的操作

前者偏向 read context。

後者會建立訂單、改變 target balance,還需要留下 actor / target 的責任關係。

如果只從 UI 長相出發,因為兩邊都有 member selector 就共用同一套權限,很容易把「看得到」和「可以代替他改資料」混成同一件事。

AC 的作用,就是在實作之前先把這種語意差異攤出來。

AI 加快的是實作,不會自動補齊產品決策

這也是 Vibe Coding 進入真實系統後,我越來越在意的一個落差。

早期功能單純時,一句自然語言需求常常就能得到很接近預期的結果。

系統變大後,同一句話背後可能已經綁著:

  • Role;
  • Calendar;
  • Deadline;
  • Target ownership;
  • Balance;
  • Audit。

AI 可以幫忙把模糊需求整理成 AC,但最後仍需要人確認:

  • 哪些行為是真的允許;
  • 哪些是禁止;
  • 哪些例外是既有 Business Rule;
  • 哪些只是模型補出的「看起來合理」。

產碼速度可以交給 AI,加快產品決策並不代表產品決策本身也能外包。

我現在會做的兩次切割

第一輪是用案例類型找洞:

Happy path
Boundary
Forbidden
State consistency

它回答:

我是不是只想到「成功時會怎樣」?

第二輪再把需求壓成四個最小問題:

Who
誰可以做?

When
什麼日期/狀態下可以做?

Effect
成功後誰的哪些狀態必須改變?

Reject
哪些情況必須完全不產生副作用?

Day 12|一句需求 → Who / When / Effect / Reject → Observable Behavior → PASS / FAIL

兩套看起來都像四格,但用途不同。

前一套用來找漏掉的案例;後一套用來寫最小行為契約。

這樣一句「讓 ProxyAdmin 也可以幫別人點餐」,才會從一個自然語言願望,變成 AI、測試與人都能判斷 PASS / FAIL 的工作。

下一步才是另一個問題:

當一條 AC 真的穿過 Frontend、API、Auth、Domain 與 Persistence 時,要在哪些地方看到證據,才算整條鏈都改對?

本系列實作專案

這不是純概念示範,而是一套持續開發中的便當訂購系統。文章著重「為什麼」,GitHub 保留實際程式碼、測試、文件與演進紀錄。

GitHub:https://github.com/henryfir456/bento-order-app


上一篇
Day 11|當 AI 開始跨模組幫我改,第一個學到的不是速度
系列文
從 GAS 到 Cloudflare D1:AI Agent 如何打造、接手並重構真實便當系統 共 12 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言