ROSE 編譯器框架/良好 API 設計
外觀
Google: Joshua Bloch 著的“如何設計一個好的 API 以及它為什麼重要”
待辦事項:從 Markdown 轉換
- 易於學習
- 易於使用,即使沒有文件
- 難以誤用
- 易於閱讀和維護使用它的程式碼
- 足夠強大以滿足需求
- 易於擴充套件
- 適合受眾
- 以用例的形式收集真實需求
- 從簡短的 1 頁規格說明開始
- 敏捷勝過完整性
- 收集大量反饋
- 儘早且經常使用您的 API
- [測試驅動開發 (TDD)](http://en.wikipedia.org/wiki/Test-driven_development)
[T]重複一個非常短的開發週期:首先,開發人員編寫一個失敗的自動化測試用例,定義所需改進或新功能,然後生成透過該測試的程式碼,最後將新程式碼重構到可接受的標準。
- 同時作為示例/教程和單元測試
- 保持現實的期望
- 你不能取悅所有人……目標是讓每個人都同樣不滿意
- 預計 API 會發展;會犯錯誤;需要真實世界的使用
- 如有疑問,請勿使用。你可以隨時新增,但不能刪除。
- 僅僅因為你可以,並不意味著你應該
- [功率重量比](http://en.wikipedia.org/wiki/Power-to-weight_ratio)
> [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 設計決策對效能的影響是真實且永久的
- 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`
- 不要強迫客戶端使用異常進行控制流
- 不要靜默失敗
- 更喜歡未經檢查的異常
- 包含故障捕獲診斷資訊
- 快速失敗:儘快報告錯誤
- 編譯時:靜態型別、泛型
- 執行時:在第一個錯誤方法呼叫時出錯(應該是故障原子)