"Pos" 2026-07-17
自持狀態與可導出狀態:上游身份轉移時,誰要搬家、誰自動對齊
後端合併操作讓資料換了身份,前端持有的多份「以舊 id 為 key」的狀態怎麼辦?POS App 的答案分兩類:能從上游重新導出的狀態不用管、下一輪同步自動對齊;必須自行持有的狀態(差異比對基準、追蹤記錄)才需要通知搬家。分類錯誤的代價是兩個方向的 bug。 2026-07-17
單調狀態機與樂觀更新的回滾契約:前台不得顯示後端沒記錄的狀態
POS App 的品項處理狀態只能遞增——現實世界的動作不可逆,狀態機跟著不可逆。樂觀更新讓 UI 先行,但後端拒絕時必須回滾:因為這個狀態是其他防護規則的資料來源,前台多顯示一格進度,防護就會在錯誤的前提上放行。 2026-07-17
跨邊界參照的生命週期:前端凍結的 id,死活由後端決定
POS App 的前端把後端資料的 id 凍結在本地追蹤記錄裡,後端的「合併」操作會重建資料——舊 id 全部失效,取消與追加功能無聲死亡。判準:跨邊界持有的每一個參照,都要回答「對方的哪些操作會讓它死」;穩定身份是實測出來的事實,不是推理出來的假設。 2026-07-10
「該收多少錢」抽成 pure function — IO 在邊界、領域計算在核心
多個畫面都要顯示「未結帳的份數與金額」時,把計算抽成無 IO 的 pure function:資料由 caller 從 repository 拿好傳入、函式只做合併 / 扣減 / 折扣運算。含合併鍵要跟同一性定義同維度的陷阱、兩層折扣各自 clamp 的邊界、以及用註解預留擴充點讓未來規則接入不動本體。 2026-07-10
16 種支付渠道、4 種行為分類 — 分層 enum:保真層與行為層的粒度分工
同一個分類系統要同時服務序列化(要無損)跟 UI 行為分流(要粗粒度)時,單一 enum 選哪個粒度都錯。解法是分層:保真層無損對齊後端完整列舉、行為層收斂成行為真正分歧的少數大類、層間用 exhaustive switch 衍生——粒度轉換獲得編譯期保證。 2026-07-10
文件裡的扁平 Product、程式碼裡的雙層聚合 — 宣稱型文件的半衰期
refactor 總結文件記的是決策時刻的快照:扁平 Product(一商品一價一庫存)在真實 POS 業務下演化成 Product + ProductSpecification 雙層、價格三種下沉到規格。欄位放聚合根還是子層的判準是「兩個規格會不會不同」;文件預言的需求全中、預言的結構全錯——這正是先蓋結構會蓋錯的實證。 2026-07-10
只活在結帳流程裡的領域物件 — ephemeral model 與「Rx 外殼、immutable 內核」
流程型狀態(結帳中的輸入金額、支付方式、會員)建模成生命週期等於流程的 ephemeral 物件:結完即丟、下次全新,殘留狀態忘記重置的 bug 被結構性消滅。實作形態是 reactive 外殼包 immutable 內核——對外只開語意化變更方法、每次變更是原子的狀態替換。 2026-07-10
同一個品項、四個 model — value object 什麼時候該升級成 entity
同一個業務概念要不要拆成多個 model、value object 什麼時候該升級成 entity——判準是操作需不需要 identity-based 回寫。以 POS 品項從點選、掛單、結算到歷史訂單的四階段模型為例,含 snapshot 與 live reference 的凍結時機。 2026-07-10
桌子跟購物車是兩個聚合 — 從「提前結帳」推導生命週期解耦
兩個業務資源該綁死成一對一、還是解耦成獨立生命週期加綁定關係——判準是有沒有業務操作需要其中一方獨立存活。以 POS 的提前結帳、純佔桌、外賣單推導桌位與購物車的聚合邊界,含組合空間大於業務空間時的非法組合封鎖。 2026-07-10
會員身分、計價、支付方式必須一起換 — 耦合欄位的原子切換
多個狀態欄位被同一條業務規則綁住時,分開的 setter 會製造不一致的中間態;把切換收成單一方法、一次狀態更新內同步全部欄位,並注意衍生值重算的順序。以 POS 結帳的會員登出重算為例,含不變式收進 model 的 canCheckout 設計。 2026-05-05
Dart StreamController:single-subscription vs broadcast 的設計選型問題
Dart `Bad state: Stream has already been listened to.` 的根因:預設單訂閱在第二個訂閱者出現時才爆。StreamController vs .broadcast() 修復決策、與 Rx / .obs 的比較。 Tarragon (CC BY 4.0) | 使用 hugo 製作