FIDL 設計原則

本頁面會歸納 FIDL 歷來採用的重要設計原則。

選區優先順序

FIDL 的目標是尊重以下選區優先順序:

  1. 使用者 (使用 Fuchsia 產品)
  2. 終端開發人員 (使用 FIDL 繫結)
  3. Fuchsia 貢獻者 (使用 FIDL 繫結)
  4. API 設計人員 (編寫 FIDL 程式庫)
  5. Fuchsia FIDL 團隊成員

這份清單改編自 API 委員會章程

ABI 優先,API 次之

出自 RFC-0050:語法修訂

FIDL 主要用於定義應用程式二進位檔介面 (ABI) 相關事項,其次是應用程式設計介面 (API) 相關事項。

二進位線路格式優先

出自 RFC-0050:語法修訂

雖然許多格式都能代表 FIDL 訊息,但 FIDL Wire Format (或「FIDL 二進位線路格式」) 享有優先處理權,且會優先處理。我們在選擇語法時,會過度傾向二進位 ABI 格式。

先顯示低價位等級

摘錄自 RFC-0131:FIDL 線路格式的設計原則

如果為了支援低階程式設計而必須犧牲高階程式設計 (反之亦然),我們通常會選擇支援低階程式設計。

功能最少

出自 RFC-0050:語法修訂

我們致力於減少功能和規則,並整合功能來達成使用情境。實務上,考慮新功能時,我們應先嘗試調整或概括其他現有功能,而不是導入新功能。

用多少付多少

根據 RFC-0027:用多少付多少

為 FIDL 新增功能時,我們應評估新增功能對 FIDL 使用者造成的成本,但這些使用者不會使用新功能。因此,如果某項功能會對未使用該功能的人造成負擔,我們就應嚴格把關,確保該功能值得推出。

舉例來說,RFC-0047:表格遵循這項原則,在語言中新增表格,而非取代結構體:

資料表必然比結構體複雜,因此處理速度較慢,序列化時也會使用更多空間。因此,建議您保留結構體,並導入新項目。

相反地,RFC-0061:可擴充聯集經過仔細分析取捨後,做出以可擴充聯集取代靜態聯集的決定。與資料表不同,可擴充聯集通常不會產生額外費用,或費用極低。

解決實際問題

我們設計 FIDL 是為瞭解決實際問題和滿足實際需求,而非想像中的需求。 我們避免設計「為解決問題而生的解決方案」。

舉例來說,FIDL 一開始不支援空結構體,因為不清楚如何在 C/C++ 中表示這類結構體。在 RFC-0056:空結構體中,我們發現使用者採用了因應措施,並瞭解需要正式解決方案。我們隨後才在該語言中加入空白結構體。

根據資料進行最佳化

如果沒有資料,最佳化作業輕則毫無用處,重則可能造成危險。設計最佳化項目 (例如效能、二進位大小) 時,我們會依據資料。

舉例來說,RFC-0032:高效信封最初獲得接受,但後來遭到拒絕。回想起來,當時不應接受這項要求,因為沒有資料可供備份。後來,在有資料顯示效能大幅提升後,這項提案重新獲得接受,成為 RFC-0113:高效封包

同樣地,使用較稀疏的表格資料表示法也獲得顯著進展。不過,經過調查後,我們發現設計複雜度和效能之間存在不利的取捨關係,因此決定不繼續開發 (請參閱 RFC-0116:Sparser Tables)。如果沒有重要的原型設計和資料收集階段,可能就會採用較稀疏的表格,對 Fuchsia 造成負面影響。

不會在遠處斷裂

我們會盡量避免遠距離中斷。在某處進行變更時,不應導致遠處發生令人意外的故障。舉例來說,如果將名為 Foo 的結構體新增至 FIDL 檔案,卻導致編譯作業中斷,這會令人感到意外,因為程式碼庫完全不同部分的另一個 FIDL 檔案,已經有名為 Foo 的型別。因此,FIDL 與大多數程式設計語言一樣,會使用命名空間來限制名稱衝突的範圍。

RFC-0029:增加方法序數一文討論了與通訊協定組合相關的問題。RFC-0048:明確的聯集序數會重新探討這個主題,說明 FIDL 只會對通訊協定使用雜湊。

RFC-0057:預設無控點導入了值和資源類型之間的差異。其中一個動機是為 Rust 中的型別提供 Clone 特徵,且不會在遠端中斷:

雖然 FIDL 繫結可以根據控制代碼是否存在,有條件地啟用程式碼,但這麼做會破壞可演進性保證,因此不建議。舉例來說,在表格中新增欄位通常很安全,但新增控制代碼欄位會導致來源中斷,不僅是該表格,所有遞迴包含該表格的型別都會受到影響。

RFC-0149:FIDL 編碼驗證並非必要也涉及這個主題。這項規則會細分可能發生的中斷類別,並將是否執行編碼端驗證的決策移至繫結。這樣一來,就能更細緻地討論編碼端驗證的額外負荷,以及遠距離發生中斷的風險。

寬鬆的語法,慣用的風格

我們不會固守「一種做法」的哲學。如果我們擔心使用者會浪費時間在微不足道的替代方案之間做決定,我們會在 fidl-lintfidl-format 中導入限制,而不是在 fidlc 中導入。

舉例來說,FIDL 接受任何順序的修飾符關鍵字,但我們打算在 Lint 中強制執行一致的順序。

舉例來說,RFC-0040:ID 唯一性修正了 ID 在大小寫轉換後發生衝突的問題,方法是讓 fidlc 在任何兩個 ID 具有相同標準形式時回報錯誤。較簡單的替代方案是在編譯器中強制執行 FIDL 命名慣例。但這有點過頭了。使用不同命名樣式有其正當理由,例如在說明 Kernel API 時,強烈建議使用 snake_case 方法。

標準表示法

摘錄自 RFC-0131:FIDL 線路格式的設計原則

FIDL 值必須有單一明確的表示法,也就是說,FIDL 值只能有一個編碼表示法,以及一個解碼表示法。

FIDL 線路格式是標準格式:特定訊息只有一種編碼方式。因此,每個位元組都有其意義:如果變更任何位元組,訊息的意義就會隨之改變。

舉例來說,規格要求所有填補位元組都為零。同樣地,RFC-0047:資料表禁止儲存多餘的空白信封,以確保標準表示法。

標準表示法可讓 FIDL 更簡單且安全。舉例來說,允許非零填補可能會導致 FIDL 訊息洩漏記憶體中剛好佔用這些位元組的私密資訊。允許特定訊息有多種表示方式,也會導致很少執行的程式碼路徑可能隱藏錯誤,例如「額外空白信封」程式碼路徑。此外,標準表示法可讓您輕鬆比較訊息是否相等,不必瞭解結構定義:對於值型別,這只是簡單的 memcmp

無須分配

摘錄自 RFC-0131:FIDL 線路格式的設計原則

必須能夠在單一傳遞中編碼及解碼,且不得超出堆疊空間分配 (即不得動態分配堆積)。

這項規定對線路格式的設計有重大影響:您必須能夠只使用堆疊,在適當位置解碼。因此,線路格式採用存在指標和深度優先遍歷順序,而非例如基於偏移的格式,這類格式需要輔助資料結構,才能在解碼時追蹤資訊。

這項原則與「您只需依照使用量付費」有關,因為它適用於 FIDL 的極低層級用途,可能還沒有 malloc,或成本過高。

沒有立即可用的反思功能

摘錄自 RFC-0131:FIDL 線路格式的設計原則

未明確選擇加入的情況下,不得允許同層級對通訊協定執行反映,無論是公開方法或公開型別。

傳輸一般性

雖然二進位線路格式優先,但這並不代表 FIDL 應緊密連結至 Zircon 管道傳輸。還有其他重要用途需要考慮,例如說明 Kernel API、程序內訊息傳遞和持續性。

RFC-0050:語法修訂說明瞭傳輸一般化的未來方向。

RFC-0062:方法不可能遭到部分拒絕,因為 FIDL 與 Zircon 管道傳輸過於緊密。