從功能發想到完整規格與實作:vibe coding + SDD的體驗
需求聽起來只有一句話。以往我會直接叫 AI 動手,這次改成先寫規格,結果底下藏著十幾個我沒想過的決定。記錄一次 vibe coding 搭配 SDD 的完整過程,以及為什麼 AI 讓「先寫規格」從太貴變成划算。
一句話的需求
我有三個跟台股有關的專案。它們做的事情不同,但都需要把跑完的結果用 LINE 訊息推播給我。
一開始只有其中一個專案有 LINE bot,發訊息的程式碼就寫在那個專案裡。後來另外兩個也想發。
我當時的想法很單純:「讓另外兩個專案也能用同一個 bot 發訊息」。聽起來就是一句話的事。
這次我沒有直接叫 AI 動手
以往遇到這種需求,我會直接下一個 prompt:「把 LINE 推播功能也加到另外兩個專案」。AI 大概二十分鐘就能給我一份會動的東西 —— 複製程式碼、複製金鑰,跑起來完全正常。
這次不一樣的地方是,我在這個專案用了 OpenSpec 來管理需求變更。也就是說,動手實作之前,要先把「這個東西應該有什麼行為」寫成一份規格。
所以我先跟 AI 討論架構。討論的結論是:這件事不該複製三份,應該拆成一個獨立的服務。
但真正有價值的是接下來發生的事。 決定拆分之後,AI 開始一個一個提出拆分會衍生的問題,我們逐題討論,有了結論才寫進規格:
- 通知送不出去的時候,算不算整個工作失敗?(資料明明已經處理完了)
- 同一個工作重跑一次,我會不會收到兩則一模一樣的訊息?
- 如果某個頻道根本沒有人訂閱,這算錯誤嗎?
- 有人封鎖了 bot,之後解除封鎖,他原本的訂閱要不要自己回來?
- 金鑰外流的話,對方最多能做到什麼?
- 一個專案有沒有可能發到另一個專案的收件者那裡?
這些問題我一個都沒想過。 但每一個的答案都會改變程式怎麼寫,而且都是那種寫完之後很難改的部分。
比如「重跑會不會收到兩則」。如果一開始沒處理,等到某天你手動重跑一個失敗的工作、收到重複訊息,才回頭去補 —— 那時候要動的是資料庫的結構,不是加一個 if。
拆出去之後,專案端變成什麼樣
我把「發送與接收 LINE 訊息」整件事抽出來,做成一個獨立的服務。
專案端的程式碼因此只剩下一件事:告訴服務「把這則訊息發到這個頻道」。就這樣。
它不再需要處理的東西包括:
- LINE 的金鑰。 金鑰只有一份,在服務裡。專案完全拿不到它。
- 收發訊息的邏輯。 一次最多能發給幾個人、格式怎麼組、失敗要不要重試 —— 這些跟專案本身在做的事一點關係都沒有,以前卻得寫在裡面。
- 好友名單。 誰加了 bot、誰封鎖了、誰解除封鎖了,全部由服務接收 LINE 的通知後自己更新。
- 判斷該發給誰。 專案只說「發到這個頻道」,至於誰訂閱了這個頻道,是服務的事。
專案手上唯一有的,是一張只能發自己頻道的通行證。回測專案的通行證發不了其他頻道的訊息,而且服務認的是通行證本身,不是專案自己宣稱的身分 —— 所以一個專案也無法冒充另一個。
這樣一來,萬一某個專案的設定外流,對方最多只能往那一個頻道發垃圾訊息。我撤銷那一張通行證就好,其他專案不受影響,LINE 帳號本身完全沒事。
換成以前的做法,三個專案各拿一份完整金鑰 —— 任何一份外流,整個 LINE 官方帳號就落在別人手上,而且你不會知道是從哪一份漏的。就像三個人各配一把公司大門鑰匙。
拆分前後對照
| 拆分前(複製三份) | 拆分後(獨立服務) | |
|---|---|---|
| LINE 金鑰有幾份 | 三份,散在三個專案 | 一份,只在服務裡 |
| 專案手上有什麼 | 完整金鑰 | 只能發自己頻道的通行證 |
| 外流的後果 | 整個 LINE 帳號被接管 | 撤銷那一張,其他不受影響 |
| 發訊息的程式碼 | 三份,會慢慢長不一樣 | 一份 |
| 誰要懂 LINE 的規則 | 三個專案都要 | 只有服務 |
| 好友名單 | 各自維護,會對不上 | 服務統一維護 |
| 新增第四個專案 | 再複製一份程式+再給一把金鑰 | 發一張通行證 |
它還會提出這次用不到、但以後會後悔沒做的事
規格討論到一半,AI 問了一件完全不在我需求裡的事:這個服務要不要能同時管很多個 LINE bot?
我當下的反應是「用不到啊」。我就一個 bot。
但它接著說明的理由讓我改變了想法。這種能力事後補的代價,跟現在順手做掉差太多了 —— 資料庫裡幾乎每張表、每次查詢都要改,而且只要漏改一處,就可能發生「A bot 發過的訊息被誤判成重複,所以 B bot 的好友沒收到」。這種錯不會跳出任何錯誤訊息,只會有人默默收不到訊息,可能幾個月後才被發現。
所以最後做了。現在的效果是:以後我開了新的 LINE bot,不用再蓋一套發訊息的東西,把金鑰交給同一個服務就行 —— 兩邊的好友名單、金鑰、訊息完全隔開。
這裡要說清楚的是,我不是主張「把以後可能要的功能都先做」。 那樣只會做出一堆用不到的東西。AI 提出這件事的時候,講的不是「以後可能會用到」,而是現在做跟以後做的代價差多少、以及做錯的時候會不會有人發現。這兩個問題才是判斷的依據。
而我自己一個人做的時候,根本不會停下來問這兩個問題 —— 我甚至不知道有這個問題存在。
vibe coding 讓「先寫規格」從太貴變成划算
「先寫規格再實作」不是新概念,它一直都被認為是好做法。但對個人專案來說,它以前太貴了。
貴在規格全部要人寫。 一份把行為講清楚的規格,光是把腦中模糊的想法變成一條條可以判斷對錯的句子,就要花掉好幾天。而且寫完之後,程式還是得你自己一行行敲。所以絕大多數個人專案都跳過這一步 —— 直接開始寫比較快,這是理性的選擇。
vibe coding 把這個成本結構整個翻過來了。規格的草稿由 AI 產出,我做的事變成讀、質疑、決定。原本要花幾十倍時間才產得出來的東西,現在幾十分鐘就有一份可以開始討論的版本。
而同一件事,也讓先寫規格從「可有可無」變成「不可或缺」。
原因很現實:AI 一口氣產出兩千行程式碼,你有辦法認真 review 嗎?老實說很難。你會看一看、覺得結構合理、跑起來也正常,就過了。
但如果先寫規格,你要 review 的東西就變成三十條情境句,每一條都是一句話能判斷對錯的:
當通知的目標頻道沒有任何有效訂閱者時,工作視為推播成功,不因此失敗。
這句話對不對,我讀一遍就知道。而程式有沒有照這句話做,可以交給測試去驗。
所以 vibe coding 同時做了兩件事:讓規格變得便宜,也讓規格變得必要。 便宜是因為 AI 幫你寫;必要是因為 AI 寫程式的速度已經超過你能審查的速度,你只能退一步,去審查那個更小、更容易判斷的東西。
先寫規格不是為了流程好看,是為了把需要人判斷的部分,壓縮到人真的判斷得完的份量。
小結
拆分的理由其實很單純:同一件事被三個地方需要的時候,它就不該屬於其中任何一個。
但更有價值的收穫是另一件事:我以為那是一句話的需求。如果照以往直接叫 AI 動手,二十分鐘就會有一個「能動」的版本,而底下十幾個問題一個都不會浮出來 —— 它們會等到很久以後,在某個你沒預期的時間點,用「怎麼會收到兩則一樣的訊息」這種形式出現。
先寫規格,就是讓這些問題在還很便宜的時候浮出來。
本文由 Claude Opus 5 high協作撰寫