iT邦幫忙

2026 iThome 鐵人賽

DAY 5
0
Vibe Coding

從 GAS 到 Cloudflare D1:AI Agent 如何打造、接手並重構真實便當系統系列 第 5

Day 5|一家店變成多家店後,原本固定的東西全變成資料

  • 分享至 

  • xImage
  •  

Day 5

Day 4 談到,當便當系統真的開始被使用後,一筆訂單就不再只是一列資料。

它會影響店家要準備幾份、不同樓層怎麼分餐,甚至牽涉到使用者的餘額與信任。

但那時候我還沒有完全意識到另一件事。

一開始很多流程之所以看起來很簡單,不一定是因為系統真的很簡單。

而是因為:

環境偷偷幫系統回答了很多問題。

例如:

  • 店家是哪一家?
  • 今天用哪份菜單?
  • 一份多少錢?
  • 幾點截止?
  • 哪些餐點今天可以訂?

當系統只服務固定店家時,這些問題甚至不需要被「設計」。

答案一直都一樣。

所以我很自然地把它們當成背景。

直到後來開始增加其他店家。

我第一個直覺也很單純:

多一家店,不就是多一個選項嗎?

做下去才發現,完全不是。


單一店家時,很多規則只是「被藏起來」

假設一開始系統只有一家便當店。

那很多事情可以非常直覺:

店家 = 固定
菜單 = 固定
價格 = 固定
截止時間 = 固定

甚至根本不需要特別問:

這份菜單是誰的?

因為只有一個答案。

也不用特別想:

這個價格從哪一天開始有效?

因為大家看的都是現在這份菜單。

這種做法在系統早期沒有什麼問題。

反而很合理。

因為當時最重要的是把真實流程跑起來,而不是先建立一套可以支援所有未來可能性的抽象模型。

但第二家店出現之後,原本那些「不用回答的問題」就全部回來了。


多一家店,不只是多一個 Vendor 欄位

當店家從一變成二,表面上看起來最直覺的改法就是:

Order
+ vendor

畫面再多一個下拉選單:

請選擇店家

好像就結束了。

但很快會發現,跟著店家一起變動的東西遠比一個名稱多。

原本像常數的東西 多店家後要回答的問題
店名 這筆訂單到底屬於哪一家店?
菜單 每家店現在使用哪一份?
價格 同一餐點在不同時間價格是否一樣?
截止時間 每家店、每種開團方式是否相同?
停售狀態 某個餐點今天還能不能訂?
菜單圖片/連結 管理者與使用者要看哪一個版本?

這時候我才清楚感覺到:

原本是環境常數的東西,開始變成 Domain Data。

這和「多加幾個欄位」是兩件完全不同的事。


Domain Data 的差別,是它開始有自己的生命週期

一般欄位很容易只考慮:

現在值是多少?

但店家、菜單、價格這類資料麻煩的地方,是它們會變,而且「現在的答案」不一定能代表「當時的事實」。

例如今天菜單價格是:

A 餐 100 元

幾個月之後變成:

A 餐 110 元

如果系統只保存現在價格,那一個很自然的問題就出現了:

三個月前那張 100 元的訂單,現在到底應該顯示多少?

如果直接拿現在菜單重新組畫面,歷史就可能被今天的狀態改寫。

店名也一樣。

系統裡曾經出現過名稱不一致的情況,因此後來需要做店家的 canonicalization,也就是:

系統內部先判斷「它到底是不是同一家店」。

但這不代表要把所有舊訂單上的文字全部改成今天最新的名字。

因為「現在怎麼稱呼這家店」和「當時那筆訂單記錄了什麼」是兩種不同責任。

所以後來我會先把這類資料粗略分成三種:

類型 例子 主要責任
Current Configuration 現在店名、目前菜單、截止設定 支援現在的操作
Effective Data 某段期間有效的菜單、價格 判斷某時間點應使用什麼
Historical Snapshot 訂單成立時的品項、價格、店家資訊 保留已發生的事實

這裡最重要的不是一定要做出多複雜的版本表。

而是先辨認:

哪些資料可以直接覆蓋,哪些不能。

否則很容易發生一件危險的事:

今天改了一份菜單,昨天的世界也跟著變了。

對現在畫面來說,那可能只是「資料同步」。

對歷史訂單來說,卻是在改寫事實。


Vendor Hub 就是這種變化的結果

後來系統裡出現了 Vendor Hub。

如果只看畫面,它很容易被理解成:

做了一個管理店家的新頁面。

但對我來說,它更像是一個訊號。

代表「店家」已經不再只是散落在程式裡的一個字串。

它開始需要集中管理:

  • 店家資訊
  • 菜單來源
  • 菜單圖片
  • 外部菜單連結
  • 顯示名稱
  • 截止相關資訊

換句話說,Vendor Hub 不是因為我突然想做後台。

而是因為 Domain 已經長到:

這些東西需要有一個正式的位置。


我後來會用這四個問題抓「隱藏常數」

回頭看,這次最大的技術收穫不是 Vendor Hub 本身。

而是一個之後很常用的檢查方式。

看到一個目前寫死、固定或只有單一答案的東西時,我會問:

  1. 它永遠只有一個值嗎?
  2. 它未來會隨時間改變嗎?
  3. 歷史資料需要保留當時的值嗎?
  4. 不同角色或流程會不會需要不同答案?

如果其中兩三題開始回答「會」,

那它通常已經不只是常數。

它正在變成:

需要被正式建模的 Domain Data。


但也不是所有常數都要立刻抽象化

這裡也有另一個很容易踩的坑。

知道「寫死的東西未來可能變」之後,很容易開始走向另一個極端:

那乾脆所有東西一開始都做成設定檔、版本表、規則引擎。

這通常也不是好答案。

如果 Day 3 的第一版就先為:

  • 十家店
  • 多種菜單版本
  • 複雜有效期間
  • 未來所有截止模式

全部建模,

很可能只是把還沒發生的問題提前做一遍。

所以我現在比較傾向:

先讓真實變化證明抽象化的必要,再把已經出現的變化整理成模型。

不是看到任何常數就消滅它。

而是當現實已經出現第二種答案時,不再假裝只有一種答案。


系統開始長大的訊號,不一定是 Code 變多

Day 3 的 GAS + Sheets 解決的是:

怎麼快速把流程搬到手機。

Day 4 開始面對的是:

當資料真的承擔訂單與金額責任後,要怎麼讓它可信。

到了 Day 5,我看到的是另一種成長:

原本藏在環境裡的假設,開始一個一個被拉進系統裡。

店家不再固定。

菜單不再只有一份。

價格會變。

截止方式會變。

歷史也不能跟著現在一起改。

系統變複雜的原因,不是我突然想加更多功能。

而是現實世界開始給出:

第二個答案。

而一套原本只為「唯一答案」設計的系統,

就必須開始學會怎麼管理差異。


本系列實作專案

這不是純概念示範,而是一套持續開發中的便當訂購系統。文章著重「為什麼」,GitHub 保留實際程式碼、文件與演進紀錄。

GitHub:https://github.com/henryfir456/bento-order-app


下一篇

做到這裡,GAS + Sheets 仍然可以繼續工作。

功能也沒有突然壞掉。

讓我開始重新思考架構的,不是「使用人數一多,系統就撐不住」,而是一件更日常、也更容易被忽略的事:

幾乎每一個主要操作,都要等。

登入,等個 1~3 秒。

打開訂單資料,等。

需要重新取得資料,再等。

最後送出訂單,還是要等。

單看其中任何一次,好像都不算嚴重。

系統最後也都有正常回應。

但這是一個每天都會使用的便當系統。

當這些等待散落在整個操作流程裡,「功能可以完成」和「操作起來順不順」開始變成兩件不同的事。

我也第一次明確意識到:

系統效能不一定要慢到不能用,才值得處理。

下一篇,我想談的就是這件事:

GAS 明明還能用,我為什麼還是開始想把它搬走?


上一篇
Day 4|當 GAS + Sheets 真的開始被使用後,試算表就不再只是試算表
下一篇
Day 6|功能都正常,為什麼我還是決定離開 GAS?
系列文
從 GAS 到 Cloudflare D1:AI Agent 如何打造、接手並重構真實便當系統9
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言