Functional Spec Partner — 七步工作流詳解

本檔為 SKILL.md 引用的詳細工作流指南。在每次對話開始前讀一次。


前置條件

進入本工作流前確認:

  1. requirement/{feature}/index.md 已存在且可讀。沒有它,這層沒輸入,停下。
  2. 使用者明確要產出這份 feature 的 functional spec,不是「順便看看」。
  3. feature 名與 requirement 同名(同名成組是可追溯性的基石)。

不符合任一條 → 明說缺什麼、停下,不要替使用者跳過 Stage 1。


步驟 1 — 定位 requirement 輸入

目標:讀完 Stage 1 的產出,建立自己的脈絡,再開始草擬。

操作

  1. requirement/{feature}/index.md
    • Problem statement(一句話)
    • Stakeholders(誰提的、誰受影響)
    • 素材清單(每筆來源、日期、簡述)
    • 未解問題清單
  2. 視需要瀏覽 requirement/{feature}/raw/notes/
  3. 檢查 spec/{feature}/{feature}.fp.md 是否已存在:
    • 存在 → 視為延續編輯,讀過後與使用者對齊是補洞還是改既有條目。
    • 不存在 → 全新 spec。

與使用者對齊

我讀過 requirement/{feature}/index.md,看到:
- Problem statement:…
- {N} 個未解問題(最關鍵的是 X、Y)
- 素材主要來自 {來源}

我打算先草擬 {M} 個 use case 給你挑,先從 {第一個} 開始。OK 我就開始。

異常

  • requirement 不存在 → 「Stage 1 還沒輸出,我這層沒輸入。要回去補還是先停?」由使用者決定。
  • requirement 有未解問題但使用者要繼續 → 把未解問題標進 spec 的「待裁定」區,腦補。

步驟 2 — 草擬 Use Cases

目標:把 requirement 中的需求點轉成結構化 use case 草稿,請使用者挑錯。

一次一個草稿

Use Case A1: 細排既有工單

- Actor:排程員
- 觸發條件:在排程主畫面按「細排」
- 行為:
  1. 系統載入目前未完成工單清單
  2. 依加型/扣型分組
  3. 套用產能限制,產生排程結果
  4. 顯示結果於甘特圖
- 預期結果:所有可排工單已分配時段;無法排者列入未排清單
- 例外路徑:見 §邊界條件 B2、B3

這個草稿你看:
- Actor 對嗎?
- 行為步驟有沒有漏?
- 預期結果這樣寫夠不夠具體?

涵蓋面檢查

每個 use case 都問:

  • Happy path 有沒有寫到?
  • 主要 alternate path 有沒有列?(例如:失敗、取消、超時、無資料)
  • Actor 是不是同一個?多 actor 流程要切多個 use case 還是用 swimlane?

對 requirement 逐項回溯

requirement index.md 提到 5 個需求點,我目前的 use case 對應:
- 需求 R1 → UC A1
- 需求 R2 → UC A2
- 需求 R3 → UC A1(同一條流程的延伸)
- 需求 R4 → 我把它列為「明確不做」對嗎?
- 需求 R5 → 還沒對應,這個是漏了還是不在範圍?

漏的逐條對齊。Exit Gate 第 1 條就是「涵蓋 requirement 中所有列入範圍的 user need」。

不要做

  • ❌ 一次給三個 use case 倒著問「都對嗎」
  • ❌ 把 requirement 沒寫的需求腦補成 use case
  • ❌ Scope 決定(做/不做)自己拍板 — 一律請使用者選

步驟 3 — 建流程圖/狀態機

目標:用 Mermaid 把核心 use case 的流程或狀態轉換畫出來。

選 flowchart 還是 state diagram

情境
使用者操作流程、系統處理步驟flowchart
物件/資源在不同狀態間轉換(工單從 NEW → SCHEDULED → DONE)stateDiagram-v2
兩者都要切兩張圖,各畫各的

範例(flowchart)

flowchart TD
    Start[排程員按細排] --> Load[載入未完成工單]
    Load --> Empty{有工單嗎?}
    Empty -- 否 --> Done[顯示空清單]
    Empty -- 是 --> Group[依加型/扣型分組]
    Group --> Schedule[套用產能限制排程]
    Schedule --> Fail{全部可排?}
    Fail -- 是 --> Show[顯示甘特圖]
    Fail -- 否 --> Partial[排可排的+列出未排清單]
    Partial --> Show

規則

  • Label 寫人話,不寫程式碼
  • 條件節點用 {},動作節點用 []
  • 一張圖一個主題;超過 15 個節點就拆
  • 流程中的每個決策點要在後面的「邊界條件」段對應到一條規則

與使用者對齊

這張流程圖你看:
- 主要路徑(NEW → SCHEDULED → DONE)對嗎?
- 「全部可排」這個決策點我看 requirement 沒明寫,要不要也把「部分可排」單獨成一個分支?

步驟 4 — 逼出 I/O 範例

目標:每個 use case 給正常值、邊界值、異常值三組具體輸入輸出。

格式

### Use Case A1 的 I/O 範例

#### 正常值
- input:
  - 工單清單 = [
      { id: 1042, type: 加型, qty: 100, dueDate: 2026-06-15 },
      { id: 1043, type: 扣型, qty: 50, dueDate: 2026-06-20 }
    ]
  - 產能 = { 2026-06-01: 8h, 2026-06-02: 8h }
- output:
  - 排程結果 = [
      { orderId: 1042, scheduledAt: 2026-06-01T08:00, duration: 4h },
      { orderId: 1043, scheduledAt: 2026-06-01T12:00, duration: 2h }
    ]
  - 未排清單 = []

#### 邊界值
- input:
  - 工單清單 = [ 500 張同型工單 ]
  - 產能 = { 2026-06-01: 8h }
- output:
  - 排程結果 = [...前 N 張...]
  - 未排清單 = [...剩下的 500-N 張,含原因「產能不足」...]

#### 異常值
- input:
  - 工單清單 = []
- output:
  - 排程結果 = []
  - 未排清單 = []
  - (不報錯,視為合法空輸入)

規則

  • 必須有實際值 — LongStringorderId、「成功訊息」全部不收
  • 日期用 ISO 8601 或人類可讀格式,挑一種一致使用
  • 集合不要寫「等等」— 至少列兩三筆代表性元素
  • 異常值至少一條,不要省

寫不出來怎麼辦

寫不出具體值 = spec 還沒清楚。回 use case 步驟把該條補細,或標進「未解問題」。不要捏假值充數。


步驟 5 — 列邊界條件 / 異常情境

目標:把流程圖中的決策點、I/O 範例中的異常值,整理成枚舉式的邊界條件表。

格式

### 邊界條件

| 編號 | 條件 | 結果 |
|---|---|---|
| B1 | 工單清單為空 | 回傳空結果,不報錯 |
| B2 | 工單數量 ≤ 0 | 報 InvalidQuantityException |
| B3 | 產能完全為 0 | 全部工單進未排清單,標示原因「無產能」 |
| B4 | 工單交期早於今日 | 仍依規則排,但在結果標 `overdue: true` |
| B5 | 同型工單超過 500 張 | 依排序規則處理,不分批 |

涵蓋面檢查

  • 流程圖每個 {} 決策節點都有對應的一條邊界條件嗎?
  • I/O 範例的「異常值」都有對應的邊界條件嗎?
  • requirement 的未解問題中是否有變成邊界條件的?

編號是契約

B1B2 等編號之後會被 use case 的「例外路徑」、Stage 4 的 pseudo code §編號 引用。一旦寫出就append-only

  • 新條件加新編號(B6、B7…)
  • 廢棄條件用 ~~刪除線~~ + 廢棄原因,不要重編號

步驟 6 — (可選)寫驗證 Python script

目標:把核心邏輯短腳本跑一次,確認 spec 自洽。

何時寫

  • 流程含演算法或多步決策(細排、配料、產能扣減)
  • 邊界條件多、彼此交互影響
  • 使用者明確要 demo

何時不寫

  • 純 CRUD(新增/查詢/修改/刪除)
  • 純 UI 互動(按鈕觸發某個顯示)
  • 純資料查詢、報表

範例骨架

# spec/{feature}/{feature}.fp.validate.py
"""
驗證 spec/{feature}/{feature}.fp.md 的 I/O 範例是否自洽。
跑法:python {feature}.validate.py
"""
 
def schedule(orders, capacity):
    # 對應 functional-spec §UC A1 行為步驟
    ...
    return scheduled, unscheduled
 
# I/O 範例 — 正常值
orders = [
    {"id": 1042, "type": "加型", "qty": 100, "dueDate": "2026-06-15"},
    {"id": 1043, "type": "扣型", "qty": 50, "dueDate": "2026-06-20"},
]
capacity = {"2026-06-01": 8, "2026-06-02": 8}
 
scheduled, unscheduled = schedule(orders, capacity)
assert len(scheduled) == 2
assert unscheduled == []
 
# I/O 範例 — 邊界值(500 張同型)
...

規則

  • 腳本只驗證 spec 自洽,是實作雛形
  • 跑得通 ≠ 設計正確;只代表「I/O 範例不矛盾」
  • 跑不通 → spec 有洞,回去補

步驟 7 — 組裝 + 請人簽核

目標:寫檔、留簽核欄位、提示後續。

操作

  1. output-template.md 組裝完整文件
  2. 寫入 spec/{feature}/{feature}.fp.md
  3. 文件底部留簽核欄位(姓名 + 日期,由使用者自己填)
  4. 提示:
    • 「簽核欄位請你填名 + 日期,這份才算定稿(Exit Gate 第 5 條)」
    • 「路徑可加進 ticket」

收尾話術

這份 functional spec 我們確認了:
- {N} 個 use case(A1 ~ A{N})
- {M} 張流程圖/狀態機
- 每個 use case 三組 I/O 範例
- {K} 條邊界條件(B1 ~ B{K})
- {有/沒有} 驗證 script

我會:
1. 套 output-template 組裝
2. 寫到 spec/{feature}/{feature}.fp.md
3. 留簽核欄位給你填

可以嗎?

異常情境

使用者要求「跳過 use case 直接畫流程圖」

可以加速,但不要省。流程圖的每個決策節點要對得回某個 use case 的行為步驟,沒有 use case 的流程圖是孤兒。

流程圖我會畫,但我需要先知道是哪個 use case 的流程。我快速列三個候選 use case(A1/A2/A3),你挑一個我直接畫,OK?

使用者堅持要寫 class diagram

class diagram 是 Stage 3 OOA 的事,這份 spec 寫了反而會跟 OOA 文件衝突。
這層我們只到「對外觀察點」— 例如 input/output、流程、邊界。
要不要記成「下一步交 OOA 處理」?

使用者答不出某個 use case 的 alternate path

不要腦補。記成 use case 內的「待裁定 alternate path」並標進文件,明說此 use case 在這點上尚未 Exit Gate ready。

I/O 範例的具體值需要查資料

如果使用者答不出具體值(例如「客戶實際資料長什麼樣」),可選:

  • 具體值待確認 並繼續
  • 暫停這個 use case,先處理其他

不要用「example_value_123」這種假值寫進去,那會在 OOA / Code 時被當真。