本頁面會歸納 FIDL 歷來採用的重要設計原則。
選區優先順序
FIDL 的目標是尊重以下選區優先順序:
- 使用者 (使用 Fuchsia 產品)
- 終端開發人員 (使用 FIDL 繫結)
- Fuchsia 貢獻者 (使用 FIDL 繫結)
- API 設計人員 (編寫 FIDL 程式庫)
- Fuchsia FIDL 團隊成員
這份清單改編自 API 委員會章程。
ABI 優先,API 次之
出自 RFC-0050:語法修訂:
FIDL 主要用於定義應用程式二進位檔介面 (ABI) 相關事項,其次是應用程式設計介面 (API) 相關事項。
二進位線路格式優先
出自 RFC-0050:語法修訂:
雖然許多格式都能代表 FIDL 訊息,但 FIDL Wire Format (或「FIDL 二進位線路格式」) 享有優先處理權,且會優先處理。我們在選擇語法時,會過度傾向二進位 ABI 格式。
先顯示低價位等級
如果為了支援低階程式設計而必須犧牲高階程式設計 (反之亦然),我們通常會選擇支援低階程式設計。
功能最少
出自 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-lint 或 fidl-format 中導入限制,而不是在 fidlc 中導入。
舉例來說,FIDL 接受任何順序的修飾符關鍵字,但我們打算在 Lint 中強制執行一致的順序。
舉例來說,RFC-0040:ID 唯一性修正了 ID 在大小寫轉換後發生衝突的問題,方法是讓 fidlc 在任何兩個 ID 具有相同標準形式時回報錯誤。較簡單的替代方案是在編譯器中強制執行 FIDL 命名慣例。但這有點過頭了。使用不同命名樣式有其正當理由,例如在說明 Kernel API 時,強烈建議使用 snake_case 方法。
標準表示法
FIDL 值必須有單一明確的表示法,也就是說,FIDL 值只能有一個編碼表示法,以及一個解碼表示法。
FIDL 線路格式是標準格式:特定訊息只有一種編碼方式。因此,每個位元組都有其意義:如果變更任何位元組,訊息的意義就會隨之改變。
舉例來說,規格要求所有填補位元組都為零。同樣地,RFC-0047:資料表禁止儲存多餘的空白信封,以確保標準表示法。
標準表示法可讓 FIDL 更簡單且安全。舉例來說,允許非零填補可能會導致 FIDL 訊息洩漏記憶體中剛好佔用這些位元組的私密資訊。允許特定訊息有多種表示方式,也會導致很少執行的程式碼路徑可能隱藏錯誤,例如「額外空白信封」程式碼路徑。此外,標準表示法可讓您輕鬆比較訊息是否相等,不必瞭解結構定義:對於值型別,這只是簡單的 memcmp。
無須分配
必須能夠在單一傳遞中編碼及解碼,且不得超出堆疊空間分配 (即不得動態分配堆積)。
這項規定對線路格式的設計有重大影響:您必須能夠只使用堆疊,在適當位置解碼。因此,線路格式採用存在指標和深度優先遍歷順序,而非例如基於偏移的格式,這類格式需要輔助資料結構,才能在解碼時追蹤資訊。
這項原則與「您只需依照使用量付費」有關,因為它適用於 FIDL 的極低層級用途,可能還沒有 malloc,或成本過高。
沒有立即可用的反思功能
未明確選擇加入的情況下,不得允許同層級對通訊協定執行反映,無論是公開方法或公開型別。
傳輸一般性
雖然二進位線路格式優先,但這並不代表 FIDL 應緊密連結至 Zircon 管道傳輸。還有其他重要用途需要考慮,例如說明 Kernel API、程序內訊息傳遞和持續性。
RFC-0050:語法修訂說明瞭傳輸一般化的未來方向。
RFC-0062:方法不可能遭到部分拒絕,因為 FIDL 與 Zircon 管道傳輸過於緊密。