我們用 SMART——Specific(具體)、Measurable(可衡量)、Achievable(可達成)、Relevant(具關聯)、Time-bound(有時限)——把每個故事拆成五天,作為每次動手造輪子前的五個檢查問題。
本篇是故事五「擔心客戶看不懂 OpenAPI 文件,我急到沒看到 Postman,先刻了一個範例 App」的 Time-bound 篇:何時要完成?何時必須停止研究、重構或自研?
本篇定位:故事五的收尾,替範例、教學工具與正式應用程式建立清楚的生命週期,並整理第五種手擀破輪子模式。
有一天我打開那個 App 的專案,想不起某段程式為什麼要那樣寫。那是趕工時為了繞過一個還沒改好的回應格式加的轉換;API 後來修好了,它沒有跟著拿掉,也沒有人記得。
那時我才意識到:這個 App 沒有任何一個時間點是「結束」。它沒有版本號、沒有支援聲明,也沒有任何條件會讓它被淘汰。它不是產品,因為沒人立項;也不再是範例,因為早就超出示範的規模。它停在中間,一直半成品下去,同時一直被使用。
而 API 那邊已經在討論下一個版本。討論到一半有人問:「那個 App 要不要跟著改?」沒有人知道答案,因為從來沒有人定義過它跟 API 版本的關係。
前四個故事裡,缺時限造成的是研究無限延長、重構停不下來。這個故事不同:問題不是做太久,是做完之後沒有終點——東西交出去了,卻沒有機制決定它什麼時候該退休。
沒有終點的東西會累積三種債。版本債:API 每改一次,它就多一分與現況不符的風險,沒有人負責檢查。資安債:相依套件持續老化,直到某天出現在客戶的盤點清單上。期待債最貴——客戶用得越久,越理所當然地認為它會一直在,而我們從來沒告知過它可能不在。
那份沒有文件、沒有版本的隱形契約會在這裡結出果實:當我們終於停掉這個 App,客戶失去的是已經內建到日常流程裡的一段作業。那時候「這本來只是範例」不會有說服力——說服力靠的是事前聲明,不是事後解釋。
這個故事缺的不是起點,是終點。要補的有四樣。
先寫下期限。 用途、限制與問題管道那份宣告交付當下就該寫好,這裡要補的是它少掉的一欄:到什麼時候為止。期限有兩種訂法——綁 API 大版本(支援到目前這個大版本,下一個大版本推出後不再更新),或綁月份(支援到某月某日,屆時重新檢視)。也要寫上到期時由誰決定續或不續,通常是 API 這一側的負責人,不是最後改過它的那個人。續期要重新確認一次:誰還在用、用在哪一段流程、下一個期限訂到哪裡,再寫進交付紀錄。期限可以寬鬆但必須存在——沒有期限的東西只會被遺忘到出事為止。
寫清楚由誰發布、由誰修補。 支援聲明裡最不能省的一行,是版本發布與安全修補的負責人,要具體到能對上一個角色,不能只是一份好意。如果誠實回答之後答案是「原作者有空時順手處理」,那就等於沒有支援;與其把那一行寫得含糊,不如直接標成不支援,改推薦互動文件、Collection 與 curl 範例。標成不支援不好看,但至少是真的。
為 API 版本變更設定同步檢查。 把範例與教學資產納入改版檢查清單:規格更新了,對應的 Collection、curl 與 SDK 範例要一起重跑,壞的就修,或標記為不再支援。這件事最好接上流程,別靠記性——放進發版檢查項目,或讓那組請求範例可以被自動執行。
設定升級門檻。 寫清楚什麼條件成立時,這個東西要停止當範例:客戶把它用在正式營運、使用者超出示範用途、出現權限與紀錄查核的需求,或第二個客戶要求同一套介面。門檻的意義是把「不知不覺變成產品」換成「有人做了一個決定」;要不要另外立案,就是門檻觸發那一刻做出的一次決定,而不是無限期拖著等它自己長大。退場同樣要有路徑:停用不等於關掉伺服器,得附上替代方案與一段告知期。沒有替代路徑的退場,才會變成信任問題。
這個故事的手擀破輪子模式是第五種,也最難自我察覺:還沒問清楚使用者卡在哪裡,就先替他做一套產品。
前四種都是替自己解題,改造的是讓自己不安心的那一塊——有時候因為不熟,有時候因為太熟。第五種調轉了方向:我對自己的 API 沒有不安,不安的是「客戶可能不懂」。於是我把猜測當成需求、把體貼當成授權,做出一個沒有人下訂單的東西。它偽裝得比前四種都好,因為過程中每個人——包括我——都覺得這是在服務客戶。
回頭看,我本來只是怕客戶不會使用輪子,最後卻先替他做了一台沒有保固、沒有說明書,也不知道誰要維修的車。而客戶真正需要的,可能只是有人指著輪子告訴他:這裡抓、這樣轉,轉不動時通常是這個原因。
五個故事到這裡走完了。它們相似的地方在哪裡、能不能在動手之前就認出來,是接下來五天要處理的事。要做的是把這五次的經過攤在同一張桌上,試著把「別再手擀破輪子」變成一套真的拿得出來用的判斷方法。