2023 年 2 月 23 日,星期四 ·5分鐘閱讀

最後的重大變更

當我們持續朝向穩定的規格邁進時,我們一直在分析 JSON Schema 的各種組成部分、行為和功能,以確定哪些可以包含,哪些可能需要修改,以及哪些(如果有的話)需要刪除或替換。我們的主要問題是,是否有任何計劃的變更會對使用現有 schema 的用戶造成問題,也就是重大變更。

為了回答這個問題,我們需要用戶的意見。因此,我們在網路上發文,鼓勵用戶參與GitHub 上關於我們如何處理即將發布版本之重大變更的特定討論。回應大多是,「如果可以的話,請不要破壞現有的東西。」但也有很多人表示,如果有一個定義好的遷移路徑和工具可以幫助他們,他們會比較不介意。

我們還對功能穩定性進行了內部調查,所有 JSON Schema 核心團隊成員都參與其中。我們很高興地報告,絕大多數 Draft 2020-12 可以完全保持不變。有一些關鍵字和行為可能需要一些調整,但大部分都是我們認為與目前版本相容的方式。

用戶和團隊成員之間的另一個普遍看法是,JSON Schema 在發布新版本的規格時,已經有(和聲譽)包含了重大變更,這意味著在一個版本中正確驗證的 schema 可能在下一個版本中無法正確驗證。這種觀感是我們需要解決的問題。為了做到這一點,我們需要調整我們自己和規格的方向,以便我們能夠保證按照一個版本編寫的 schema 將在每個後續版本中始終如一地進行驗證

不幸的是,為了做出這個保證,我們絕對必須以重大變更的方式更改一個行為:支援未知關鍵字。

什麼是未知關鍵字?

如果關鍵字是由 schema 的元 schema(由 $schema 中的值識別)中列出的 vocabulary 定義的,則該關鍵字是「已知」的。透過識別此 vocabulary 並繼續處理 schema,實作宣告它理解如何處理該 vocabulary 定義的所有關鍵字。任何未由 schema 的元 schema 中列出的 vocabulary 定義的關鍵字都被視為「未知」。

目前所有已發布的 JSON Schema 版本都指示實作(至少)忽略無法識別的關鍵字。隨著 Draft 2019-09 中引入註解,實作可以選擇收集未知關鍵字的值並在輸出中向用戶報告。此行為廣受社群支援,因為這意味著他們可以註解和記錄他們的 schema,而無需擔心他們的驗證會受到影響。對於像這樣的 schema

schema
{ "$schema": "https://json-schema.dev.org.tw/draft/2020-12/schema", "type": "object", "properties": { "firstName": { "type": "string", "database-field-id": 1234 } }}

驗證器會忽略 database-field-id,或將其及其值作為註解包含在輸出中。可以看出這個功能會非常有用。然而,這個功能也阻礙了我們承諾未來相容性的能力。

為什麼我們不能繼續支援這個功能?

假設使用者在撰寫上述範例綱要時,使用的是符合 2023 年規格的驗證器。幾年後,他們想要升級驗證器,現在的驗證器支援 2025 年的規格。然而,在 2025 年的規格中,我們將 database-field-id 新增為關鍵字,並且它的值預期為字串。突然間,使用者的綱要不再有效。我們因為新增了一個新的關鍵字而破壞了使用者的程式。

為了防止這種情況發生,我們被迫禁止未由列出的詞彙宣告的關鍵字。我們知道這會讓很多人在一開始就遇到問題。然而,我們認為,對未來相容規格的承諾應該優先於必須再次(而且可能在未來不斷)更改綱要的即時痛苦。

為了減輕衝擊,我們正在做些什麼?

我們有一個關於這個主題的公開討論,我們邀請您發表意見。

目前的提案包括簡單的前綴,作為自訂註解的慣例,以及更複雜的解決方案,例如內嵌和臨時詞彙,這些詞彙會與綱要捆綁在一起,可以定義僅限註解的關鍵字,例如 titlereadOnly。這些選項實際上是綱要作者表示「我知道這些關鍵字未由任何詞彙宣告,但我真的希望將它們放在我的綱要中。請忽略它們。」的方法。

下一個版本中會有其他重大變更嗎?

希望不會。我們認為,移除對未知關鍵字的支援將是唯一真正產生負面影響的變更,但這並不排除其他以較不重要的方式破壞程式的可能性。

我們知道,像這樣進行重大變更對開發人員(包括使用者和實作者)來說很困難,因此我們正盡力衡量所需的變更,並在可能的情況下尋求替代方案,以避免破壞程式。我們不認為這是一個可以隨意進行變更的機會。

無論如何,我們將公開且透明地說明我們所做的任何變更,包括重大變更和其他變更。

總結

看來我們必須在下一個版本中破壞一些綱要。然而,透過這樣做,我們能夠承諾未來不會這樣做。

我們必須先破壞它才能修復它。

封面照片由 Ken SuarezUnsplash 上拍攝