← Back to home

從功能發想到完整規格與實作:vibe coding + SDD的體驗

需求聽起來只有一句話。以往我會直接叫 AI 動手,這次改成先寫規格,結果底下藏著十幾個我沒想過的決定。記錄一次 vibe coding 搭配 SDD 的完整過程,以及為什麼 AI 讓「先寫規格」從太貴變成划算。

#AI#OpenSpec#SDD#開發流程#架構

一句話的需求

我有三個跟台股有關的專案。它們做的事情不同,但都需要把跑完的結果用 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協作撰寫