第十章:文件(Documentation)#
TL;DRs#
- 文件在時間與規模的維度上極為重要。
- 文件的變更應融入既有的開發工作流程。
- 每份文件聚焦於單一目的。
- 為你的讀者寫作,而非為自己。
什麼算是文件?#
本書所說的「文件」(documentation)涵蓋工程師為了完成工作而撰寫的所有補充文本:不僅包括獨立的文件,也包括程式碼中的註解(code comments)。事實上,Google 工程師撰寫的文件中,大多數都是以程式碼註解的形式存在。本章將進一步討論各種類型的工程文件。
為什麼需要文件?#
高品質的文件為工程組織帶來巨大的效益:
- API 與程式碼變得更容易理解,降低犯錯機率
- 設計目標與團隊方向更加聚焦
- 手動流程因為有清楚的步驟而更容易遵循
- 新成員加入團隊或了解程式碼庫所需的時間大幅縮短
然而,文件的效益都發生在下游——寫作者無法立即獲得回報。與測試不同的是,測試能快速為程式設計師帶來好處,文件則需要較多的前期投入,回報要到後來才會顯現。不過,就像對測試的投資一樣,對文件的投資最終會回本。你可能只寫一份文件一次,但它之後會被閱讀數百甚至數千次,初始成本被攤分到所有未來的讀者身上。不僅文件本身隨時間擴展,它對組織的擴展也至關重要。
文件能幫助回答這些關鍵問題:
- 為什麼做出這些設計決策?
- 為什麼用這種方式實作這段程式碼?
- 兩年後回來看自己寫的程式碼,當初為什麼要這樣做?
為何文件普遍被認為品質低落?#
在工程師的種種抱怨中,缺乏高品質文件是一個普遍的挫折。「這個方法的副作用是什麼?」「我在步驟三之後遇到錯誤。」「這份文件還是最新的嗎?」每位軟體工程師在職涯中都曾對文件的品質、數量或根本缺乏文件發出怨言。
工程師通常認為文件品質不佳,原因包括:
- 工程師常將寫作視為與程式設計完全不同的技能(本書試圖說明,即使有所不同,它也與軟體工程的技能並不完全分離)
- 部分工程師覺得自己不擅長寫作——但其實不需要精通英文,只需要能跳出自身視角,從讀者的角度來思考
- 寫文件的工具支援不足,或未整合進開發者的工作流程
- 文件被視為額外的負擔——又一件需要維護的東西——而非讓既有程式碼更容易維護的手段
並非每個工程團隊都需要技術寫作者(即使需要也不夠用)。這意味著工程師在很大程度上會自行撰寫大部分文件。因此,與其強迫工程師變成技術寫作者,不如思考如何讓撰寫文件對工程師來說更容易。
文件對撰寫者的效益#
即使對撰寫者自身,文件也帶來具體好處:
- 釐清 API 設計:撰寫文件是確認 API 是否合理的最佳方式。撰寫文件的過程本身就會促使工程師重新評估原本不會被質疑的設計決策。如果你無法解釋或定義它,代表設計得不夠好。
- 提供維護路線圖與歷史紀錄:程式碼中應避免「技巧」,但好的註解在你兩年後回頭看程式碼、試圖找出問題時幫助極大。
- 讓程式碼顯得更專業並吸引使用者:開發者自然會假設文件完善的 API 代表設計較好。雖然這聽起來像是表面效益,但其實不完全是——產品是否有好的文件,通常是該產品維護品質的良好指標。
- 減少他人的提問:這大概是對文件撰寫者最大的長期效益。如果你需要向不同人解釋同一件事超過一次,把它文件化通常更有效率。
Google 的 C++ Style Guide 指出「為讀者最佳化(optimize for the reader)」。這條準則不僅適用於程式碼,也適用於程式碼周圍的註解以及 API 的文件集。就像測試一樣,你投入在撰寫好文件上的努力,會在文件的生命週期中獲得多倍的回報。
文件即程式碼(Documentation Is Like Code)#
軟體工程師即便主要使用單一程式語言,仍會為了解決特定問題而使用不同語言——可能用 shell script 或 Python 處理命令列任務,或者用 C++ 寫後端但用 Java 寫中介層。每種語言都是工具箱中的工具。
文件也應該如此:它是一種工具,只是用另一種語言(通常是英文)來達成特定目的。撰寫文件與寫程式碼並無太大差異——它有規則、特定語法和風格決定,目的同樣是強制一致性、提高清晰度、避免(理解上的)錯誤。在技術文件中,文法之所以重要,不是因為需要規則本身,而是為了統一口吻、避免讓讀者困惑或分心。
文件應具備的特性#
文件如同程式碼,需要擁有者。沒有擁有者的文件會逐漸過時、難以維護。明確的擁有權也使文件更容易透過既有的開發流程來處理——bug 追蹤系統、code review 工具等。當不同擁有者的文件彼此衝突時,重要的是指定權威文件(canonical documentation):確定主要來源,並將其他相關文件整合進去或淘汰重複項。
Google 內部廣泛使用的「go/ 連結」(參見第三章)使這個流程更簡單。有簡明 go/ 連結的文件往往成為權威的真實來源(source of truth)。另一種推廣權威文件的方式是將它們直接與所記錄的程式碼關聯,放在版本控制下、與原始碼並排。
Google 主張文件應盡量像程式碼一樣對待:
- 有內部的撰寫政策或規則
- 納入版本控制(source control)
- 有明確的擁有者(owner)負責維護
- 變更時需經過審查(review),並隨程式碼同步更新
- 像 bug 一樣追蹤問題
- 定期進行評估(某種程度上的「測試」)
- 盡可能衡量準確性、新鮮度等指標(工具在這方面仍有待發展)
工程師越是把文件視為軟體開發的「必要任務之一」,就越不會抗拒撰寫的前期成本,也越能收穫長期效益。此外,降低撰寫文件的門檻也能減少這些前期成本。
案例研究:Google Wiki#
Google 早期規模較小時,技術寫作者不多。最簡單的資訊分享方式是使用內部 wiki(GooWiki)。起初看似合理——所有工程師共用同一套文件集,可隨需更新。
但隨著 Google 擴大規模,wiki 模式的問題浮現:
- 缺乏擁有者:許多文件變得過時。當 GooWiki 最終被淘汰時,約 90% 的文件在前幾個月內無人瀏覽或更新。
- 缺乏新增流程:重複的文件和文件集不斷出現。GooWiki 有扁平的命名空間,人們不善於為文件集施加層級結構。關於設定 Borg(生產運算環境)的文件曾多達 7 到 10 份,其中只有少數似乎被維護,且大多只適用於特定團隊的權限和假設。
- 修復者與使用者的錯位:能修正文件的人不需要使用這些文件;發現文件有錯的新使用者既無法確認文件是否錯誤,也沒有簡便的方式回報問題。他們知道有問題(因為文件不管用),但無法「修正」它。反之,最有能力修正文件的人在寫完後往往不需要再參考。
文件品質之差,最終在 Google 年度開發者調查中成為第一名的開發者抱怨。
解決方案:將重要文件移至版本控制。文件開始有擁有者、在原始碼樹中有固定位置、有識別與修復 bug 的流程,品質大幅改善。文件的撰寫和維護方式開始與程式碼相同——錯誤可透過 bug 追蹤系統回報,變更可透過既有的 code review 流程處理。最終,工程師開始自行修正文件,或將變更送交給技術寫作者(後者通常是擁有者)。
將文件移至版本控制起初引發不少爭議。許多工程師擔心廢除 GooWiki 這個「資訊自由的堡壘」,會因為較高的門檻(需要審查、需要擁有者等)而導致品質下降。但事實正好相反——文件變得更好了。
引入 Markdown 作為通用文件格式也有幫助,讓工程師不需 HTML 或 CSS 專業知識即可編輯。Google 最終推出自己的框架 g3doc,將文件嵌入程式碼旁邊。有了這個框架,文件進一步改善,因為文件與原始碼在工程師的開發環境中並存。現在,工程師可在同一個變更集中同時更新程式碼與相關文件。
關鍵差異在於維護文件的體驗變得與維護程式碼相似:工程師提交 bug、在 changelist 中修改文件、送出審查給專家。利用既有的開發工作流程,而非創造新流程,是成功的關鍵。
了解你的讀者(Know Your Audience)#
工程師撰寫文件時最常犯的錯誤之一是只為自己寫。為自己寫並非全無價值——畢竟幾年後你可能需要回頭看這段程式碼。但如果只為自己寫,你會做出某些假設,而考慮到你的文件可能被非常廣泛的受眾閱讀(整個工程部門、外部開發者),即使只流失少數讀者也是很大的成本。隨著組織成長,文件中的錯誤會變得更加突出,你的假設往往不再適用。
在開始撰寫之前,應先(正式或非正式地)辨識文件需要滿足的受眾。設計文件可能需要說服決策者;教學文件可能需要提供非常明確的指示給完全不熟悉程式碼庫的人;API 文件可能需要為專家和新手都提供完整且準確的參考資訊。
務必找出主要受眾,並針對他們來寫。
好的文件不需要完美無瑕。工程師撰寫文件時常犯的一個錯誤,是認為自己需要成為更好的寫作者。如果用這個標準衡量,很少有軟體工程師會去寫文件。把寫作想成測試或其他工程流程即可——用讀者期望的聲音和風格來寫。記住,你的讀者曾站在你曾經站的地方,但沒有你現在的領域知識。你不需要成為傑出的寫作者,你只需要讓像你一樣的人熟悉這個領域。先立下基礎,之後再逐步改善。
受眾的類型#
受眾通常依據以下標準區分:
- 經驗等級:專業程式設計師,或可能連程式語言都不太熟悉的初級工程師
- 領域知識:團隊成員,或只熟悉 API 端點的其他組織內工程師
- 目的:需要 API 完成特定任務、希望快速找到資訊的終端使用者,或負責特別複雜實作細節的軟體專家
有時不同的受眾需要不同的寫作風格,但多數情況下,技巧在於以盡可能廣泛適用於不同受眾群體的方式來撰寫。為專家寫可能讓你省略某些內容,但會讓新手困惑;反之,向新手詳細解釋一切,專家肯定會感到厭煩。
在平衡不同受眾時,一個有效的策略是保持文件簡短。寫得足夠詳細以向不熟悉主題的人解釋複雜概念,但不要讓專家感到厭煩。撰寫簡短的文件通常需要先寫一份較長的版本(把所有資訊記下來),然後進行編輯,盡可能移除重複資訊。正如 Blaise Pascal 所說:「如果我有更多時間,我會寫一封更短的信。」保持文件簡短明確,就能同時滿足專家和新手。
按使用方式區分的讀者#
另一個重要的受眾區分,是基於使用者如何接觸到文件:
- 搜尋者(Seekers):知道自己要找什麼,想確認眼前的內容是否符合需求。對這群受眾的關鍵教學手段是一致性。如果你在為這群人撰寫參考文件——例如在程式碼檔案中——你會希望註解遵循類似的格式,讓讀者能快速掃描並找到所需內容。
- 漫遊者(Stumblers):不確定自己要什麼,可能只是隱約知道如何實作手上的工作。對這群受眾的關鍵是清晰度。在檔案頂部提供概述或介紹,說明程式碼的用途。辨識文件何時不適合某類受眾也很有用。Google 許多文件會以「TL;DR 聲明」開頭,例如「TL;DR: 如果你對 Google 的 C++ 編譯器沒有興趣,可以停止閱讀了。」
消費者 vs. 提供者#
最後一個重要的受眾區分是消費者(如 API 使用者)和提供者(如專案團隊成員)。面向其中一方的文件應盡可能與面向另一方的文件分開。實作細節對團隊成員的維護很重要,但終端使用者不需要閱讀這些資訊。工程師經常在發布的函式庫 API 參考文件中混入設計決策,但這些推理更適合放在專門的文件(設計文件)中,或至多放在隱藏於介面背後的實作細節中。
文件類型(Documentation Types)#
工程師在工作中撰寫各種不同類型的文件:設計文件、程式碼註解、操作指南、專案頁面等。這些都算「文件」,但重要的是了解不同的類型,且不要混合。一份文件通常應有單一目的,並堅持它。就像 API 應該做好一件事一樣,避免在一份文件中嘗試做太多事。
Google 早期的團隊常擁有巨大的 wiki 頁面,裡面堆滿了大量連結(許多已失效或過時)、一些關於系統運作的概念資訊、API 參考等,全部混在一起。這類文件之所以失敗,是因為它們沒有服務單一目的(而且太長以至於沒人會讀——某些臭名昭著的 wiki 頁面要滾動數十個螢幕)。
主要文件類型包括:
- 參考文件(Reference documentation),包含程式碼註解
- 設計文件(Design documents)
- 教學文件(Tutorials)
- 概念文件(Conceptual documentation)
- 著陸頁(Landing pages)
參考文件(Reference Documentation)#
這是工程師最常撰寫的文件類型,幾乎每天都需要撰寫某種形式的參考文件。所謂參考文件,指的是記錄程式碼庫中程式碼用法的所有內容。程式碼註解是工程師必須維護的最常見參考文件形式。
程式碼註解可分為兩大陣營:
- API 註解:面向使用者,不需要討論實作細節或設計決策,也不能假設使用者與 API 作者一樣熟悉
- 實作註解(Implementation comments):可假設讀者具備較多領域知識,但要謹慎——人員會離開專案,有時明確記錄你為何以此方式撰寫程式碼會更安全
大多數參考文件由程式碼中的註解產生(參考文件應盡可能單一來源化)。Java、Python 等語言有專門的註解框架(Javadoc、PyDoc、GoDoc)以利生成參考文件。C++ 雖無標準的「參考文件」實作,但由於 C++ 將 API 表面(在標頭檔 .h 中)與實作(.cc 檔案)分開,標頭檔自然成為記錄 C++ API 的場所。Google 的 Code Search 瀏覽器(參見第十七章)功能強大,使用者不僅能輕鬆搜尋程式碼,通常還能找到程式碼的原始定義作為最佳結果。讓文件與程式碼定義並排,也使文件更容易被發現和維護。
Google 的程式碼註解指引(以 C++ 為例)包含三個層級:
1. 檔案註解(File comments)
Google 幾乎所有程式碼檔案都必須包含檔案註解。檔案註解應以概述開始,說明所閱讀的程式碼中包含什麼。它應標明程式碼的主要用途和目標受眾。若前一兩段無法精確描述 API,通常代表 API 設計不夠完善,此時應考慮將 API 拆分成獨立的元件。
2. 類別註解(Class comments)
Google 所有公開類別(及 struct)都必須包含類別註解,描述該類別、重要方法及其目的。類別註解通常應以名詞方式撰寫,強調其物件面向。例如:「AlphaNum 類別作為 StrCat() 和 StrAppend() 的主要參數型別,提供數值、布林值和十六進位值到字串的高效轉換。」
3. 函式註解(Function comments)
所有自由函式(free functions)或類別的公開方法都必須包含函式註解。函式註解應以祈使動詞開頭,描述函式的行為與回傳值(如「Merges」、「Deletes」、「Creates」)。搜尋者可以快速掃描 API,只讀動詞就能判斷函式是否適用。
Google 發現不需要「Returns:」、「Throws:」等各種樣板格式——用流暢的散文註解往往更清楚且不冗贅:
// Creates a new record for a customer with the given name and address,
// and returns the record ID, or throws `DuplicateEntryError` if a
// record with that name already exists.
int AddCustomer(string name, string address);注意後置條件、參數、回傳值和例外情況如何自然地一起記錄,因為它們彼此並非獨立。加入明確的樣板區段會讓註解更冗長且重複,但不會更清楚(甚至可以說更不清楚)。
設計文件(Design Docs)#
Google 大多數團隊在啟動重大專案前都需要經過核准的設計文件。工程師使用團隊核准的設計文件範本撰寫提案,通常在 Google Docs 上進行協作(因為 Google Docs 有良好的協作工具)。某些團隊要求在特定會議上討論與辯論設計文件,讓專家可以對設計的細節提出批評。在某種程度上,這些設計討論相當於程式碼撰寫前的 code review。
由於開發設計文件是工程師在部署新系統之前最先進行的流程之一,它也是確保各種考量被涵蓋的便利場所。Google 的標準設計文件範本要求工程師考慮安全性影響、國際化、儲存需求、隱私考量等面向,且這些部分通常由各領域的專家審查。
一份好的設計文件應涵蓋:
- 設計的目標
- 實作策略
- 關鍵設計決策及其個別的權衡取捨(trade-offs)
- 替代設計方案及其優缺點
經核准的設計文件不僅是歷史紀錄,也是衡量專案是否成功達成目標的標準。大多數團隊會將設計文件歸檔在團隊文件的適當位置,以便日後回顧。在產品發布前回顧設計文件,確認撰寫時的目標是否仍與發布時的目標一致,這通常很有用。
教學文件(Tutorials)#
每位新加入團隊的工程師都需要盡快上手。一份引導新人完成專案設定的教學文件是無價之寶;「Hello World」早已確立為確保所有團隊成員起步正確的最佳方式之一。這適用於文件和程式碼。大多數專案都值得有一份「Hello World」文件——不假設任何前提,讓工程師完成某個「真實」的操作。
撰寫教學文件的最佳建議:
- 最佳撰寫時機是剛加入團隊時(同時也是發現既有教學文件 bug 的最佳時機)。拿出筆記本,沿途記下所有你需要做的事,不假設任何領域知識或特殊設定。完成後,你可能知道過程中犯了哪些錯誤及原因,然後可以精簡步驟成更流暢的教學。
- 明確編號每個步驟:如果教學的焦點在於使用者,就編號使用者需要執行的每個動作。不要編號系統可能自動回應的動作。
- 合併原子操作:將系統的回應說明放在使用者操作步驟的敘述中,而非獨立編號。
- 區分使用者的輸入與輸出:如果教學有使用者可見的輸入或輸出,應在獨立行中以等寬字體標示。
- 宣告前置條件:如果需要假設某些設定,在教學開頭明確列出。
教學文件中最惱人的錯誤就是步驟四失敗了,因為作者忘記在前面步驟中提醒使用者進行必要的授權或設定。務必明確且完整地列出每一個步驟——沒有比這更重要的事了。
概念文件(Conceptual Documentation)#
有些程式碼需要比參考文件更深入的解釋或洞見。概念文件用來提供 API 或系統的概覽,例如流行 API 的函式庫概覽、描述伺服器中資料生命週期的文件等。在幾乎所有情況下,概念文件旨在補充而非取代參考文件。這常導致某些資訊的重複,但這是有目的的:為了促進清晰度。概念文件不需要涵蓋所有邊界情況(但參考文件應該虔誠地涵蓋這些情況)。在這種情況下,為了清晰度而犧牲一些準確性是可以接受的。概念文件的核心目的是傳達理解。
概念文件的特點:
- 是最難撰寫的文件類型,因此也是最常被忽略的
- 往往無法直接嵌入原始碼中,因為沒有一個權威位置可以放置。有些 API 表面較廣,此時檔案註解可能適合放置概念性解釋。但通常一個 API 需要與其他 API 或模組協作,唯一合理的地方是獨立的概念文件
- 如果程式碼註解是文件的單元測試,概念文件就是整合測試
- 需要對廣泛受眾有用——專家和新手皆然
- 應聚焦於常見用法,將罕見用法或副作用留給參考文件
著陸頁(Landing Pages)#
大多數工程師是某個團隊的成員,大多數團隊在公司內部網路上都有一個「團隊頁面」。這些網站往往有些混亂:典型的著陸頁可能包含一些有趣的連結、幾份標題為「先讀這個!」的文件,以及同時面向團隊和客戶的資訊。這類文件剛開始有用,但很快變成災難——因為維護太麻煩,最終只有勇者或走投無路的人才會去修正。
幸運的是,這類文件看起來嚇人,實際上修正起來很直觀:
- 確保著陸頁清楚標示其用途
- 只包含指向其他頁面的連結以獲取更多資訊
- 如果著陸頁上的內容做的事情超過「交通指揮」,它就沒有在做好自己的工作
- 如果著陸頁有太多連結(不應需要滾動多個螢幕),考慮按分類拆分
- 不要讓同一頁面同時服務兩種角色——既是產品/API 使用者的入口頁面,又是團隊的首頁。建立獨立的「團隊頁面」作為內部頁面,與主要著陸頁分開。團隊需要知道的和 API 客戶需要知道的往往截然不同。
文件審查(Documentation Reviews)#
在 Google,所有程式碼都需要審查,code review 流程已被充分理解和接受。一般來說,文件也需要審查(雖然這一點的接受度較低)。如果你想「測試」文件是否有效,通常應該讓其他人來審查。
技術文件可受益於三種不同類型的審查,各自強調不同的面向:
- 技術審查(Technical review):著重準確性。通常由主題專家——往往是你的團隊成員——進行,常作為 code review 的一部分。
- 受眾審查(Audience review):著重清晰度。通常由不熟悉該領域的人進行,例如剛加入團隊的新人或 API 的客戶。
- 寫作審查(Writing review):著重一致性。通常由技術寫作者或志願者進行。
當然,這些界線有時會模糊,但如果你的文件是高能見度的或可能被外部發布,你可能需要確保它接受更多類型的審查。即使只有一位審查者審閱你的文字,也比沒有人審查好。
如果文件已融入工程工作流程,它通常會隨時間自然改善。Google 現在大多數文件都會隱式地經過受眾審查,因為受眾在某個時點會使用它們,並希望透過 bug 或其他形式的回饋讓你知道文件何處不適用。
案例研究:Developer Guide Library#
Google Wiki 的問題在某些文件中並未出現。例如 Google C++ Style Guide 由一群資深工程師(style arbiters)管理,因為有人關心這份文件,它被維護得很好。這份文件也是權威的——只有一份 C++ Style Guide。
直接存在於原始碼中的文件是建立權威文件的一種方式;如果文件與原始碼並排,它通常是最適用的。在 Google,每個 API 通常有一個獨立的 g3doc 目錄存放此類文件(以 Markdown 撰寫,可在 Code Search 瀏覽器中閱讀)。讓文件與原始碼並存,不僅建立了事實上的擁有權,也讓文件感覺更像是程式碼的一部分。
然而,有些文件集無法很自然地存在於原始碼中。例如面向 Google 工程師的「C++ 開發者指南」,在原始碼中沒有明顯的位置。對於這類跨 API 邊界的文件,Google 建立了獨立的文件集(documentation depot),按主題而非 API 組織。這些文件集稱為「Developer Guides」,具有統一的導航和外觀,通常由技術寫作者管理,因為他們更擅長跨 API 邊界的解釋。
隨著時間推移,這些開發者指南成為權威來源。擁有競爭性或補充性文件的使用者開始願意將文件併入權威文件集,並淘汰重複內容。最終,C++ Style Guide 成為更大的「C++ Developer Guide」的一部分。隨著文件集變得更全面且更具權威性,品質也隨之提升。工程師開始提交 bug,因為他們知道有人在維護這些文件。
go/ 連結(參見第三章)的引入,讓大多數文件更容易在特定主題上建立權威性。例如 C++ Developer Guide 建立在「go/cpp」上。隨著更好的內部搜尋、go/ 連結,以及多份文件整合成統一的文件集,這些權威文件集隨時間變得更具權威性和穩健性。
文件哲學(Documentation Philosophy)#
WHO、WHAT、WHEN、WHERE、WHY#
大多數技術文件回答的是「HOW」問題——這個怎麼運作?如何對這個 API 進行程式設計?如何設定這個伺服器?因此,軟體工程師傾向於在任何文件中直接跳到「HOW」,而忽略其他相關問題。在任何文件的前兩段中,應嘗試回答以下問題:
- WHO(誰):即受眾。有時你還需要在文件中明確指出並稱呼受眾。例如:「本文件面向 Secret Wizard 專案的新進工程師。」
- WHAT(什麼):說明文件的目的。例如:「本文件是一份教學,指導如何在測試環境中啟動 Frobber 伺服器。」有時光是寫下 WHAT 就能幫你適當地框架文件。
- WHEN(何時):記錄文件的建立、審查或更新日期。原始碼中的文件隱含有此日期,但若沒有,務必在文件中註明撰寫(或上次修訂)日期。
- WHERE(何處):決定文件應存放的位置。通常偏好某種版本控制之下,理想情況是與它所記錄的原始碼並排。Google 常使用 Google Docs 進行協作,但在某個時點,共用文件會從討論變成穩定的歷史紀錄。屆時,應將它移到更永久的地方,具有明確的擁有權、版本控制和責任歸屬。
- WHY(為何):設立文件的目的。摘要讀者在閱讀後應帶走什麼。在撰寫摘要時,驗證是否達到了你原始的期望。
開頭、中段與結尾#
所有文件都應有開頭、中段與結尾。雖然聽起來顯而易見,但大多數文件確實至少應該有這三個部分。不要害怕加入章節——它們將內容切分為邏輯段落,為讀者提供路線圖。即使是最簡單的文件通常也有不止一件事要說。
大多數工程師厭惡冗餘,這有充分的理由。但在文件中,適度的冗餘是有用的。埋藏在大段文字中的重要論點可能難以記住或提取。另一方面,將該論點放在較早的顯著位置可能會失去後面提供的上下文。通常的解決方案是在引言段落中引入並摘要重點,然後用後續章節以更詳細的方式論證。在這種情況下,冗餘幫助讀者理解所述內容的重要性。
好文件的三個參數#
好文件通常有三個面向:完整性(completeness)、準確性(accuracy) 和清晰度(clarity)。你很少能在同一份文件中兼顧三者:
- 試圖讓文件更「完整」時,清晰度可能開始受損。如果你試圖記錄 API 的每一個可能用法,最終可能得到一團難以理解的混亂。
- 對於程式語言而言,在所有情況下完全準確(並記錄所有可能的副作用)也可能影響清晰度。
- 試圖清楚解釋一個複雜主題,可能會微妙地影響文件的準確性——例如在概念文件中你可能決定忽略某些罕見的副作用。
關鍵是:一份「好文件」是能達成其預期目標的文件。為每份文件(和每種文件類型)決定焦點,並相應調整寫作方式。寫概念文件?你可能不需要涵蓋 API 的每個部分。寫參考文件?你可能需要完整,但可能需要犧牲一些清晰度。寫著陸頁?聚焦於組織,將討論降到最低。
如何快速提升文件品質?聚焦於受眾的需求。通常,少即是多。例如,工程師常犯的一個錯誤是在 API 文件中加入設計決策或實作細節。就像你應該在設計良好的 API 中將介面與實作分離一樣,你應該避免在 API 文件中討論設計決策。使用者不需要知道這些資訊。相反,把這些決策放在專門的文件中(通常是設計文件)。
淘汰過時文件(Deprecating Documents)#
舊文件如同舊程式碼,會造成問題。隨著時間推移,文件會變得陳舊、過時或(經常)被遺棄。盡量避免遺棄文件,但當文件不再服務任何目的時,應移除或標記為過時(如果可能,指出新資訊的位置)。即使對於沒有擁有者的文件,某人加上「這已經不再有效了!」的註記也比什麼都不說、讓一份看似權威但已失效的東西留在那裡要好。
Google 常為文件附上「新鮮度日期」(freshness dates)。這類文件註記了上次審查的時間,文件集的元資料會在文件一段時間未被更動後(例如三個月)發送電子郵件提醒。擁有此類文件的使用者有動機保持新鮮度日期為最新狀態(如果文件在版本控制下,這需要經過 code review)。Google 發現在文件本身中加上「Last reviewed by…」的署名,能進一步提升採用率。
何時需要技術寫作者?#
Google 早期成長時,軟體工程領域的技術寫作者不夠。被認為重要的專案往往會獲派技術寫作者,無論團隊是否真正需要。想法是寫作者可以減輕團隊撰寫和維護文件的負擔,讓重要專案能更快推進。但這被證明是錯誤的假設。
Google 發現,大多數工程團隊能夠自行為自己(團隊內部)完美地撰寫文件;只有當需要為另一群受眾撰寫時,才真正需要協助,因為為不同受眾寫作是困難的。團隊內部關於文件的回饋迴路更即時,領域知識和假設更清楚,感知到的需求更明顯。支援單一團隊不是有限且專業資源的最佳利用方式,還引入了一種反效果的激勵:成為重要專案,你的工程師就不需要寫文件了。
技術寫作者作為有限的資源,應聚焦於軟體工程師在正常職責中不需要做的任務,通常涉及:
- 跨 API 邊界的文件:專案 Foo 可能清楚知道自己需要什麼文件,但可能不太清楚專案 Bar 需要什麼
- 挑戰團隊的假設:技術寫作者更能站在不熟悉領域的人的角度
- 這也是為什麼許多(甚至大多數)軟體工程技術寫作者傾向於聚焦於這種特定類型的 API 文件
阻止工程師自行撰寫文件,結果正好與你想要的相反。讓撰寫文件更容易——而非代替他們撰寫——才是正確的方向。
結論#
Google 在過去十年中在文件品質上取得了長足的進展,但坦率地說,文件在 Google 仍未成為一等公民(first-class citizen)。相比之下,工程師已逐漸接受測試對任何程式碼變更都是必要的,無論變更多小。測試工具也是穩健的、多樣的,並在工程工作流程的各個節點中整合。文件尚未達到接近同等的水準。
公平地說,文件不一定有與測試相同的需求。測試可以是原子化的(單元測試)且可遵循規定的形式和功能。文件在大多數情況下做不到。測試可以自動化,而文件的自動化方案往往不足。文件本質上是主觀的——文件的品質不是由撰寫者衡量,而是由讀者衡量,且往往是非同步的。
儘管如此,已有共識認為文件是重要的,圍繞文件開發的流程正在改善。2010 年代末的工程文件狀態,類似於 1980 年代末軟體測試的狀態——每個人都認識到需要付出更多努力來改善,但組織層級對其關鍵效益的認可尚不足夠。
要改變工程文件的品質,工程師與整個工程組織需要接受一個事實:他們既是問題,也是解方。與其對文件的現狀舉手投降,他們需要認識到產出高品質文件是工作的一部分,長遠來看能節省時間和精力。對於任何預期存活超過幾個月的程式碼,投入在文件上的額外心力不僅會幫助他人,也會幫助你自己維護那些程式碼。