精讀《API設計原則》
本期精讀的文章是:API設計原則
1 引言
優秀的 API 之於代碼,就如良好內涵對於每個人。好的 API 不但利於使用者理解,開發時也會事半功倍,後期維護更是順風順水。
一個骨灰級資深的同事跟我說過,任何在成長的代碼庫,至少半年到一年就要重構一次,否則失去的不僅是活力,更失去了可維護性與可用性。
2 內容概要
由於本文已經是翻譯後的文章,概要只列出不涉及 c++ 概念的思路框架,細節請移步譯文。
好 API 的6個特質
極簡且完備、語義清晰簡單、符合直覺、易於記憶和引導API使用者寫出可讀代碼。
靜態多態
盡量減少繼承,讓相似的類具備相似的 API,而不是統一繼承一個父類。因為統一繼承會帶來 API public 數量過多,父級無意義的方法對用戶產生誤導。
基於屬性的 API
屬性指的是對象狀態,通過屬性為粒度的 API,有利於使用者理解 API 的含義,但需注意關聯屬性的順序性。
API 語義和文檔
比如傳值 -1 的含義是什麼?如果 API 文檔不像 http status codes 一樣健全,建議通過枚舉的方式增加可讀性。
命名的藝術
不要使用縮寫,保持一致性。類命名以功能分組作為後綴,比零散命名更易懂。
函數命名要體現出是否包含副作用,參數過多時以對象作為傳參,布爾參數改為枚舉類型,或者分解為兩個語義化 API。
3 精讀
以下精讀是對原文觀點的補充。
Const 入參
eslint 有一條規則,不要直接改變入參的值。這個規則的初衷是解決函數副作用問題,禁止可能產生副作用代碼的產生。但卻可以通過如下方式避免:
function (num) {n let scopeNum = numn scopeNum = 5n}n
這是從包含指針類型編程語言學習過來的,因為當 *num 表示指針時,代表代碼可能產生副作用(修改入參的風險)。而 js 並不總是這樣的,不但沒有指針申明,基本類型也總是通過拷貝進入傳參,非基本類型通過引用傳遞,也就是會發生通過如上代碼繞過檢測,卻依然產生副作用(改變函數入參)的情況。
為了避免副作用,建議引入 flow 或 typescript,通過 const 關鍵字與約定約束入參行為:
function (const num) {n ...n}n
將沒有副作用函數的所有入參定義為 const 類型,靜態檢查階段就禁止了對值的直接修改,同時因為有這個關鍵字的約束,在函數體內也約定不要通過引用淺拷貝修改它的值。
但這也無法徹底避免,仍然可以通過如下寫法繞過檢測,修改入參:
function (const num) {n const scopeNum = { ...num }n scopeNum.a.b = cn}n
在 js 中沒有完美的方式避免對入參的修改,但通過對入參修飾 const 關鍵字,可以對使用者明確這是純函數,對開發者提示不要寫有副作用的代碼。
c++ 的 const 定義從編譯開始就完全杜絕了修改的可能性,雖然有 const_cast 「去」 const 行為,但仍然不會改變入參的值(雖然可以後續對值修改,指針指向保持不變,但用 const 修飾的入參值永遠不會改變)。
統一關鍵字型檔
所有api定義之前,先抽離業務和功能語義的關鍵字,統一關鍵字型檔; 可以更好的讓多人協作看起來如出一轍, 而且關鍵字型檔 更能夠讓調用者感覺到 符合直覺、語義清晰; 關鍵字型檔也是項目組新同學 PREDO 的內容之一, 很有帶入感;
單一職責
介面設計盡量要做到 單一職責,最細粒度化; 可以使用組合的方式把多個解耦的單個介面組合在一起作為一個大的功能項介面; 介面設計的單一職責,也更方便多人協作時候的擴展和組合;
面向未來的多態
對於介面參數的擴展,我們要做到面向擴展開放,面向修改關閉; 升級做到要兼容,否則會導致大批量的下游不可用。
同時也要避免過度設計,當抽象功能只有一處使用時,盡量不要過早抽象。
不要重複局部命名
class User {n // goodn setName() {}n n // badn setUserName() {}n}n
在有上下文環境的調用中,減少不必要的描述可以提高 API 的精簡和清晰度。
同時要避免過度使用解構,因為解構會丟失上下文,讓我們對變數來源一無所知:
const { setName } = this.props.store.usernconst { setVisible } = this.props.store.articlen
上述 setName setVisible 脫離了 user article 作用域,當隔著幾百行調用時,早已不知所云。
4 總結
參考優秀類庫是設計 API 很好的方法之一,比如本文 c++ 參考的 Qt、js 可以參考 jQuery。
當 API 穩定後,需要花時間整理文檔,因為寫文檔的思考過程可能推動著你重構和優化代碼。
最後,如果有精力,最好每半年重構一次(然後完整跑一遍測試)!
討論地址是:精讀《API設計原則》 · Issue #34 · dt-fe/weekly
如果你想參與討論,請點擊這裡,每周都有新的主題,每周五發布。
推薦閱讀: