自己動手寫 SDK 的經驗技巧分享

大家好,我是魚皮。

最近因為工作需要,自己動手寫了一些專案的通用 SDK。在編寫的過程中,我閱讀和參考了不少公司中其他大佬寫的 SDK,也總結了一些開發 SDK 的經驗和技巧,給大家分享下~

在此之前,必須先給大家解釋一下啥是 SDK。

啥是 SDK ?

SDK(Software Development Kit)即 軟體開發工具包 ,就是幫助我們開發出軟體的工具集合,除了程式碼之外,一般還要搭配文件、示例等。

一般 SDK 都是需要 引入 到專案中使用的。比如學 Java 的朋友最早接觸的 JDK,就是用來開發 Java 軟體的工具包,使用時需要編寫 類似 import java.util.* 的語法來引入。此外,大部分的 SDK,都是需要通過人工或專案管理工具,將其檔案下載到指定路徑才能引入。

使用 SDK 有什麼好處呢?

舉個例子,假設公司有很多系統都需要實現檔案上傳功能。之前看過我文章的朋友應該知道,一個優秀的檔案上傳功能並不好做,要考慮很多點,比如分塊、斷點續傳、秒傳、檔案儲存、檔案管理等。

檔案上傳設計:https://mp.weixin.qq.com/s/3QXe4MSObJTP43M2gXWSlA

顯然,我們不需要給每個系統都去開發檔案上傳,而是隻需要有一個團隊捨身而出,編寫一套 通用的 檔案上傳 SDK,然後讓需要實現同樣功能的系統引用就行了,這樣就 大大減少了工作量、提高了開發效率

有點前人造車,後人享樂的意思~

編寫 SDK 又稱 造輪子 ,好的輪子不僅能夠幫助團隊省時省力,還能夠減少一些專案在相同功能上的差異。就不要說同一個功能,小王寫的要執行 1 秒,小李寫的要執行 1 小時!

而假設每個系統都去開發同樣的功能,那就是 重複造輪子 ,在大多數情況下,不是明智之舉。

理解了啥是 SDK 後,來看看如何寫出優秀的 SDK 吧~

手寫 SDK 經驗總結

好的 SDK 應該具有簡單易用、通俗易懂、便於擴充套件、高效穩定等特點。

易用性

如今,現成的輪子實在太多了!如何讓你的輪子脫穎而出呢?那就要先提升 SDK 的易用性。

我自己在技術選型時,就會傾向於優先選擇簡單易用的 SDK,最好是幾行程式碼就能輕鬆使用,而不是必須要我讀完老長一份文件,再寫個幾十行程式碼才能生效。

就和產品說明書一樣,太複雜直接把人勸退。

我們可以通過以下幾點提高易用性:

統一呼叫

將複雜的功能進行封裝,對外提供統一的呼叫入口,儘量遮蔽一些實現細節,減少使用者呼叫的流程和對引數的理解成本。

舉個例子,下面是兩種日期處理函式。使用者不需要關心他們是如何實現的,只需要知道怎麼用、傳遞哪些引數、得到哪些返回值就行了。

// 第 1 種:需要 new 物件
DateUtils dateUtils = new DateUtils();
dateUtils.setDate('2021-08-31');
Date date = dateUtils.parse(); // 第 2 種:直接呼叫
Date date = DateUtils.parse('2021-08-13');

那大家覺得哪種更易用呢?

集中配置

將複雜的引數配置化,不需要讓使用者到處寫引數,而是通過一個配置檔案統一管理。

Java 主流開發框架 SpringBoot 就是典型的例子,假如使用者想改變內嵌伺服器啟動的埠、亦或是改變資料庫的連線地址,不需要寫程式碼,而是改一下配置檔案就行了:

# 伺服器配置
server:
port: 8081
# 資料庫配置
db:
ip: 10.0.0.1

此外,這樣也便於維護專案和實現多環境。

良好命名

給 SDK 的函式取名稱時,儘量讓它符合使用者的習慣。

比如具有解析功能的函式,可以叫 "parseXXX";判斷是否為空的函式,可以叫 "xx.isEmpty" 等。最好能做到讓使用者不看文件,只通過函式名稱和引數,就知道你這個函式是做什麼的。

因此,想要寫出好的 SDK,首先要多用、多參考別人的 SDK,養成習慣後你就會發現,大家起名兒都差不多。

但也要注意一點,如果可以,儘量不要讓你 SDK 中的類名(函式名)和別人的完全一致,否則可能給使用者帶來困擾:這麼多同名的函式,我該用哪個呢?哪個是你開發的 SDK 呢?

可理解性

有時,使用者可能不滿足於簡單地使用你的 SDK,而是希望閱讀你的 SDK 原始碼來進一步瞭解,用的才更放心。

因此,除了易用外,還要讓你的 SDK 便於理解,不能金玉其外敗絮其中。

這個就和編碼習慣有很大的關係了,無論是寫 SDK 也好,還是做專案也罷,都要做到以下幾點:

結構清晰

把程式碼按照功能或類別進行整理,放到指定的目錄下。常見的做法有分包、分層等,讓人一眼就知道每個目錄下的檔案的作用。

比如下面這個經典的 Java 專案結構,service 目錄是編寫業務邏輯的、constant 是存放常量的、utils 是存放工具類的等等,都很清晰:

統一風格

統一風格的目標很簡單:讓專案看起來是同一個人寫出來的。

比如程式碼縮排都用 4 個空格、命名都用駝峰式等。尤其是功能相似的程式碼,一定要保持命名和用法的統一!比如解析文字的函式,不要一會叫 "parseXXX"、一會兒又叫 "jiexiXXX",給使用者都整樂了~

但實際上,團隊開發中,很難做到這點。因此才需要有一套通用的程式碼規範,大家都去遵守規範,才能讓專案更好理解、更便於維護。

編寫註釋

最好給 SDK 中的每個類和函式的 開頭 都加上註釋,這樣使用者在使用 SDK 時,甚至都不需要看文件,直接看程式碼註釋就能知道它是幹嘛的、怎麼用。

隨便開啟 Java SDK 或者網上知名 SDK 中的一個函式,一般都能看到這些註釋,包括對函式功能的描述、引數含義、返回值含義等:

說明文件

除了註釋外,還要編寫一個說明文件(使用者手冊),包括如何引入 SDK 、有哪些功能、應該怎麼使用等等,甚至還可以補充一些關鍵的實現細節、以及常見的問題列表。

這點也會極大地影響使用者的選擇。就我個人而言,沒有文件的 SDK 我一般是不會選用的,萬一出了事我找誰呢?

可擴充套件性

編寫 SDK 的一大難點是:不僅要考慮到大部分通用的使用場景,還要滿足小部分使用者定製化的需求。

因此,SDK 的可擴充套件性是很重要的,但怎麼提升呢?

輕量依賴

一方面,我們可以儘量減少 SDK 本身對其他類庫的依賴。

舉個例子,假如你要做一個很輕小的工具類,可能只有幾十 KB,那就沒有必要再引入一個幾百 KB 的依賴庫了,得不償失!別人也不樂意用啊!

輕量依賴不僅可以減少 SDK 的體積,更關鍵的是可以減少依賴衝突的可能性。我自己也曾經遇到過很多次這樣的尷尬局面:引入一個工具類後,整個專案就跑不起來了!

自定義實現

為了提高 SDK 的通用性和靈活性,在設計 SDK 時,除了提供預設實現外,建議提供一個通用介面或抽象類,讓使用者來繼承,編寫自己的實現方式。

舉個例子,假設我們要編寫一個日期解析類,預設的解析規則是按照短橫分割字串:

// 按照 '-' 切分
date = DateUtils.parse('2021-01-18')

如果只能做到這點,那這個 SDK 就很死板。因為使用者可能想按照冒號或其他規則來解析。

怎麼實現呢?

我們可以允許使用者自己傳入分割字元:

// 按照 '-' 切分
parseRule = ':'
date = DateUtils.parse('2021-01-18', parseRule)

還可以讓使用者自己來控制解析的方式:

// 自定義解析器
interface MyParser extends Parser {
// 需要使用者自己實現
void doParse();
}
// 指定解析器
date = DateUtils.parse('2021-01-18', MyParser.class);

這兩種方式在 SDK 的設計中屢見不鮮,此外還可以讓使用者自行編寫或指定配置檔案,也能提高靈活性。

高效穩定

其實,開發 SDK,尤其是在大廠開發 SDK,是個很 “坑” 的工作,我相信做過的朋友會感同身受。

因為隨著使用你 SDK 的使用者越來越多,可能會發現各種各樣莫名其妙的問題;而且 SDK 作為相對底層的依賴,對使用方的影響也是無法估量的。所以,不想經常加班改 Bug 的話,就要保證你 SDK 的穩定性。

我們需要注意以下幾點:

1. 測試

為了保證每個功能都是正常的,我們可以編寫 單元測試(UT)來最大程度上地覆蓋 SDK 的功能和程式碼。

尤其是每次改動程式碼後、釋出新版本之前,都要再完整地執行一遍測試,不要盲目自信。

此外,還可以通過 壓力測試 來估算 SDK 的執行效率,比如每秒最多同時執行 3 次、每次要執行 500 毫秒等。建議將這些資訊補充到說明文件中,給使用者一些預期。當然也可以嘗試通過壓測來優化 SDK 的效能。

2. 相容性

重要的函式和介面儘量減少改動,尤其是函式名、入參和返回值!

舉個例子,SDK 0.1 版本時,函式的定義是這樣的:

boolean isValid(String str)

結果突然在 0.2 版本時改成了:

String checkValid(StringBuilder str)

這樣就會導致使用者升級時一臉懵逼,怎麼報了一堆找不到函式呢?

因此,對於比較大的改動,可以新寫一個函式,並且給老函式打上類似 @Deprecated 的註釋,表示已過時,引導使用者去用新的。

此外,還可以在 版本號 上做做文章,小改動時只改變小版本號,比如 0.0.1 到 0.0.2;大改動時才改變大版本號,比如 1.0 到 2.0。這樣可以給使用者一個預期:這次改動很大,可能會存在不相容。

3. 暴露異常

要讓使用者感知到 SDK 程式碼中可能丟擲的異常,交給他們去進行相應的處理,防止出現一些意料之外的錯誤。

此外,SDK 要合理地列印日誌,尤其是異常日誌,在出了問題時要讓呼叫者知道是出了什麼問題,便於排查。


以上就是本期分享,建議學程式設計的同學多自己動手寫 SDK,並且按照本文的總結去優化它,對提升程式設計能力真的很有幫助!

最近整理了我原創的 140 篇程式設計經驗和技術文章,歡迎大家閱讀,一起成長!️

指路:https://t.1yb.co/ARnD

我是魚皮,最後求個 點贊 ,這將是我持續創作的最大動力,謝謝