Fuchsia 平台 API 演進指南

本節包含 Fuchsia 貢獻者變更 Fuchsia 平台 API 的相關指南。開始之前,請先熟悉下列概念:

平台 API 的生命週期

Fuchsia 平台 API 應遵循以下生命週期: 新增 → 淘汰 → 移除 → 刪除,如下圖所示:

這張圖片顯示 Fuchsia 平台上的 API 生命週期,從新增 API 的版本開始,然後是淘汰、移除,最後是淘汰

以下各節說明 API 開發人員如何管理這個生命週期。

新增 FIDL API

請務必使用 @available 屬性,為新的 FIDL 程式庫和元素加上註解。不穩定的 API 應在 HEAD API 級別新增。請注意,使用 SDK 的合作夥伴可以指定 HEAD API 級別,但如果這麼做,將無法獲得 API/ABI 相容性保證。

例如:

@available(added=HEAD)
library fuchsia.examples.docs;

API 準備好穩定運作時,您應將其更新為 added,並在 NEXT 中進行。例如:

@available(added=NEXT)
library fuchsia.examples.docs;

NEXTHEAD 類似,但 NEXT 中提供的 API 元素會自動新增至下一個發布的 API 級別。因此,如果您在 F23 的 API 凍結前一週將程式庫加入 NEXT,一週後會看到:

@available(added=23)
library fuchsia.examples.docs;

之後,凡是新增至 23 的 API 元素,都必須支援到包含這些 API 元素的所有 API 級別都淘汰為止。

如果 FIDL 程式庫有多個 .fidl 檔案,程式庫應包含個別的 overview.fidl 檔案,且 @available 屬性應寫入該檔案,並附上說明程式庫的文件註解。詳情請參閱 FIDL 樣式指南

SDK 類別中的每個 FIDL API 都會選擇在 CI/CQ 中進行靜態相容性測試。如果 API 變更不具回溯相容性,這些測試就會失敗。新程式庫不會指定 SDK 類別,因此不會向合作夥伴公開,也不會納入相容性測試,API 則可自由變更。API 穩定且程式庫完成 API 校正後,請指定 "partner" 類別。詳情請參閱「宣傳 API」。

取代 FIDL API

有時您需要以新定義取代 API。如要在 API 級別 N 執行這項操作,請使用 @available(replaced=N) 註解舊定義,並使用 @available(added=N) 註解新定義。舉例來說,以下說明如何在 API 級別 5 變更常數的值:

@available(replaced=5)
const MAX_LENGTH uint32 = 16;
@available(added=5)
const MAX_LENGTH uint32 = 32;

淘汰 FIDL API

對於依賴平台 API 的開發人員來說,Fuchsia 平台必須提供平穩的轉移體驗。其中一項措施是充分警告開發人員,日後將移除 API。淘汰是向開發人員傳達這項資訊的方式之一。

您應一律在移除 API 之前,先在較早的層級中將其淘汰。如果終端開發人員指定已淘汰的 API,系統會在建構時顯示警告,指出該 API 已淘汰,並建議改用替代方案。您應加入附註,協助終端開發人員尋找替代方案。例如:

protocol Example {
    // (Description of the method.)
    //
    // # Deprecation
    //
    // (Detailed explanation of why the method is deprecated, the timeline for
    // removing it, and what should be used instead.)
    @available(deprecated=5, removed=6, note="use Replacement")
    Deprecated();

    @available(added=5)
    Replacement();
};

API 淘汰和移除之間必須至少有一個 API 級別。 例如:

// These are OK.
@available(deprecated=5, removed=6)
@available(deprecated=5, removed=100)
@available(added=5, deprecated=5)

// These will not compile.
@available(deprecated=5, removed=5)
@available(deprecated=5, removed=3)

移除 FIDL API

請注意,您應先淘汰 API,再將其移除。

如要移除在穩定層級中新增的 API,請使用 @available 屬性的 removed 引數。舉例來說,如要移除 18 級的方法,該方法在 12 級時已遭淘汰:

protocol Example {
    @available(added=10, deprecated=12, removed=18, note="Use Go() instead")
    Run() -> ();
};

在本例中,如果目標層級介於 10 到 17 (含) 之間,終端開發人員會看到 Run 方法的用戶端繫結,但如果目標層級為 18 以上,則不會看到。只要平台支援 10 到 17 之間的任何級別,在 Fuchsia 平台上工作的開發人員就會看到 Run 方法的繫結,因為平台建構目標是所有支援的 API 級別集。

平台停止支援 10 到 17 之間的所有層級後,您可以視需要從 FIDL 檔案中刪除 Run 方法。如果在此之前刪除,靜態相容性測試就會失敗,且必須取得 //sdk/history/OWNERS 的特別核准,才能提交變更。

如要移除在不穩定層級 (例如 NEXTHEAD) 新增的 API,只要從 FIDL 檔案中刪除即可。

設計可順利演進的 API

本評量表著重於提升與各種平台版本的相容性。這些屬性可盡量簡化相容性維護作業,且是 FIDL API 評量標準的子集。

遵循 FIDL 樣式指南

FIDL 樣式規範可讓 FIDL 易於閱讀,並體現最佳做法。這些是通用的最佳做法,無論 sdk_category 為何,都應遵循這些做法。

使用 FIDL 版本管理註解

FIDL 版本控制註解可讓程式庫、通訊協定和其他元素與特定 API 級別建立關聯。所有相容性推理都是以 API 版本為依據。這是表示 API 演進過程中的某個時間點的方式。

  • 請務必只在 NEXTHEAD API 級別修改 API。

  • 只有在變更準備好在下一個 Fuchsia 里程碑中發布時,才應在 NEXT 中實作變更。

  • 請勿變更編號 API 級別。請參閱 version_history.json

指定向量和字串的界限

詳情請參閱: FIDL API Rubric - Specify bounds for vector and string

使用列舉與布林值

由於布林值是二進位,因此在製作 API 時,建議使用可有多個狀態的列舉,以確保相容性。這樣一來,如果需要其他狀態,列舉可以擴充,但布林值就必須替換為其他型別。詳情請參閱: FIDL API Rubric - Avoid booleans if more states are possible

使用彈性列舉和位元

彈性列舉具有預設的未知成員,因此可輕鬆演進列舉。

只有在極度確定這些型別絕不會擴充時,才使用 strictenumbits 型別。strictenumbits 類型無法擴充,如要將這些類型遷移至 flexible,必須針對具有指定類型的每個欄位進行遷移。

詳情請參閱「FIDL 語言 - 嚴格與彈性」。

偏好使用資料表而非結構體

結構體和表格都代表具有多個具名欄位的物件。不同之處在於,結構體在傳輸格式中具有固定版面配置,這表示「無法」修改結構體,否則會破壞二進位檔的相容性。相較之下,表格在線路格式中具有彈性版面配置,這表示欄位可以隨時間新增至表格,而不會破壞二進位檔相容性。

詳情請參閱: FIDL API Rubric - Should I use a struct or table?

使用開放式通訊協定,搭配彈性方法和事件

一般來說,所有通訊協定都應為 open,而這些通訊協定中的所有方法和事件都應為 flexible

將通訊協定標示為開放,可讓您更輕鬆地處理移除方法或事件的問題,因為不同元件可能是在不同版本中建構,因此每個元件對現有的方法和事件都有不同的看法。由於一般來說,我們希望通訊協定能隨著時間演進,因此建議您選擇開放式通訊協定,除非有理由選擇較封閉的通訊協定。

其中一個可能的例外狀況是撕除通訊協定,代表交易,其中唯一的雙向方法是必須嚴格執行的提交作業,而交易中的其他作業可能會演變。如果通訊協定非常小,不太可能變更,且預期由用戶端實作,您可以將其設為 closed,所有方法也會設為 strict。這樣一來,用戶端就不必費心決定如何處理「不明互動」。但代價是,方法或事件永遠無法新增至這類通訊協定,也無法從中移除。如果您決定新增方法或事件,則必須定義新的撕除通訊協定來取代。

更多資訊:

使用錯誤語法

錯誤語法用於指定方法會傳回值,或發生錯誤並傳回代表錯誤的 int 或列舉。

使用自訂錯誤列舉,而非 zx.Status

定義及控管網域時,請使用專為此用途建構的列舉錯誤型別。舉例來說,如果通訊協定是專為特定用途而建構,且傳達錯誤語意是唯一設計限制,請定義列舉。

如果遵循明確定義的規格 (例如 HTTP 錯誤代碼),且列舉是代表規格所規定原始值的便利方式,請使用網域專屬的列舉錯誤型別。

詳情請參閱: FIDL API Rubric - Prefer domain specific enum for errors

請勿使用其他程式庫的宣告

如果公開 API 的類型和通訊協定在語意上等效,重複使用這些項目並組合通訊協定是個好主意,但也很容易出錯。