本頁歸納了 FIDL 隨著時間的推移採用的主要設計原則。
民眾的優先順序
FIDL 旨在尊重以下消費者的優先順序:
- 使用者 (使用 Fuchsia 產品)
- 開發人員 (使用 FIDL 繫結)
- Fuchsia 協作者 (使用 FIDL 繫結)
- API 設計人員 (編寫 FIDL 程式庫)
- Fuchsia FIDL 團隊成員
這份清單是根據 API 委員會憲章規定改編而成。
ABI 優先,API 秒鐘
來源為 RFC-0050:語法 revamp:
FIDL 主要在定義應用程式二進位檔介面 (ABI) 疑慮,以及應用程式設計介面 (API) 相關問題。
二進位線格式優先
來源為 RFC-0050:語法 revamp:
雖然有許多格式可以代表 FIDL 訊息,但 FIDL 傳輸格式 (或稱「FIDL 二進位線路格式」) 是優先處理的方式,且為最先...我們選擇在選擇語法時,選擇過度旋轉為二進位 ABI 格式。
從低到低
在設計上為了支援低階程式設計而犧牲高階程式設計能力時,我們通常選擇啟用低階程式設計。
最少功能
來源為 RFC-0050:語法 revamp:
我們致力於提供最少的功能和規則,並致力結合多項功能來實現用途。實際上,在考慮新功能時,我們應該先嘗試調整或一般化其他現有功能,而非推出新功能。
用多少付多少
為 FIDL 新增功能時,應評估新增該功能會對使用 FIDL 但未使用新功能的使用者產生的影響。針對不使用這項功能的使用者,我們應設有非常高的門檻,用來接受這類功能的使用者會產生費用。
舉例來說,RFC-0047: Tables 遵循這項原則,其次是為語言新增資料表,而不是替換結構:
資料表比結構複雜,因此處理速度會比較慢,序列化資料表會耗用較多空間。因此,最好將結構保持原樣,並引入新的內容。
相反地,RFC-0061:可延伸聯集就達到了相反的決定,即以可延伸聯集取代靜態聯集,但必須先仔細分析權衡的取捨。與資料表不同,擴充聯集產生的額外費用在大多數情況下為邊緣或不存在。
解決真實問題
我們設計 FIDL 來解決實際問題並解決實際需求,而非想像中。我們避免設計「找出問題的解決方案」。
舉例來說,FIDL 一開始因為不清楚如何在 C/C++ 中表示空白結構體,因此一開始並不支援。在 RFC-0056: Empty structs 中,我們發現使用者使用了變通方法,並且察覺到正式解決方案的需求。我們只接著在語言中新增空白的結構體。
根據資料進行最佳化
在沒有資料的情況下進行最佳化,在最壞的情況下是最佳的最佳化風險,也最危險。在設計最佳化項目 (例如效能、二進位檔大小) 時,我們會追蹤資料。
舉例來說,我們一開始接受 RFC-0032: Efficient 依,但後來遭到拒絕。但因為沒有可備份的資料,因此目前不應接受。之後,當系統顯示可大幅提升效能的相關資料後,又再次提出解決方案,並成為 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 會接受以任何順序加入修飾符關鍵字,但我們希望在 Linter 中強制執行一致的順序。
再舉一個例子,RFC-0040:ID 唯一性透過在兩個 ID 具有相同標準格式的情況下,透過 fidlc
回報 ID 在轉換後會發生衝突的問題。較簡單的替代方案是在編譯器中強制執行 FIDL 命名慣例。然而,這個步驟會間隔太遠。基於正當理由使用不同的命名樣式 (例如說明核心 API),我們強烈建議使用 snake_case
方法。
標準化表示法
FIDL 值必須有一個明確且不明確的表示法,即只有一個 FIDL 值的編碼表示法和一個 FIDL 值的解碼表示法。
FIDL 線格式是標準:特定訊息只有一個編碼。做為共同項目,每個位元組都會列入計算:在不變更訊息含義的情況下,沒有可供變更的位元組。
例如,規格要求所有邊框間距位元組全都是零。同樣地,RFC-0047: Tables 會禁止儲存多餘的空白信封,以確保標準表示法。
標準表示法可讓 FIDL 更加簡便且安全。舉例來說,如果允許非零填充,可能會導致 FIDL 訊息外洩,導致記憶體中佔用這些位元組的機密資訊。允許特定訊息進行多個表示法,也會導致很少執行的程式碼路徑可能隱藏錯誤,例如「額外空白信封」程式碼路徑。標準表示法也能讓您在不瞭解結構定義的情況下,輕鬆比較訊息的相等性:對於「值類型」,這是簡單的 memcmp
。
無須分配
系統可以在單次傳遞中編碼及解碼,而不配置超出堆疊空間 (即沒有動態堆積配置) 的配置。
這項要求大幅影響傳輸格式的設計:必須能夠只使用堆疊來進行解碼。因此,線路格式是使用狀態指標和深度優先遍歷順序,而非諸如偏移式格式,需要輔助資料結構才能在解碼時持續追蹤資訊。
這個原則與「用多少付多少」的計費方式相關,因為這個原則適用於非常低階的 FIDL 用途 (其中 malloc
可能尚未存在,或費用較低)。
沒有立即可用的反射功能
如未明確選擇加入,就不得允許對等點對通訊協定、公開方法或公開類型執行反射。
交通通用
雖然首先是二進位線格式,但這並不表示 FIDL 應與 Zircon 管道傳輸緊密耦合。還有其他需要考量的重要用途,例如說明核心 API、處理中訊息傳遞和持續性。
RFC-0050:語法 revamp 說明傳輸一般化的未來方向。
RFC-0062:方法不可能遭部分拒絕,因為 FIDL 與 Zircon 管道傳輸太過緊密。