最近在整理一個內部決策系統的 dashboard,做到一半突然發現自己差點走回老路:畫面越做越完整,資料 fallback 越接越多,看起來好像越穩,實際上卻是在把系統弄得更不可信。
這件事讓我重新想清楚一個很重要的邊界:dashboard 不是資料源,它只是觀測層。
聽起來很像廢話對吧?Dashboard 本來就是拿來看的,不是拿來存資料的。但實務上最容易出事的地方,往往就是這種「大家都知道」的原則。因為當你真的在趕一個可用畫面時,誘惑會一直出現:這個欄位資料庫還沒寫好,先讀昨天輸出的 JSON;那個狀態 API 偶爾沒有值,先從 report 裡撈;某個指標缺資料,先用記憶檔補一下。每一個決定單獨看都合理,合在一起就變成災難。
最危險的是「看起來正常」
Dashboard 壞掉不可怕。畫面紅紅的、API 回 500、資料庫連不上,至少你知道它壞了。真正可怕的是它沒壞,還很努力地顯示一個「看似合理」的世界。
例如主要資料庫沒有今天的資料,但 dashboard 自動退回昨天的報表快照;候選清單沒有同步成功,但畫面從某個中間檔案補了一份舊資料;決策紀錄其實沒落盤,但 UI 因為還留著前一次生成的 JSON,所以看起來一切正常。
這種狀況對技術主管來說很毒。因為 dashboard 的目的不是裝飾,它通常是拿來做判斷的:系統有沒有跑、資料有沒有到、風險在哪裡、下一步要不要介入。如果它把錯誤包裝成正常,那就不是 observability,而是迷魂湯。
我後來給自己的規則很簡單:寧可明確顯示「沒有資料」,也不要偷偷拿別的地方補出一個假正常。
Fallback 不是不能用,但不能污染事實層
這裡要先講清楚,我不是反對 fallback。做系統的人都知道,完全沒有 fallback 的服務很脆弱。外部 API 會掛,排程會延遲,資料庫會有 maintenance window,模型也可能突然變笨。問題不在 fallback 本身,而在 fallback 被放到哪一層。
我現在會把資料分成三層:
flowchart TD
A[主要事實來源] --> B[資料服務 / API]
B --> C[Dashboard 觀測層]
D[報表快照 / 匯出檔] --> E[人工查核 / 歷史追溯]
F[警告與空狀態] --> C
主要事實來源只能有一個。它可以是資料庫、event log、ledger,或任何你明確定義的 source of truth。報表快照和匯出檔可以存在,但它們的角色是追溯、稽核、下載,不是用來在主畫面上假裝今天的狀態還活著。
如果主資料源沒有資料,dashboard 應該顯示 warning:「目前沒有讀到資料」、「最後更新時間過舊」、「某個資料集未同步」。這種訊息看起來很醜,但它誠實。相反地,自動退回舊檔案很漂亮,但它會讓使用者在錯誤的現實裡做決策。
靜態報表和即時畫面的責任不一樣
我以前很喜歡先做靜態報表。產一份 HTML、一份 JSON,丟到固定位置,打開就能看。這個做法有很多優點:容易 debug、容易保存、容易比較版本,也不需要維護長駐服務。對早期探索來說,靜態報表非常好用。
但當需求從「看一次結果」變成「持續監控狀態」,它的性質就變了。
靜態報表回答的是:「那次執行產生了什麼?」即時 dashboard 回答的是:「現在系統相信什麼?」這兩個問題不能混在一起。前者可以是 artifact,後者必須綁定目前的事實來源。
如果 dashboard 一邊讀即時 API,一邊讀前一次靜態輸出,一邊再讀某個排程留下的中間 JSON,你就很難回答一個基本問題:畫面上的這個數字,到底從哪裡來?更慘的是,當數字錯了,你也不知道該修誰。
這就是為什麼後來我會傾向把靜態產物降級成「資料層副產品」或「除錯附件」,而不是人看的主要入口。主入口只讀正式資料源;正式資料源沒有,就讓它紅。不要怕紅,紅至少代表系統還有羞恥心。
Dashboard 應該幫你發現問題,不是幫問題化妝
一個好的 dashboard,不只是把資料畫出來而已。它應該幫你回答三件事:
- 這份資料從哪裡來?
- 它是什麼時候更新的?
- 如果它不可信,我要怎麼知道?
很多 dashboard 做到第一點就停了。資料有顯示,圖有畫出來,顏色也漂亮。但真正決定可信度的是後兩點。最後更新時間、資料來源名稱、同步狀態、warning、空狀態,這些看起來很無聊的東西,才是 dashboard 從「展示頁」變成「操作介面」的關鍵。
尤其現在很多 AI 工作流會產生大量中間結果:模型輸出、候選清單、摘要、評分、trace、usage、快照、人工修正版本。每一份檔案都很像資料源,每一份都可以被 UI 拿來補洞。但越是這樣,越要嚴格定義:哪些是事實,哪些是解釋,哪些只是 debug artifact。
AI 系統已經夠容易讓人產生「它看起來很懂」的錯覺了,dashboard 不能再加一層「畫面看起來很正常」的錯覺。
我現在會先寫資料契約,再寫漂亮畫面
這次調整後,我對 dashboard 的開發順序也變保守了。以前會先想畫面:上面放總覽,中間放清單,右邊放指標,底下放 log。現在我會先問資料契約:
- 這個畫面唯一允許讀哪個 source of truth?
- 哪些欄位必須有,哪些可以為空?
- 資料過期多久要警告?
- 缺資料時要顯示空狀態,還是直接擋住?
- 匯出檔、快照、trace 的角色是什麼?
這些問題很不性感,但它們決定系統能不能被信任。畫面可以醜一點,資料契約不能糊。因為 dashboard 一旦被團隊拿來做日常判斷,它就不只是 UI,而是決策介面。
對,決策介面最重要的不是好看,是誠實。
結語:讓系統誠實地壞掉
我越來越覺得,工程成熟度的一個指標,是你願不願意讓系統誠實地壞掉。
初期我們常常會想把錯誤藏起來,讓畫面盡量保持完整;後來才會發現,藏錯誤不是韌性,是債務。真正可靠的系統不是永遠綠燈,而是紅燈亮的時候你知道為什麼、知道影響範圍、知道下一步怎麼處理。
所以現在我對 dashboard 的要求變得很樸素:只讀被承認的資料源;資料沒有就說沒有;資料舊了就標出來;中間產物不要偷渡成事實。這幾條規則看起來不炫,但踩過一次「畫面正常、現實錯誤」的坑之後,就會知道它們有多重要。
如果這篇能少讓一個 dashboard 變成漂亮的謊言,那我的血淚就沒有白流。😂