ClosureBuilder Deterministic JSON Encoding¶
概念概覽
encoding/json 的不確定性來源¶
核心知識¶
encoding/json 的不確定性來源¶
Go 1.21+ 的 encoding/json 雖然對 map key 有排序保證,但以下兩點仍不可控:
- float 格式:1.0 vs 1 vs 1.000000,不同版本/平台可能不同
- time 格式:time.Time 的序列化格式取決於 MarshalJSON 實作,可能含有 timezone offset 變化
若 ClosureBuilder 用這些值產生雜湊(如 bundle fingerprint),微小格式差異會導致相同語意的 config 產生不同 hash,觸發非預期的 content_mutation。
Custom JSON Encoder 的取捨¶
優點:
- float 格式固定(如統一 strconv.FormatFloat(..., 'f', -1, 64))
- time 格式固定(如統一 UTC RFC3339Nano)
- map key 排序明確
缺點:
- 需自行維護 encoder
- 新增型別時需手動支援
對於 hash-based fingerprint 場景,deterministic 輸出比開發便利性更重要,custom encoder 是正確選擇。
經驗教訓¶
-
任何用於產生 fingerprint/hash 的序列化都必須保證 deterministic,encoding/json 在 float 和 time 上不夠可靠
-
Custom encoder 的維護成本在早期容易低估,應在設計時即規劃好哪些型別需要支援
常見陷阱¶
-
升級 Go 版本後 encoding/json 行為可能改變,造成既有 fingerprint 全部失效(需要強制重新 sync)
-
time.Time 若混用不同 timezone,即使語意相同也會產生不同序列化結果
最佳實踐¶
-
Fingerprint 用途的 JSON 序列化:float 統一用 strconv.FormatFloat,time 統一轉 UTC 後序列化
-
為 custom encoder 寫 golden file 測試,確保 Go 版本升級後輸出不變
相關概念¶
來源 Sessions¶
| 日期 | Session | 貢獻摘要 |
|---|---|---|
| 2026-04-02 | 157b6880-f9d3-466a-abf9-07af0459b5d5 | 記錄了為何不用 encoding/json 而改用 custom encoder 來保證 deterministic hash 輸出 |