所有的程式人,對於API這個名詞肯定不陌生,這甚至是我們在討生活的過程中,總是時常掛在嘴上的一個名詞。

所謂的API,即為應用程式介面(Application Programming Interface),通常是作業系統或是程式庫,為了便利應用程式的撰寫,而提供的一組程式碼。其目的在於隱藏底層實作的細節,透過簡化、抽象、又一致的介面,讓應用程式的撰寫者,並不需要明白底層確切的實作方式,也不需要花費時間重新開發這些共通的輪子,而能更專注在自己所欲開發的應用程式之上。

在我們之中,或許有許多人的工作,便是使用現成的API來完成應用程式的開發,但是,或許還有些人的部份或全部工作,反而是開發特定的API,提供給其他的應用程式開發者來使用。

對後續的程式開發影響很廣泛,好壞很重要
和API設計者相對的角色,可以說是API使用時的客戶,雖然他們也是程式設計者,但對API設計者而言,他們仍然是站在客戶端,就好比應用程式的使用者一樣的地位。所以,通常會把他們稱為「客戶端程式設計者(client programmer)」,而他們立足於API之上所寫下的程式碼(也就是呼叫API的應用程式程式碼),則會被稱為「客戶端程式碼(client code)」。

身為API設計者,其目標當然是設計出好的API。好的API帶你上天堂,壞的API讓你住套房。因為一套API被設計出來,通常都會有許多客戶端程式設計者基於這套API來開發他們的應用程式,倘若在API設計中有一個缺陷,那麼這一個缺陷就會「傳染」到所有該API的客戶端程式設計者所開發的應用程式中,接著便會影響到所有應用程式的使用者。

因此,API的設計良善與否,影響層面往往十分廣泛。而且受到重視及眾多程式設計者採用的API,其生命期更是十分久長,即使API會演化,通常也會保持往下相容,所以,舊的API問題,倘若出在介面上,那麼演化時仍會從前一代繼續帶往下一代。

有一個故事是這樣子的,B語言的發明者,也是C語言的共同發明者、同時還是Unix的建立者Ken Thompson,他在設計Unix的檔案系統API(Unix稱為系統呼叫,system call)時,把開檔函式傳入參數值的一個常數定義名稱拼錯了,這個常數定義名稱也就是O_CREAT,所有C程式設計者對這個定義名稱都不陌生,但不知道你有沒有懷疑過,它是原作者拼錯字下的產物呢?Ken Thompson一直想把O_CREAT糾正成為正確的O_CREATE,但因為已經被列在POSIX中的規範,所以,根本就沒有機會,全世界所有的人只能繼續將錯就錯。

在這個例子中,設計者所犯下的錯誤雖然只是拼錯一個字,無礙於整體的運作,也不會造成什麼傷害,頂多只是看起來礙眼(對Ken Thompson來說,可能是刺眼),但是,這說明了,倘若在API介面中犯下其他型式的錯誤,想要修正這個錯誤的代價可能就十分的沉重。

那麼,你接著自然會問,一組好的API應該具有什麼特質呢?

如何辨識優良的API
一組好的API最重要的特質,便是要能滿足客戶端程式設計者的需求。就這一點而言,就和好的應用程式相同,並無二致。API的基本條件是包裝實作的細節,降低客戶端程式碼編寫時的複雜度。當你在設計你的API時,你必須分析對客戶端程式設計者而言,究竟那些實作的細節、以及複雜性,是他們所不願意碰觸的,是他們所不願意花費時間去重新撰寫的,進而歸納出,那些操作是應該被包裝成更高階、更抽象的介面,藉以隱藏這些實作細節及複雜性,對客戶端程式設計者提供撰寫程式時的便利。

有些API設計者所設計出來的API,提供的功能太少,這使得客戶端程式設計者即使有了API,但仍然許多動作得憑藉著自己的力量去完成,API的存在意義便減少許多。也有些API的設計缺乏彈性,只考慮到一些特定的應用情境(通常這是因為API的設計者只考慮到自己或少數人,而沒有考慮到API對象的共通需求),這麼一來,客戶端程式設計者仍然無法得到API應該帶來的好處。

但相反的,也有一些API設計的太有彈性,不僅客戶端程式設計者需要用到的,都能透過它來達成,連根本不需要用到的,它也都能提供。這乍看之下是件好事,但此類的API因為太過於通用,通常複雜度也就跟著提高,對客戶端程式設計者而言,一來不容易上手,二來運用難度也高、同時容易出錯。

通用性超過實際需求的API,一樣會造成客戶端程式設計者的困擾。API提供的功能太少、或太多,缺乏彈性或太有彈性,都不適宜,API的設計者需要拿捏出其中平衡點,讓你設計的API恰如其份,而這也是學問所在。

再來,好的API設計應該要夠直覺,也就是說,對客戶端程式設計者而言,不需要花費額外的心思才能理解,也不需要花費額外的力氣才能參透運用API的深層奧妙,它的設計對程式設計者來說,應該像是天生就如此理所當然的那樣。好的API並不會在介面上做高深的賣弄,和客戶端程式設計者之間相接觸的介面,應該是愈平實、愈容易理解、愈符合客戶端程式設計者自然的預期愈好。

當然,我並不是在說API設計不需要文件輔助說明,但是,好的API設計,的確可以在不倚賴太多文件說明的情況下,就能讓客戶端程式設計者自在的運用,而且不會發生誤解的情況。這便是因為這樣的API設計結果足夠直覺。

為了讓API更直覺,採用一致且容易正確套用與延伸的命名方式
所有的程式碼設計其實都應該要夠直覺,只是API設計更需要!要怎麼達到這個「夠直覺」的境界?最重要的第一步當然是命名。無論函式名稱(若是物件導向程式語言,那麼就是類別名稱、資料成員名稱、成員函式名稱)或是傳入函式的參數名稱,都能為客戶端程式者提供足夠的隱喻及暗示。

只要是適當的命名方式都可以為客戶端程式者帶來直覺,但重點是——要有一致性。具備一致性的東西,能夠讓客戶端程式者很容易舉一反三。

例如,在Java的群集器(collection)API中,將元素加到群集器中,一律都用「add」這個名稱,移除則一律採用「remove」這個名稱。一旦涉及傳入另一個群集器的操作,則都會使用「all」來表示,例如將另一個群集器中的元素加入某個群集器中的動作是「addAll」,而將另一個群集器中的元素自某個群集器中移除的動作則是「removeAll」。判斷某個元素是否在群集器中,是用「contains」,很自然而然的,你會推論,判斷某個群集器中的所有元素是否皆在另一個群集器中,它是使用「containsAll」這個名稱。

這便是命名的重要性,同時也是一致性帶來的好處,即使我們不知道,也可以根據這個一致的規則,「推論」出究竟應該是什麼。
當然,一致性不僅僅只反映在命名上,所有設計原則都應該要有一致性。從Java群集器API的設計,你就能大概體會到,一個直覺的API設計,對客戶端程式設計者來說,在理解上能夠起多大的作用。

專欄作者


熱門新聞

Advertisement