昨天完成了 PRD 文件,確定了 DDD + BDD 的混合開發模式。今天要實踐這個策略:用 Event Storming 挖掘領域知識,用 BDD 定義行為場景,最後轉化為精準的 User Story。
記帳是一個領域知識密集但用戶行為簡單的應用。DDD 幫我們理解金錢、週期、預算這些複雜概念,BDD 確保用戶的每個動作都符合預期。
今天的目標:結合兩種方法論的優勢,產出可執行的需求規格。
我和 AI 開始了虛擬的 Event Storming 工作坊。第一步:不管順序,列出所有可能的領域事件。
初始事件風暴(30分鐘):
💰 支出領域
- 支出已記錄 (ExpenseRecorded)
- 支出已分類 (ExpenseCategorized)
- 支出已修改 (ExpenseModified)
- 分類已學習 (CategoryLearned)
- 重複支出已識別 (DuplicateExpenseDetected)
📊 預算領域
- 預算已設定 (BudgetSet)
- 預算已消耗 (BudgetConsumed)
- 預算已超支 (BudgetExceeded)
- 預算警告已觸發 (BudgetWarningTriggered)
- 預算已重置 (BudgetReset)
🔄 訂閱領域
- 訂閱已識別 (SubscriptionIdentified)
- 訂閱已創建 (SubscriptionCreated)
- 帳單已生成 (BillGenerated)
- 訂閱已續約 (SubscriptionRenewed)
- 訂閱已取消 (SubscriptionCancelled)
🤖 AI 領域
- 模式已識別 (PatternIdentified)
- 信心度已更新 (ConfidenceUpdated)
- 異常已偵測 (AnomalyDetected)
- 建議已生成 (RecommendationGenerated)
📈 報表領域
- 資料已聚合 (DataAggregated)
- 報表已生成 (ReportGenerated)
- 洞察已發現 (InsightDiscovered)
- 趨勢已分析 (TrendAnalyzed)
命令對應表:
觸發者 | 命令 | 事件 |
---|---|---|
用戶 | RecordExpense | ExpenseRecorded |
AI分類器 | CategorizeExpense | ExpenseCategorized |
用戶 | CorrectCategory | CategoryLearned |
系統排程 | CheckSubscriptions | BillGenerated |
預算監控器 | CheckBudgetStatus | BudgetWarningTriggered |
分析引擎 | AnalyzeSpending | PatternIdentified |
發現了四條主要時間軸,彼此交織但各自獨立:
時間軸 1:即時記帳流(Real-time Entry Flow)
用戶輸入 → 文字解析 → AI分類 → 儲存確認 →
預算檢查 → 模式學習 → 統計更新
時間軸 2:訂閱生命週期(Subscription Lifecycle)
重複偵測 → 訂閱建議 → 用戶確認 →
週期計算 → 定期生成 → 續約/取消
時間軸 3:預算守護流(Budget Guardian Flow)
預算設定 → 即時追蹤 → 閾值檢查 →
智慧提醒 → 用戶調整 → 週期重置
時間軸 4:洞察生成流(Insight Generation Flow)
資料累積 → 模式分析 → 異常識別 →
洞察生成 → 故事化呈現 → 建議行動
Event Storming 過程中浮現的核心業務規則:
規則 1:分類學習規則
規則 2:訂閱識別規則
規則 3:預算彈性規則
規則 4:智慧提醒規則
現在把 Event Storming 發現的領域知識,轉換成 BDD 的 Given-When-Then 場景。
Feature: 快速自然語言記帳
作為一個懶惰的用戶
我想要用最簡單的方式記帳
以便不會因為麻煩而放棄
Background:
Given 我已經登入 PocketSmart
And AI 分類服務正常運作
Scenario: 極簡輸入 - 只有描述和金額
Given 我在記帳輸入框
When 我輸入 "咖啡 120"
Then 系統應該解析出金額 120 元
And 描述應該是 "咖啡"
And AI 應該自動分類為 "飲料"
And 整個過程應該在 3 秒內完成
Scenario: 智慧學習 - 記住我的習慣
Given 我曾經將 "麥當勞" 分類為 "正餐"(而非預設的"速食")
When 我輸入 "麥當勞 150"
Then AI 應該分類為 "正餐"
And 顯示 "根據您的習慣" 提示
Scenario: 低信心度處理 - 不確定時詢問
Given 這是我第一次輸入 "美廉社"
When 我輸入 "美廉社 523"
And AI 信心度低於 70%
Then 顯示分類選項 ["日用品", "食材", "其他"]
And 預選最可能的選項
And 記錄我的選擇供未來學習
Scenario: 批量記帳 - 一次記多筆
Given 我想要補記多筆消費
When 我輸入:
"""
早餐 65
捷運 30
午餐 120
"""
Then 系統應該識別出 3 筆消費
And 分別正確分類
And 顯示批量記帳成功
Feature: 智慧訂閱識別與管理
作為一個有很多訂閱的用戶
我想要系統自動追蹤我的訂閱
以便了解真實的固定支出
Scenario: 自動識別訂閱
Given 我在過去兩個月記錄了:
| 日期 | 描述 | 金額 |
| 1/15 | Netflix | 390 |
| 2/15 | Netflix | 390 |
When 我輸入 "Netflix 390" 在 3/15
Then 系統應該提示 "這似乎是訂閱服務"
And 詢問 "是否設為每月自動記錄?"
When 我確認是訂閱
Then 創建月付訂閱 "Netflix"
And 下次扣款日設為 4/15
Scenario: 訂閱異常提醒
Given 我有一個訂閱 "Spotify" 每月 15 號扣款 149 元
And 現在是 3/20
And 本月還沒有 Spotify 的記錄
When 系統執行每日檢查
Then 發送提醒 "Spotify 本月尚未扣款,是否已取消?"
Scenario: 訂閱成本透明化
Given 我有以下訂閱:
| 名稱 | 月費 | 類型 |
| Netflix | 390 | 娛樂 |
| ChatGPT | 600 | 工具 |
| iCloud | 30 | 工具 |
When 我查看訂閱總覽
Then 顯示月總成本 1,020 元
And 顯示年度成本 12,240 元
And 按類別顯示佔比圖表
Feature: 智慧預算管理
作為想要控制支出的用戶
我想要有彈性的預算管理
以便在不感到壓力的情況下省錢
Scenario: 漸進式預算警告
Given 我的餐飲預算是每月 5,000 元
And 目前已消費 4,000 元
When 我記錄一筆餐飲支出 200 元
Then 顯示黃色提醒 "餐飲預算已使用 84%"
And 顯示剩餘額度 800 元
And 提供建議 "剩餘 10 天,建議每日 80 元"
Scenario: 預算超支協商
Given 我的娛樂預算是每月 2,000 元
And 目前已消費 2,000 元
When 我嘗試記錄 "電影票 350"
Then 顯示確認對話框:
"""
娛樂預算已用完,這筆支出會超支 350 元
[堅持記錄] [改為其他分類] [取消]
"""
When 我選擇 "堅持記錄"
Then 記錄支出但標記為超支
And 月報表中特別標示
Scenario: 智慧預算建議
Given 這是我第一次設定預算
And 我過去 3 個月的消費記錄存在
When 我點擊 "AI 建議預算"
Then 基於歷史資料顯示:
| 類別 | 平均消費 | 建議預算(適中) |
| 餐飲 | 4,800 | 5,000 |
| 交通 | 1,200 | 1,500 |
| 娛樂 | 2,500 | 2,000 |
And 提供說明 "娛樂建議降低因為上月有演唱會異常支出"
Feature: 個人化消費洞察
作為想要了解消費習慣的用戶
我想要有意義的分析報告
以便做出更好的財務決定
Scenario: 月度故事化報告
Given 月底系統生成報告
When 我查看 3 月報告
Then 看到故事化描述:
"""
【3月消費故事】
本月總支出 24,500 元,比上月減少 8%!
🏆 最大成就:餐飲支出降低 1,200 元
⚠️ 注意事項:訂閱服務增加了 Netflix(390元/月)
💡 發現模式:週五的餐飲支出是平日的 2.3 倍
如果保持這個節奏,年底可以多存 15,000 元!
"""
Scenario: 異常消費警示
Given 我平常的單筆餐飲消費都在 200 元以下
When 我輸入 "聚餐 1,200"
Then 標記為異常消費
And 詢問 "這是特殊情況嗎?"
When 我標記為 "特殊"
Then 不計入平均消費
And 在報表中分開顯示
Scenario: 個人化省錢建議
Given 系統分析我的消費模式
When 月中觸發分析
Then 提供具體可行的建議:
"""
💰 省錢機會發現:
1. 每週五的下午茶平均 180 元
→ 改為每兩週一次,月省 360 元
2. Netflix 與朋友共享
→ 月省 195 元
3. 早餐從超商改為早餐店
→ 根據歷史資料,平均可省 20 元/次
預估月省總額:1,155 元
"""
結合 DDD 的領域事件和 BDD 的行為場景,我們可以寫出更精準的 User Story,並且包含清晰的驗收條件。
User Story 1.1:自然語言快速記帳
標題: 三秒完成記帳
角色: 懶惰的記帳用戶
故事:
As a 懶惰的記帳用戶
I want to 用一句話完成記帳
So that 不會因為麻煩而放棄記帳
驗收條件 (BDD):
Scenario: 基本記帳
Given 我在記帳頁面
When 輸入 "拿鐵 120"
Then 3秒內完成記帳
And 自動分類為 "飲料"
Scenario: 批量補記
When 輸入多行文字
Then 每行都被正確解析
And 失敗項目單獨標記
領域事件:
- ExpenseRecorded
- ExpenseCategorized
- CategoryLearned
估點: 8
優先級: P0
User Story 1.2:AI 分類學習
標題: 記住我的分類習慣
角色: 有固定消費模式的用戶
故事:
As a 有固定消費模式的用戶
I want to 系統記住我的分類偏好
So that 不用每次都手動選擇
驗收條件 (BDD):
Scenario: 學習用戶習慣
Given 我修正過 3 次同類分類
When 再次輸入相似消費
Then 自動採用我的分類
And 顯示 "根據您的習慣"
Scenario: 低信心度處理
When AI 信心度 < 70%
Then 提供分類選項
And 記錄選擇供學習
領域事件:
- CategoryLearned
- ConfidenceUpdated
- PatternIdentified
估點: 5
優先級: P0
User Story 2.1:自動識別訂閱
標題: 發現我的訂閱服務
角色: 訂閱多個服務的用戶
故事:
As a 訂閱多個服務的用戶
I want to 系統自動發現訂閱
So that 清楚知道固定支出
驗收條件 (BDD):
Scenario: 重複支出識別
Given 連續2個月相同金額
When 第3次出現
Then 提示轉換為訂閱
Scenario: 關鍵字識別
When 描述含"月費"
Then 直接建議創建訂閱
領域事件:
- SubscriptionIdentified
- SubscriptionCreated
- BillGenerated
估點: 8
優先級: P1
User Story 2.2:訂閱異常管理
標題: 訂閱異常提醒
角色: 容易忘記取消訂閱的用戶
故事:
As a 容易忘記的用戶
I want to 收到訂閱異常提醒
So that 及時處理訂閱變化
驗收條件 (BDD):
Scenario: 未扣款提醒
Given 超過預期扣款日 5 天
When 系統每日檢查
Then 發送提醒確認狀態
Scenario: 金額變動提醒
When 扣款金額與設定不同
Then 提醒並更新資訊
領域事件:
- AnomalyDetected
- SubscriptionCancelled
- NotificationSent
估點: 5
優先級: P1
User Story 3.1:彈性預算管理
標題: 人性化的預算控制
角色: 想省錢但不想被限制的用戶
故事:
As a 想控制支出的用戶
I want to 有彈性的預算管理
So that 不會因太嚴格而放棄
驗收條件 (BDD):
Scenario: 漸進式提醒
Given 預算消耗 80%
Then 溫和提醒剩餘額度
Scenario: 超支協商
Given 預算已用完
Then 詢問是否繼續
And 可選擇其他分類
領域事件:
- BudgetConsumed
- BudgetWarningTriggered
- BudgetExceeded
估點: 5
優先級: P2
User Story 4.1:故事化月報表
標題: 看得懂的月度報告
角色: 不懂財務但想理財的用戶
故事:
As a 不懂財務的用戶
I want to 看到故事化的報告
So that 真正理解我的消費
驗收條件 (BDD):
Scenario: 月度故事生成
Given 月底
When 生成報告
Then 用故事描述消費
And 標出關鍵成就
And 提供具體建議
領域事件:
- ReportGenerated
- InsightDiscovered
- TrendAnalyzed
估點: 8
優先級: P1
DDD 的事件告訴我們「系統裡會發生什麼」,BDD 的場景告訴我們「用戶期待什麼行為」。兩者結合,我們得到了:
DDD 強調建立通用語言,BDD 的 Gherkin 語法天然就是通用語言。當我說「訂閱已識別」,無論是領域專家、開發者還是測試人員,都理解是什麼意思。
每個 User Story 都有對應的 BDD 場景,每個場景都觸發特定的領域事件。這讓我們的程式碼有了雙重保障:
AI 在這個過程中扮演了多重角色:
經過今天的 DDD + BDD 雙重設計,我們得到了: