本文章是由機器翻譯。

“大家好!”

API 文檔編寫編碼人員指南

Peter Gruenbaum

您是否遇到過經理要求您為所開發的 API 編寫文檔的情況? 如果您像大多數開發人員一樣,只喜歡寫代碼而痛恨寫文檔,就讓我們面對這項挑戰吧。 此外,寫文檔還要佔用完成重要任務所需的時間,例如功能開發和錯誤修復。

API 文檔常常以讓讀者失望和困惑而告終,這並不讓人驚奇,因為它很少能得到應有的重視。

本文將指導您編寫 API 文檔。 我將介紹 API 文檔中最重要的元素,並就如何創建有效文檔提供一些建議。 我還會給您一些提示,告訴您如何創建優秀的概述、示例代碼和參考資料,包括應當如何運用您的時間和精力來獲得最佳效果。

為什麼要為您的 API 編寫文檔?

讓我們從非技術層面開始探討這個問題。 自從第一個程式設計語言創建以來,API 文檔就已經存在了。 儘管投入了大量時間來開發有效的流程,以便製作高品質的文檔,但是真正寫得好的 API 文檔還是鳳毛麟角。 為什麼會發生這種情況?

首先,文檔很少進行優先順序劃分。 儘管文檔在軟體平臺的推廣方面發揮了巨大作用,它的實際影響力還是難以估量。 因此,文檔編寫工作很難獲得充足的時間和預算。 開發人員接到的文檔編寫工作通常都被列為最重要的任務,因此他們必須設法將其擠進已排滿的工作日程當中。

其次,開發代碼和編寫文檔是兩種不同的技能。 有時候,開發人員需要使用母語以外的語言編寫文檔。 但是,即使他們出生在說英語的地區,被要求編寫英文文檔,也很可能有這樣的情況存在:在學校的時候勉強通過文學和社會研究課程考試,而更願意把時間花在解決數學和科學問題上。

製作優秀的 API 文檔的第一步,就是向管理層要求足夠的時間和預算。 有兩點需要向經理說明:

  1. 優秀的文檔能夠使平臺更容易推廣,因為它可以減少開發人員的挫折體驗。
  2. 優秀的文檔還可以減少支援成本,因為開發人員更容易找到問題的答案。

如果您不喜歡編寫文檔,或者是您已經超負荷工作了,那麼討論優秀文檔的重要性對您來說可能是一個挑戰。但是,還有另外的選擇。 如果有足夠的預算,您可以雇用一位技術撰稿人,讓他/她從您那裡收集資訊,然後編寫文檔。

正如開發人員一樣,您也可以找到擁有豐富的經驗和專業知識的技術撰稿人。 許多技術撰稿人在編寫最終使用者文檔和支援資料方面擁有更為豐富的經驗。 不過,對於 API 文檔,您需要尋找具有實際軟體發展經驗的技術撰稿人。 許多公司將這類撰稿人列為類似于程式師/文檔專家的職位。

擁有一些編碼經驗的技術撰稿人理解開發人員在竭力讓軟體平臺運行起來的過程中所承受的痛苦,而優秀的文檔能夠説明改善平臺的開發過程。 此外,他們還應當在語言、演算法和模式方面具備足夠的專業知識,才能讀懂您的代碼,理解您的庫。 有了這些知識和經驗,撰稿人和開發團隊之間的技術討論將會更直接有效。

話雖如此,如果沒有足夠的預算來雇用一位技術撰稿人,您就需要自己編寫文檔了。 務必讓管理層理解您需要擠出時間來做這項工作,就像您需要時間開發新功能一樣。

API 文檔的元素

一份優秀的 API 文檔包含四種元素:

  1. 概述: 解釋開發人員使用該平臺有哪些優勢,在有些情況下,還要提供平臺的體系結構描述。
  2. 開始使用: 以分步教程或更簡單的演練形式,説明開發人員入門。.
  3. 示例代碼: 提供包含詳細注釋且能夠讓開發人員在此基礎上繼續開發的示例代碼。
  4. 參考資料: 提供有關每個類、成員、函數或 XML 元素的詳細資訊。.

當開發人員第一次開始閱讀 API 的文檔時,他們首先需要獲得的資訊是:誰需要使用這個 API,以及為什麼要使用這個 API。 如果開發人員不了解這一點,他們很快就會轉向別的工具。 遺憾的是,此資訊常常被人遺忘。 對於 API 的開發人員來說,這一點顯而易見,但是對於其他人卻並非如此。

列舉一些明顯的示例,介紹您何時需要使用這個 API。 如果您已經有了一些客戶,或一些潛在客戶,則可以將他們當作真實的示例。 列舉該軟體平臺的優勢,最好能與現有的平臺進行對比。 您會發現,專案經理通常擁有此類資訊。

“概述”也是一個用來解釋 API 整體體系結構的理想場所。 對於某些類型的 API(例如,許多 Web API)而言,API 本身已經足夠簡單,無需再進行體系結構討論。 但是,如果您正在為某些包含許多類和繼承結構的複雜 API 編寫文檔,那麼提供全面的體系結構討論並伴以圖表,則可以説明開發人員更好地理解 API。

開始使用

一旦開發人員決定試用您的 API,他們首先想知道的就是如何開始。 在 2009 年,我的公司 (SDK Bridge LLC) 針對文檔進行了一項調查,調查結果中最普遍的反響之一,就是開發人員希望獲得入門説明。 (請參閱我的文章“Survey on SDK Documentation”,網址為 tinyurl.com/35l66yk。) 這一點對於 API 的推廣至關重要:如果開發人員發現很難入門,他們會很快放棄,然後尋找其他的途徑來達成目標。.

教程是説明開發人員入門的一種好方法。 這種方法通常比說明性文字或體系結構圖表都有效得多。 教程引導開發人員一步一步創建簡單的應用程式,演示 API 的工作原理。 教程通常是從非程式設計的活動開始的,例如設置您的開發環境或獲得授權憑據。 然後,它會引導開發人員逐步添加代碼,直到代碼能夠演示通過 API 實現的簡單任務。 教程的結構應該盡可能讓開發人員很快獲得一些代碼,並且運行之後能夠看到結果。 然後繼續編寫教程,添加更多功能。

因為您太熟悉 API 了,您可能已經忘記,如果從一個全新的視角來看,您的 API 會是什麼樣的。 因此,在編寫這部分內容時,儘量退後一步,從一個新人的角度來思考。

編寫示例代碼

在 SDK Bridge 的調查中,另一個普遍的調查結果是:優秀的示例代碼非常重要。 開發人員在學習新的平臺時,會先以他們確信能夠正常運行的代碼開始,然後在其基礎上修改或添加內容。 及時不是大部分,至少也有很多開發人員發現,實際動手要比唯讀書要更容易學會。

您可能知道如何創建優秀的生產代碼。 優秀的示例代碼與優秀的生產代碼有很多共同點,但是也有幾處截然不同。 通常,優秀的示例代碼應當遵循以下原則:

  1. 相關的資訊應當組織在一起。
  2. 清晰性比效率和可靠性更重要。
  3. 簡單性比美觀的 UI 更重要。

您可以將這些原則應用到特定的軟體領域,看看示例代碼與生產代碼有什麼不同。

每個程式師都知道,在代碼中決不應當使用硬編碼的值。 應當將這些值轉換為常量,放在容易發現的地方,以便進行更改。

事實證明,這一原則對於生產代碼適用,對於示例代碼卻不適用。 在示例代碼中,您應當使用硬編碼的值,以便將所有相關的資訊儘量緊密地組織在一起。 如果您按照編寫生產代碼的良好做法,在檔的開頭定義了所有常量,那麼當開發人員看到使用常量的代碼行時,就不得不滾動到檔開頭去查看常量的值是什麼。 這個簡單的操作可能會打斷他們的思路。 字串、整數、十六進位值和其他簡單值應當在使用它們的地方進行硬編碼。

注釋對於生產代碼和示例代碼都很有用,而在示例代碼中,它們尤為重要。 每個類、成員或函數的前面都至少要有一行注釋,解釋它是什麼以及它有什麼功能。 無論何時,只要代碼不是很淺顯易懂,就應當使用注釋進行說明,特別是在您記錄解決方法或某些不常用的內容時。 如果需要,這些注釋可以長達數行。 請使用完整的句子,不要擔心過於囉嗦。

通常,每 5 行或 10 行代碼應當至少有一行注釋。 但這一原則有幾種例外情況。 在您的演示中,完成週邊功能的代碼不需要這麼多注釋(例如,顯示 API 結果所需的 UI 代碼)。 如果您編寫的是一小段代碼,只包含了參考資料中的幾行代碼,可能根本就不需要注釋。 如果您要提供一個非常大的、更像是生產代碼的示例,則減少注釋行的數量可能會更切實可行。

無論您編寫的是生產代碼還是示例代碼,變數、類、成員和函數的名稱都應當清楚明白。 而與生產代碼相比,在清晰性比效率更重要的示例代碼中更需要嚴格貫徹這一原則。 長而複雜的名稱在生產代碼中可能是個問題,但是在示例代碼中就很值得,因為它們更清晰易懂。 即便是最短的變數名稱也應該有意義;無論您多麼希望,也不要使用沒有意義的變數名稱,例如“foo”或只包含一個字母的名稱。

物件導向程式設計是軟體工程最棒的發明之一。 您可能會很驚訝,儘管物件導向程式設計非常適合生產代碼,但通常並不適合示例代碼。 原因是,物件導向的設計會分散功能,以便將資料和函陣列合到一起,它還會使用繼承來減少重複代碼。 請記住,優秀的示例代碼的一個基本原則就是將相關的資訊組織在一起。 而物件導向的代碼則傾向于將相關的資訊分散到不同的類中。 這樣,開發人員就不必在繼承層次結構中搜尋某個方法的用途,從而避免浪費時間,也不會打斷思路。

當然,也有一些例外。 有些 API 需要物件導向程式設計才能正常運行。 非常大的、更像生產應用程式的示例可能也需要使用物件導向的設計。 但請注意,只要有可能,使用者總是希望在一個類中看到所有必要的資訊。

優秀的軟體設計的一項基本原則是將功能封裝到函數和方法中。 對於生產代碼,這提高了清晰性並減少了重複代碼。 這個規則也適用于示例代碼,因為它通常可以創建代碼塊,開發者可以輕鬆將代碼塊複製並粘貼到自己的代碼中,使用起來非常方便。

示例代碼偶爾也需要大量的代碼行,這些代碼行與您的 API 沒有直接關係,但對於示例的運行卻是必不可少的。 在這種情況下,最好的辦法就是嘗試將這些不相關的代碼行封裝到一個函數或方法中,這樣開發人員就能更輕鬆地略過這些代碼。

除非您的 API 明確提供了您需要演示的 UI 功能,否則您應當讓示例代碼中的 UI 元素盡可能保持簡單。 UI 代碼會佔用大量空間,並稀釋您要演示的重要代碼行。 開發人員並不在意您的示例看起來是否漂亮,他們只想瞭解 API 的工作原理。

如果您非得包含大量 UI 代碼行,請將這些代碼行包裝到單獨的函數中,使開發人員能夠輕鬆閱讀或略過。

最後,儘管異常處理對於生產代碼的正常運行至關重要,但在示例代碼中卻會稀釋相關代碼,讓讀者分心。 通常,一種好的解決辦法是不包含異常處理,而是加入一條注釋,指明在生產代碼中需要處理哪些異常。 但是,總會有一些情況,需要執行特定的調用以進行異常處理,在這樣的情況中,用額外的代碼行來展示異常處理的確切工作原理,還是值得的。

图 1 顯示了示例代碼中的一個函數示例,該示例代碼演示了如何在一個社交網站中以 C# 發出 REST 請求,以便返回與指定使用者相關的使用者 ID。 在生產代碼中,REST 端點 URL 應當作為常量與其他相關 URL 存儲在一起。 然而在示例代碼中,最好將此資訊放在開發人員最希望看到它的地方,並在函數中建立與其角色的連接。 還需要注意,雖然建議使用錯誤處理,但本示例中並未採用。 為了簡便起見,本示例中刪除了 XML 處理。

图 1 示例代码示例

/// <summary>
/// Returns an array of user IDs for users that 
/// are connected to the specified user.
Note that 
/// this is a simple, synchronous way to obtain the data.
/// </summary>
/// <param name="userId">The ID of the specified user.</param>
/// <returns>An array of user IDs that are connected to 
/// the specified user.</returns>

public int[] GetConnectedUserIds(int userId) {
  // Create variable to hold the returned IDs
  int[] connectedIds;

  // Construct a URL using the userId and the authorization token
  string url = 
    "http://webservices.contoso.com/users/connections?userid=" + 
    userId.ToString() +
    "&token=" + 
    authorizationToken;

  // Create the Web request using the url
  HttpWebRequest request = 
    WebRequest.Create(url) as HttpWebRequest;
 
  // Get the response
  using (HttpWebResponse response = 
    request.GetResponse() as HttpWebResponse) {

    // Read the response XML
    StreamReader reader = 
      new StreamReader(response.GetResponseStream());
    string xmlResponse = reader.ReadToEnd();

    // Process XML to extract user IDs for connected users 
    // and responseStatus
    ...
if (responseStatus != "ok") {
      // Handle errors here
      ...
}

    reader.Close();
  }

  return connectedIds;
}

參考資料

參考資料通常佔據了 API 文檔的大部分篇幅。 對於每個類、成員、函數、XML 元素等等,都需要提供詳細的資訊來介紹它們的作用及使用方法。 參考資料至少要涵蓋以下內容:

  • 簡要說明
  • 所有參數和返回值的說明
  • 任何能夠為開發人員提供説明的重要注解

如果有更多的時間和預算,請添加以下資訊:

  • 可能需要捕獲的異常
  • 指向其他相關概述或參考主題的連結
  • 一段示例代碼,最好來自您已經編寫好的示例代碼

優秀的參考文檔的風格應當始終一致。 有時已經有了風格指導原則,但往往需要您自己將它們弄明白。 图 2 列舉了一些編寫簡短說明的一般性指導原則。

例如,請參考圖 3 中所示的用於 Microsoft .NET Framework 中 Button 類的說明。 此示例直接摘自 MSDN 上的 SDK 文檔。

图 2 参考文档的风格

類型 指導原則 示例
以“Represents”(表示)這樣的詞開頭 “Represents a user’s photo album.”(表示使用者的相冊。)
方法和函數 以動詞開頭

“Returns the number of contacts for the specified area.”(返回指定區域的連絡人數量。)

“Pauses the video.”(暫停視頻。)

屬性 使用名詞,或以“Gets”(獲取)或“Gets and sets”(獲取和設置)這樣的動詞開頭

“The user’s tasks.”(使用者的任務。)

“Gets and sets a collection of the user’s tasks.”(獲取和設置使用者的任務集。)

事件 採用“Raised when”(當……時引發)或“Occurs when”(當……時發生)這樣的句式 “Raised when the response from server is received.”(當收到來自伺服器的回應時引發。)
XML 元素 使用名詞短語 “The city’s postal code.”(城市的郵遞區號。)
布林值 對於布林屬性,採用“Indicates whether”(指示……是否……)這樣的句式;對於方法和函數返回的布林值,採用“Returns whether”(返回……是否……)這樣的句式

“Indicates whether the control is visible.”(指示控制項是否可見。)

“Returns whether two regions intersect.”(返回兩個區域是否相交。)

图 3 参考文档示例

類或成員 類型 說明
類描述 表示 Windows 按鈕控制項。
Button 構造函數 構造函數 初始化新的 Button 類實例。
Focus 方法 將輸入焦點設置到控制項。
Visible 屬性 獲取或設置一個值,用於指示是否顯示控制項及其所有子控制項。
Click 事件 當控制項被按一下時發生。

Web API

在過去幾年中,Web API 的數量快速增長,因此值得我們思考一下 Web API 與本地 API 的不同之處。 “軟體即服務”正在成為一種普遍的業務模型,各個公司也迅速發現更多客戶希望能夠直接通過自己的系統使用他們提供的服務。 這意味著服務提供者需要提供一個公共 API,以供他們的客戶調用。

(有關術語的說明:我使用“本地 API”這個詞來描述在 Web 出現以前就存在的典型 API。 從技術上來說,這些 API 可以是遠端程序呼叫,因而不是本地 API;而 Web API 可以在與客戶機同屬一台電腦的伺服器上調用,因而是本地 API。 但是,在大多數情況下,使用 HTTP 等標準協定的 Web API 通過遠端方式使用,而其他 API 則在本地使用。)

由於 Web API 是一種相對比較新的技術,因此還沒有標準來規範其文檔的編寫。 Web API 文檔的品質良莠不齊,有的結構清晰、內容完整,有的卻只有 Wiki 上的一點點資訊。 如果您打算編寫 Web API 文檔,就值得花時間去研究各個公司的 API 文檔編寫風格,以便尋找合適的範本。 例如,Twilio 是一個語音和消息傳送應用程式平臺,擁有非常棒的 REST 文檔範例,其文檔可在以下網址找到:twilio.com/docs。 希望隨著時間的推移,行業內會逐漸採用少數幾種有效的範本。

從某種意義上來說,Web API 文檔比本地 API 文檔更為重要,因為開發人員更難以通過試用 Web API 來弄清其工作原理。 開發人員可以進行的調用次數可能有限制(配額),他們的實驗可能會影響實際的系統,或者是很難類比特定的條件,例如伺服器處於高負荷之下的狀況。

正如前文所述,開發人員非常依賴示例代碼。 Web API 的一個強大之處就是不受平臺和語言的限制。 遺憾的是,這也意味著在創建示例代碼時需要付出額外的努力。 您可能會發現自己需要使用 Python、Ruby、Java、C# 等語言來編寫示例代碼。 設法瞭解您的客戶最常用的語言是什麼,然後著重關注對他們最重要的語言。

Web API 最常用的兩種技術是 SOAP 和 REST。 SOAP 擁有一個定義格式(Web 服務描述語言,或 WSDL),這對於參考文檔來說是一個好的開始,而 REST 則沒有。 HTTP 調用示例和 XML/JSON 檔示例在演示這兩種技術的工作原理時都很有用,但是還不夠。 示例之後應該跟有表格,描述每個元素及其資料格式。

例如,僅僅將參數描述為字串,可能還遠遠不夠。 有沒有它不能處理的特殊字元? 它的長度有沒有限制? 如果某個 XML 元素是日期,您應當指定日期的格式。 如果是時間,則需要指定時區。

此外,您還需要解釋如何處理錯誤。 具體取決於您的 API 支援的格式。 如果您的 API 使用 HTTP 回應代碼來標記錯誤,應當在文檔中加以說明。 錯誤文檔應當解釋錯誤發生的原因以及解決問題的方法。

Web API 通常需要身份驗證,這也需要在文檔中詳細說明。 如果開發人員需要 API 金鑰,請務必提供如何獲得金鑰的分步說明。 此外,請勿忘記 Web API 是基於 HTTP 構建的,而 HTTP 是極其豐富的協定。 您可能需要將與 HTTP 相關的資訊記錄到文檔中,例如緩存、內容類別型和狀態碼。

Web API 是新鮮事物,我們還在探索為其編寫文檔的最佳方式。 希望在未來幾年內能夠看到相關標準。

發佈

到目前為止,我一直專注于內容,但是您還需要發佈文檔,以便讓開發人員閱讀。 通常,開發人員希望看到基於 Web 的超連結文檔,而不是 PDF 這樣的平面檔。 有幾種方式可以將您的文檔發佈到 Web 上。

如果您的 API 很小,那麼很簡單,只需創建 HTML 檔就足夠了。 使用 CSS 來設計外觀,以配合您公司的網站。

Wiki 提供了一種結構,適用于更為複雜的 API。 通過 Wiki,您還可以輕鬆地逐步更新文檔或向文檔添加內容,而無需使用其他工具或伺服器。 此外,Wiki 的團隊協作功能還可以讓整個團隊(甚至您的使用者)共同參與文檔編寫。 但是,草草拼湊一個 Wiki,或指望開發人員和使用者來編寫文檔,並不是非常可行的 API 文檔編寫策略。

關於 API 文檔編寫,有幾個免費的開源 Wiki 引擎可供選擇,而且它們已經非常流行,例如基於 PHP 的 MediaWiki (mediawiki.org/wiki/MediaWiki) 和基於 PERL 的 TWiki (twiki.org)。

Madcap Flare(請訪問 madcapsoftware.com/products/flare)和 Adobe RoboHelp(請訪問 adobe.com/products/robohelp)等商業文檔編寫工具主要用於編寫最終使用者文檔,但也可以輕鬆應用於 API 文檔編寫。 這些工具提供了一個簡單的 UI 用於輸入資訊,其外觀比 Wiki 更精美。 通過這些工具,可以使用相同的源生成 Web 文檔和平面檔文檔。

PBworks (pbworks.com) 和 MindTouch (mindtouch.com) 等線上協作服務也逐漸應用於 API 文檔編寫。 除了 Wiki 的協作功能以外,這些工具還提供了更多功能,例如託管、精細的存取控制和腳本編寫等功能。 這些服務通常需要支付訂閱費才能用於商業用途。

趕緊行動起來吧!

優秀的 API 文檔對於您平臺的推廣至關重要,還能減少公司收到的支援電話的數量。 如果您能夠說服經理雇用一位具備合適技能的技術撰稿人,那就再好不過了。 如果不能,請遵循本文中的指導原則。

您的文檔應當包含概述、入門説明、示例代碼和參考資料。 在概述中,請務必解釋為什麼要使用您的平臺。 將教程集中到一起,説明開發人員快速入門。 示例代碼應側重于清晰和簡潔,而不應始終遵循生產代碼的編碼原則。 參考資料應當內容翔實、風格一致。 有許多工具可以説明您將文檔發佈到 Web 上。

現在就開始編寫文檔吧!

Peter Gruenbaum   起初是一位物理學家,後來從事軟體發展,涉獵的技術領域包括 Tablet PC、增強現實、電腦輔助設計和手術類比。 他成立了 SDK Bridge LLC,將技術和寫作的愛好融為一體,主要負責撰寫技術文檔和講授技術。

衷心感謝以下技術專家對本文的審閱:John Musser (ProgrammableWeb) 和 Eugene Osovetsky (WebServius)