跳轉到內容

ROSE 編譯器框架/良好 API 設計

來自華夏公益教科書

Google: Joshua Bloch 著的“如何設計一個好的 API 以及它為什麼重要”

待辦事項:從 Markdown 轉換

良好 API 的特點

[編輯 | 編輯原始碼]
  • 易於學習
  • 易於使用,即使沒有文件
  • 難以誤用
  • 易於閱讀和維護使用它的程式碼
  • 足夠強大以滿足需求
  • 易於擴充套件
  • 適合受眾

API 設計流程

[編輯 | 編輯原始碼]

[T]重複一個非常短的開發週期:首先,開發人員編寫一個失敗的自動化測試用例,定義所需改進或新功能,然後生成透過該測試的程式碼,最後將新程式碼重構到可接受的標準。

    • 同時作為示例/教程和單元測試
  • 保持現實的期望
    • 你不能取悅所有人……目標是讓每個人都同樣不滿意
    • 預計 API 會發展;會犯錯誤;需要真實世界的使用

一般原則

[編輯 | 編輯原始碼]
  > [A] measurement of actual performance [power / weight]
  • 不要給使用者一把槍讓他們自傷
    • 資訊隱藏:最大程度地減少所有內容的可訪問性

文件很重要

[編輯 | 編輯原始碼]
  • 類:例項代表什麼
* Method: contract between method and calling client (preconditions, postconditions, and side-effects)
* Parameter: indicate units, form, ownership

先決條件和後置條件

  • 先決條件語句表示在呼叫函式之前必須為真。
  • 後置條件語句表示在函式完成工作時將為真。
  /// \post <return_value>.empty() == false
  

API 與實現

[編輯 | 編輯原始碼]

實現細節不應影響 API。不要讓實現細節“洩漏”到 API 中。

效能

  • 為可用性設計,為效能重構
  • 不要為了提高效能而扭曲 API
  • API 設計決策對效能的影響是真實且永久的
    • Component.getSize()返回值Dimension
    • Dimension是可變的
    • 每次getSize呼叫都必須分配Dimension
    • 導致數百萬次不必要的物件分配
  • API 必須與平臺和平共處
    • 做習慣的事(標準)
    • 避免過時的引數和返回值型別
    • 模仿核心 API 和語言中的模式
    • 利用 API 友好功能:泛型、可變引數、列舉、預設引數
  • 不要讓客戶端做模組可以做的事情
    • 減少對樣板程式碼的需求
  • 不要違反[最小驚訝原則](http://en.wikipedia.org/wiki/Principle_of_least_astonishment)
  > The design should match the user's experience, expectations, and mental models...aims to exploit users' pre-existing knowledge as a way to minimize the learning curve
  • 提供對所有以字串形式提供的資料的程式設計訪問許可權 => 無需客戶端字串解析
  • 小心過載:模糊過載

名稱很重要

[編輯 | 編輯原始碼]
  • 基本上不言自明(避免使用神秘縮寫)
  • 保持一致(例如,相同的詞語意味著相同的事情)
  • 努力追求對稱
  • 應該像[散文](http://en.wikipedia.org/wiki/Prose)一樣閱讀
 > [T]he most typical form of language, applying ordinary grammatical structure and natural flow of speech rather than rhythmic structure (as in traditional poetry).
      if (car.speed() > 2 * SPEED_LIMIT)
        generateAlert("Watch out for cops!");
    

輸入引數

[編輯 | 編輯原始碼]
  • 介面型別優於類:靈活性、效能
  • 最具體的型別:將錯誤從執行時移動到編譯時
  • 使用double(64 位)而不是float(32 位):精度損失是真實的,效能損失可以忽略不計
  • 一致的排序:
      #include <string.h>
      char *strcpy (char *dest, char *src);
      void bcopy   (void *src,  void *dst, int n); // bad!
    
  • 簡短的引數列表:3 個或更少;更多的話,使用者就必須參考文件;型別相同的引數有害
    • 縮短引數列表的兩種技巧:1)分解方法,2)建立輔助類來儲存引數

返回值

[編輯 | 編輯原始碼]
  • 避免需要特殊處理的值
 > For example, return a `zero-length array` or `empty collection`, not `null`
  • 不要強迫客戶端使用異常進行控制流
  • 不要靜默失敗
  • 更喜歡未經檢查的異常
  • 包含故障捕獲診斷資訊
  • 快速失敗:儘快報告錯誤
    • 編譯時:靜態型別、泛型
    • 執行時:在第一個錯誤方法呼叫時出錯(應該是故障原子
華夏公益教科書