服務裡有個「跟基準值比較的變化率」顯示。某天我自己看著畫面覺得不對勁:那個變化率跟我在別的地方看到的數字對不上,差距還不小。
追查後發現:計算用的基準值來自第三方 API 回應裡一個現成的欄位(previousValue 這類「API 幫你算好」的貼心欄位),而這個欄位回傳的值會差一天——它有時給你的不是「上一期」的值,而是「上上期」的。
為什麼會差一天?老實說,到今天我也只能推測:可能是對方的快取更新時機、可能是對方系統的時區處理、可能是「上一期」在對方的定義裡跟我的定義本來就不同。重點是:這是一個我無法檢視、無法控制、對方也不會為我修好的黑盒子。
而我犯的錯是把「API 有這個欄位」當成了「這個欄位是對的」。這兩件事之間沒有任何邏輯關聯——API 文件通常不會告訴你這個欄位的計算時機、快取策略、邊界行為,你信任它的唯一依據是「它看起來就是我要的東西」。
解法:完全放棄那個現成欄位,改成自己從同一個 API 提供的歷史序列資料往回推——序列裡的每一筆是原始事實(某天的值是多少),比「算好的摘要」可信得多。從序列尾端往回找到最近一筆已收斂的資料點,自己算基準:
def derive_baseline(series: list[Bar]) -> float:
"""從序列自己推導基準值。
不用 API 的 previousValue 欄位——它實測會差一天(地雷清單 #6)。"""
settled = [bar for bar in series if bar.is_final]
return settled[-1].value
多付的成本是一點點運算跟幾行程式碼;換回的是這個數字的正確性從此由我自己的邏輯保證,可測試、可除錯、不再依賴外部黑盒子的內部行為。
這條教訓我後來整理成一個判斷框架,對所有第三方 API 適用:
因為加工結論隱含了對方的計算邏輯——時機、定義、邊界處理——而這些幾乎從不寫在文件裡。你的需求跟對方的實作在 99% 的情況下一致,剩下那 1% 就是使用者看到錯誤數字的那天。
懶人欄位是借來的正確性,遲早要還。