iT邦幫忙

2026 iThome 鐵人賽

DAY 6
0
Claude AI

買了 Claude Code,然後呢?系列 第 6

Day 6|別再猜我要什麼,先約好怎樣才算完成

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20260920/20162577mrXSmNnpkD.png

昨天開始記錄 Claude 執行、人工審查與返工的時間。記著記著,我心裡想的是:怎樣才算完成?

程式寫完?測試全部綠燈?需求都開發完成?

以前一行一行寫,每一段都要時間。現在 Claude Code 幾分鐘就把程式和測試交回來,那個問題反而更明顯:東西都出來了,這樣就算完成了嗎?

Day 3 那份訂單取消程式,十八個斷言全過,我卻還不能接受,因為「取消後是否要求退款」需求沒說。十八個綠燈只能說明那些測試的預期成立,不能替退款規則找到依據。

AI 可以很快把程式寫出來,卻不會讓模糊的需求自動變清楚。 沒說明的地方,也可能更快變成程式裡的決定。所以要談完成,得先知道答應交付什麼:需求說要解決什麼問題,規格把它整理成行為、限制與驗收條件,才有依據判斷做到了沒有。

動手之前,先說清楚三件事

Anthropic 八月的 AI-Native SDLC playbook 把這件事拆成三份版控檔:intent 保存問題與期待結果,spec 寫行為,plan 寫怎麼做。它是建議流程,不是「照做就會變快」的實證,但這個分工對我有用:「為什麼做」「要有哪些行為」「準備怎麼做」分開確認,才不會一張工單寫了功能名稱,就直接變成開發指令。

文件 要回答的問題 誰核對
intent.md 為什麼做?要改善誰的什麼問題,怎麼看出有改善? 能確認問題與期待結果的需求負責人
spec.md 要有哪些行為、例外與驗收條件,才能回應這個目的? RD 整理,核心規則由對應 Owner 確認
plan.md 改哪些地方、怎麼實作、怎麼驗證? 工程師核對可行性與影響範圍

這裡的 Why,是誰遇到什麼問題、期待什麼改變、不能犧牲哪些限制。這次我試著用 intent.md 保存它,讓 Claude Code 讀 Spec 時能回頭核對;Jira 保留正式需求與確認紀錄。規格回應不了目的,就先回頭問。

我實際的做法:Spec 加 Prototype,再用圖把需求走一遍

真實工作裡,我手上通常有兩樣東西:Spec 列功能與規則,Prototype 看實際操作。RD 再從系統分析與設計(SA/SD)的角度,用循序圖、流程圖與狀態圖釐清需求,確認疑問、整理測試案例,後面才進開發;改動跨系統時多一張 C4 架構圖看影響範圍。

  • 循序圖看互動:誰呼叫誰?資料怎麼傳,失敗時由誰接手?
  • 流程圖看分支:正常操作、例外與失敗時怎麼走?
  • 狀態圖看轉換:哪些狀態可以改變,哪些操作還沒說清楚?

這些圖我請 AI 用 Mermaid 畫,保留文字原始碼,核對時直接看節點與連線。看圖比讀一疊 Markdown 容易抓到重點,大家對著同一段流程討論;細節與決策理由仍留在規格裡。我依問題選圖,不是每次都畫齊;Spec 與 Prototype 不一致就回頭確認,釐清後把關鍵路徑與例外寫成驗收案例。這些材料的用途,是找出需求中的空白,確認後才變成判斷完成的依據。

https://ithelp.ithome.com.tw/upload/images/20260920/20162577sgcZHenuqu.png

作者實務整理。

接下來沿用訂單取消題目,把這條線走一小段。這次只提供文字需求與程式骨架,沒有操作原型;能檢查規則缺口,不能據此說整套需求流程已跑通。

用訂單取消看一次:Spec 寫了什麼,又沒寫什麼?

沿用 Day 3 的訂單取消教學示範案例。情境與需求是為了示範而設計,程式、測試與 Claude Code 審查則有實際執行;其中的教學假設不代表真實業務決策。當時給 Claude Code 的功能需求只有一句,另外提供程式骨架與執行限制,中文意思是:

讓使用者可以取消尚未出貨的訂單。

很像主管在走廊上講的那一句。它已經是功能要求,卻沒有交代誰遇到什麼困難、為什麼需要取消。程式骨架另外有是否出貨、是否付款、是否取消,以及「是否要求退款」的回傳欄位;任務也明訂不連付款服務、不執行退款,退款只是一個記憶體旗標。

三種資訊要分開看:需求說想要的行為,骨架說目前有哪些欄位,限制說這個示範能做什麼。有退款欄位,不代表取消時就應該把它設成 true。 把需求明說的取消路徑與未決問題分開畫,就看得見這組空白:

https://ithelp.ithome.com.tw/upload/images/20260920/201625778NtyuElRQ5.png
作者依示範需求與骨架重繪,非模型輸出;實線只摘要原句允許的取消行為。

我也讓 Claude Code 畫一次看看。給它同一份 spec.md,工具只留 Read(--tools Read --allowedTools Read),這輪不提供模型改檔工具,要它用 Mermaid 畫出需求明說的轉換並標來源,把沒有依據的轉換另列、註明該找誰確認(2 回合、12.6 秒、費用估值 US$0.04)。

它列出的三個待確認,與上圖相同:已付款是否要求退款、已出貨呼叫取消該回什麼、重複取消是否保持相同結果。

但它多畫了一條「Placed → Shipped:出貨」,超出原句明示的範圍;取消邊沒有照要求標來源;待確認被塞進圖內註記,沒有逐條列起訖狀態與確認角色。找到問題,不代表整張圖就能接受。 RD 要把每條轉換對回原文,移除或另列沒有依據的推論,再把退款與例外交給 Owner。

把尚未知道的目的,留在 intent.md

以訂單題目來說,可以先整理成這份 intent.md;原題沒有提供的 Why,保留待確認:

# 訂單取消的目的
狀態:待需求負責人確認
來源:教學示範題目「讓使用者可以取消尚未出貨的訂單」

## 誰遇到什麼問題
待確認:誰需要取消?目前怎麼處理,又卡在哪裡?

## 期待結果與觀察方式
待確認:希望改善什麼?用什麼資料比較改善前後?
「做出取消功能」是交付內容,還不是改善結果。

## 已知範圍與限制
- 功能要求:取消尚未出貨的訂單。
- 本次示範限制:不連付款服務、不執行退款。

## 尚待決定
- 取消與退款的責任分界。
- 哪個角色確認目的、範圍與期待結果?

這份草稿的價值,是讓不知道的地方有位置可放。不能因為檔名叫 intent,就讓 Claude 替使用者編一個看似合理的痛點。真實工作裡,要從需求訪談或 Jira 補入已確認的答案、來源版本與確認人。

自己試時,先建一個練習資料夾,把上面的草稿存成 intent.md,再把你有權使用的需求原文存成 spec.md,保留來源版本。開啟已安裝並登入的 Claude Code,工作目錄指向這個資料夾,再貼下面的提示。這一步不必先準備程式;想對照同一題,可用配套 repo 的 days/day06/lab/intent/ 材料。

先讀取 intent.md 與 spec.md,不修改程式。
列出你實際讀取的檔案與文件內記載的來源版本;未記載就標未知。
用自己的話重述:誰遇到什麼問題、期待什麼結果、有哪些限制。
將 Spec 的主要行為對回這些目的,指出沒有依據或互相衝突的地方。
intent 中的待確認項目不要補答案,列出需要向人確認的問題。
先交回核對結果,等我確認;這一步不產生實作。

交回來後,先核對三件事:讀到的是否就是這兩份材料、待確認的答案是否被自行補上、每個衝突能否指出來源。少一件就把缺件寫回去,不進實作;這就是這個小練習的完成條件。互動操作與下面保存的 CLI 實跑設定不同,不要求結果逐字一致。

我用這段提示實跑了一次(同樣只留 Read,3 回合、15.5 秒、費用估值 US$0.04)。--output-format stream-json 的 trace 顯示它讀了兩個檔;它沒有替待確認的四項補答案,把主要落差說成一句:「spec 把 RefundRequested 寫進簽名,等於替尚未確認的目的做了技術決策」。 然後列了三個要向人確認的問題,與狀態圖的三個空白相同。提示要求列來源版本、未記載標未知,它也漏了。

但我不接受它對簽名的那個推論:介面有退款欄位,不等於退款的觸發條件已經決定。 它找到值得問的問題,卻把欄位與規則混在一起;讀過兩份文件,仍要核對它怎麼理解。

檔名放在 repo 裡,它會不會自己讀?我另外試了一次:另一個資料夾放相同的兩份材料,提示只說「整理一份驗收草稿」,不提任何檔名(5 回合、24 秒、費用估值 US$0.03)。trace 留下四次 Read:資料夾路徑讀取失敗、README.md 不存在,spec.mdSPEC.md 則讀到同一份內容。它交回六題驗收草稿,卻沒有讀取 intent.md,也沒有處理目的。這次提示和前一次不同,不能據此算出指名檔案的改善率。

我帶走的做法很簡單:重要材料在提示裡點名,再查 trace 的 Read 與回傳內容;不假設檔案放進 repo 就一定被讀到。

先請 Claude 整理驗收依據,不急著寫程式

目的與範圍確認後,才適合把規格整理成可接受的交付條件。下面回到另一個獨立實跑:只用既有 spec.md 找規則缺口,沒有接上前面的 intent 核對,也沒有取得真實需求方的批准。spec.md 是示例檔名,請換成真正的需求檔;用 Jira 的話,先提供有權使用的需求內容與版本,不假設 Claude 已經能讀到工單。

先閱讀 spec.md,不修改程式,也不先替需求補答案。

請整理一份驗收草稿,每項包含:
1. 需求來源:版本、章節或原句。
2. 已明示的行為,以及對應的具體情境。
3. 尚未明示、但會改變實作或驗收結果的問題。
4. 建議由哪個角色確認;無法判定就標待指定。
5. 確認後可用什麼方式驗證。

把「需求明示」「你的推論」「待確認」分開。
來源衝突時列出兩邊,不自行選一邊。
遇到影響本次交付的未決規則,指出受阻範圍與待補決定。
先交回草稿,等確認後再實作。

這次把 Day 3 的需求、骨架與限制寫成 spec.md,讓 Claude Code 只讀材料(4 回合、39 秒、費用估值 US$0.06)。它交回一條明示行為「尚未出貨可以取消」,以及五個待確認問題:

  • 已出貨時,應該怎麼回應?
  • 什麼條件下要把 RefundRequested 設為 true?
  • 已取消的訂單再取消,應該怎麼處理?
  • 回傳的 Order 應保留哪些內容?
  • 未付款的訂單是否也可以取消?

前三題正是說明圖上的三個空白;後兩題圖上沒有,是它多想到的。它把「付款狀態可能影響退款」標成推論,沒有直接當規則,也判斷前兩題會阻擋核心實作。

我接受的是它把空白攤出來,不是它的排序:重複取消能不能稍後處理,要看本輪程式會不會接到這種輸入。 既有規範能回答的由 RD 查,退款責任這類核心決定找 Owner。

草稿本身也要核對。另一次獨立的唯讀實驗,先讓它從縮寫 spec 列問題,再開新 session 帶入草稿與局部退款決策,請它修訂驗收案例。它依決策改了案例,卻在變更表把「已付款」誤寫成「未付款」。格式完整,不能取代內容核對。

用一筆訂單,把模糊的地方問清楚

「取消後處理退款」仍然不夠具體。我會把問題縮成一筆訂單:

這筆訂單已付款、還沒出貨,也尚未取消。使用者按下取消後,本功能是否要回傳 RefundRequested = true?如果不由這裡決定,由哪個流程負責?

這樣 Owner 要回答的是行為與責任,不是評價 Claude 寫得好不好。

為了展示後面的寫法,以下是一條教學用的假設決策:取消功能只改取消狀態,退款交由另一個流程決定,本功能不提出退款要求。 真實工作裡換成 Owner 實際確認的答案與來源。

來源:教學決策 DEMO-DECISION-01(假設,非公司規則)
案例:已付款、未出貨、尚未取消的訂單

Given 訂單 Paid = true、Shipped = false、Cancelled = false
When 使用者取消訂單
Then Cancelled = true
And RefundRequested = false
And 不呼叫付款或退款服務

這時再回看 Day 3 的 refundRequested = order.Paid:對這筆已付款訂單,原實作回傳 true,示例決策要求 false。差別不在多寫一個斷言,而是預期終於有了來源;Owner 若選另一條規則,案例跟著改,不能為了讓測試繼續綠燈反過來改需求。這個案例只處理被圈定的行為,已出貨、重複取消仍待確認。

確認標準之後,程式才有東西可以驗

接下來才把已確認的規則、案例與適用範圍交給 Claude Code 實作。這次的提示只有五句:依已確認的驗收條件實作、逐項標出來源;為可自動驗證的條件加測試、不改預期結果;尚未確認的行為列出受阻範圍、不宣稱完成;能執行就附實際結果;交付時整理驗收條件、修改位置、驗證方式與未決事項。全文在原件 impl/prompt.txt

進入實作前,用 decisions.md 整理依據,避免把退款答案擴大解讀:

  • 本輪確認的情境: 尚未出貨、尚未取消的訂單可以取消;「尚未取消」是本輪選定的起始情境,原需求沒有定義重複取消。
  • 新增教學決策: 已出貨時維持原訂單,不丟例外;已付款取消時不提出退款要求。
  • 沿用限制: 不呼叫付款或退款服務。
  • 仍待確認: 已取消的訂單再次取消,不得自行決定行為。

交給 Claude 的材料是 spec.md、這份決策,以及只有簽名、方法內丟 NotImplementedExceptionCancel 骨架。這次的 --tools--allowedTools 都包含 Read、Grep、Glob、Write、Edit、Bash,才提供寫檔與執行 dotnet 的工具(12 回合、57 秒、費用估值 US$0.15)。

其他四次模型實跑未提供寫入工具:畫圖、intent 核對與不指名實驗只用 Read,驗收草稿還提供 Grep、Glob。runner 保存輸出是另一件事,不代表模型可以改程式。

它產生程式與三個測試,未出貨取消、已出貨維持原狀、已付款取消不要求退款,三項都 PASS,dotnet run 回傳 0。

但我往下讀程式,看到另一件事。下面摘自它交回的實作,省略註解:

if (order.Shipped)
{
    return new CancellationResult(order, RefundRequested: false);
}

var cancelledOrder = order with { Cancelled = true };
return new CancellationResult(cancelledOrder, RefundRequested: false);

第一個分支只擋已出貨。只要未出貨,程式就把取消狀態設成 true,回傳不要求退款;中間沒有先判斷 order.Cancelled。我另外寫了一支只印結果的小程式,把一筆已取消、未出貨的訂單丟進它交回的函式:

INPUT  Shipped=False Paid=True Cancelled=True
OUTPUT Cancelled=True RefundRequested=False threw=false

重複取消的規則還沒定,程式卻已經選了一種回應。 這不表示回傳相同結果一定錯;它可能正是人確認後會採用的冪等行為,只是目前沒有這個決定的依據。Claude 在註解寫著「未確認行為」,也沒替它寫測試,卻讓這個輸入走完函式。

https://ithelp.ithome.com.tw/upload/images/20260920/20162577vT6UECjKJE.png

左側為保存的測試結果;右側那條路徑另以觀察用程式執行過,不在三個測試內。

註解不是阻擋機制。 我承認那三個案例有通過的紀錄,但不接受整個取消功能。補件要求是:請 Owner 決定重複取消的預期,或明確限縮本次交付並提供呼叫端能守住範圍的依據,再補相應驗證。不能由我或 Claude 隨意補一個例外,就說問題解決了。

我會用同一張對照表追到交付,不再另外做一份只有「全部通過」的摘要:

驗收條件 規則來源 驗證方式 目前狀態
上述情境取消後不提出退款要求 DEMO-DECISION-01,教學假設 對照取消狀態與退款旗標的測試 實跑 PASS(含另兩條已確認條件,三項全過)
不呼叫付款或退款服務 原示範任務的限制 核對呼叫路徑與依賴 程式無外部呼叫;未加自動驗證
已取消訂單的重複操作 原需求沒有完整定義 先確認規則,再訂案例 待確認;觀察執行證實會回傳結果,不能接受此範圍

實際工作時,把示例換成需求版本、確認紀錄、程式版本與執行結果,Reviewer 沿著一條條件往回查,不用猜作者心裡的「完成」。這裡有兩種判斷:Spec 是否回應原本的問題,實作是否符合 Spec。這次檢查的是後者;三個測試通過,沒有回答使用者的處境是否改善。

那這次怎樣才算完成?

對這次交付來說,完成是:範圍約定清楚、關鍵規則有確認依據、相應驗證有結果,剩餘問題也有明確處置。 所以這次還不能接受整個取消功能:重複取消的預期未定,程式卻已經給出結果。我要核對四件事:

  • 這次交付到哪裡? 哪些情境包含、哪些排除,先約定。重複取消若不在本輪範圍,還得說明呼叫端怎麼守住這個邊界,不能只在文件寫「不處理」。
  • 預期結果由誰確認? 每條關鍵規則都能找到來源與有權確認的人。
  • 有什麼證據支持接受? 已約定的行為、限制與例外,附上相應的測試或人工查核結果。三項 PASS 只支持那三個案例。
  • 剩下的問題怎麼處理? 會影響本輪接受的未決事項,要解決,或由有權決定的人接受明確的範圍與條件;不能交給 Claude 自行補答案。

這也把 Day 5 的紀錄終點說清楚:Reviewer 核對本輪材料、留下接受或退件理由與時間,一輪審查就記為完成;退件不代表這段人工投入沒發生。審查完成、功能被接受、使用後問題改善,是三件不同的事。 量測時把「因需求未定而補件」單獨標記,下一輪規則先確認後有沒有少,用 Day 5 的尺看。

帶回團隊:沿用 Jira,先試一張需求

我們使用 Jira,不必為了這個做法把需求管理全部搬家。可以先挑一張正在做的工單:

  1. 先確認目的與來源。 在 Jira 留下問題、期待結果與限制,整理成 intent.mdspec.md 保存對應行為與驗收條件。兩份都附工單編號、來源版本與擷取時間,連同有權使用的 Prototype 操作說明交給 Claude。
  2. Claude 整理理解,人核對方向。 明確請它讀取 intent.mdspec.md,先看目的與功能是否對得上,再視需要整理互動或狀態;狀態轉換用狀態圖看,跨服務互動用循序圖看,未決問題列進工單。核心規則找對應 Owner;確認結果回寫 Jira,保留未決範圍。
  3. Claude 提計畫,再實作。 把修改位置與驗證方式整理成 plan.md,由工程師核對;交付時用前面的表把規則、程式與結果接起來。實作發現新問題,記下原本要求、改了什麼、誰確認,再更新規格與測試。

回到一開始:先約好怎樣才算完成

  • 用 intent 留下 Why,再讓 Spec 與 Plan 接上。 先問規格有沒有回應原問題,再問程式有沒有符合規格;測試通過還不等於問題改善。
  • Claude 先整理,人確認關鍵決定。 用具體情境問清行為與例外,再交回實作。
  • 程式驗證已約定的行為。 測試綠燈不能替未確認的業務假設背書,欄位齊全也不代表證據成立。
  • 圖用來暴露理解落差。 Spec 與 Prototype 一起看,依需要整理互動、流程與狀態;圖和測試都要回到來源核對,不能替未決規則補答案。
  • 完成要有範圍、依據、證據與未決事項的處理。 審查可以以退件結束,功能卻還沒被接受。

這次能不能接受,終於有了可以逐項核對的依據。接下來要留下的,是這些決定的理由:換一個任務、換一個接手的人,還能知道當時為什麼這樣約定。


參考資料:

本文實作說明

訂單取消為教學示範案例,程式、測試與 Claude Code 審查皆有實際執行。文中回合、時間與費用取自保存的執行紀錄,費用為 CLI 估值,不代表省時成效;測試通過不代表未確認的業務規則已被接受。退款決策中的教學假設,也不是真實業務批准。

配套 repo:days/day06/lab(diagram、intent、noname、draft、impl、impl-check 六個目錄)、lab-two-stage(兩階段唯讀驗證)。

方法參考

  • Anthropic,Best practices for Claude Code:參考「Let Claude interview you」與「Explore first, then plan, then code」兩節,先訪談、寫規格,再開新 session 實作;規格點名檔案與介面、寫明範圍外,最後做端到端驗證。這是官方建議,不是本篇成效的實證。
  • Anthropic/Louis Claxton,The AI-Native SDLC Playbook(2026-08-21):參考 intent.mdspec.mdplan.md 三份版控產物與簽核分工。本文借用其做法,尚未完成整條流程;官方建議不等於本文已驗證的結果。
  • GitHub,Spec-driven development with AI:spec 承接 what/why,plan 處理實作,各階段都要核對與修訂;並非固定要求另建 intent.md

上一篇
Day 5|先把尺放好,才知道工作有沒有變好
下一篇
Day 7|把工程師腦中的「為什麼」交給 Claude
系列文
買了 Claude Code,然後呢?7
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言