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 最有價值的地方,是能直接對到一組可判定的測試

這次不是先寫完功能,再回頭想「要測什麼」。

Repository 裡對 delegated ordering 已經有幾個很具體的判定:

User 偽造 targetUserId
→ 403 DELEGATED_ORDER_FORBIDDEN

ProxyAdmin 代點今天、cutoff 前
→ 200

ProxyAdmin 代點今天、cutoff 後
→ 400 DEADLINE_CLOSED

ProxyAdmin 代點未來有效日期、該日期 cutoff 前
→ 200

ProxyAdmin 代點未來日期,但該 calendar group 未開
→ reject

Admin delegated ordering
→ 擁有較高日期/cutoff authority

這組測試有一個很重要的特性:它沒有只證明「ProxyAdmin 可以代點」。

它同時把誰、哪一天、什麼狀態、什麼例外固定下來。

而且 Worker 端的 authorization contract 仍然是最後權威:ProxyAdmin 只能擴大 delegated ordering 的 eligible date range,不會因此繞過 canonical calendar/menu cutoff;真正具備 elevated cutoff bypass 的仍是 Admin。

這也讓 AC 不只是產品文字,而是能一路追到可重跑的 PASS / FAIL。

如果哪天 UI 又把未開團日期顯示成可操作,或某次 refactor 不小心讓 ProxyAdmin 越過 cutoff,測試不是在檢查「畫面有沒有照原本寫」,而是在提醒:

這次實作已經偏離當初確認過的 Business Rule。

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

這些條件在系統裡不是抽象規則。實際代點時,角色、目前代點對象、目標餘額與每一天能不能預訂,都會一起出現在操作畫面上。

Day 12|真實代點餐畫面:角色、代點對象、目標餘額與日期狀態共同決定可否操作

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

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

測試裡還有一個很容易被忽略的邊界:

ProxyAdmin 即使能查看某個 target 的歷史 context,也不代表該日期允許替他下單。

可查看
≠
可下單

這種差異如果沒有先進 AC,UI 只要已經拿得到 target context,就很容易讓「看得到」被誤解成「可以操作」。

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) }}
直播中

尚未有邦友留言

立即登入留言