如何寫好(hǎo)技術文檔——來自Google十多年的文檔經(jīng)驗
很多技術人自己非常輕視技術文檔的書寫,然而又時(shí)常抱怨文檔不完善、質量差、更新不及時(shí)…… 這(zhè)種(zhǒng)在程序猿間普遍存在的矛盾甚至已經(jīng)演變成(chéng)了一個段子。
文檔的重要性
高質量的文檔對(duì)于一個組織或團隊來說(shuō)有非常多的益處,比如讓代碼和API更容易理解、錯誤更少;讓團隊成(chéng)員更專注于目标;也可以讓一些手工操作更容易;另外如果有新成(chéng)員加入的話有文檔也會(huì)讓他們更快融入……
寫文檔有比較嚴重的收益滞後(hòu)性,不像測試,你跑一個測試case,它能(néng)立即告訴你是對(duì)還(hái)是錯,它的價值馬上就(jiù)體現出來了。而寫一份文檔,随著(zhe)時(shí)間的推移,它的價值才會(huì)逐漸體現出來。 你可能(néng)隻寫一次文檔,將(jiāng)來它會(huì)被(bèi)閱讀上百次、上千次,因爲一份好(hǎo)的文檔可以在未來替你向(xiàng)别人回答類似下面(miàn)這(zhè)些問題。
爲什麼(me)當時(shí)是這(zhè)麼(me)決策的?
爲什麼(me)代碼是這(zhè)樣(yàng)實現的?
這(zhè)個項目裡(lǐ)都(dōu)有哪些概念?
……
寫文檔同樣(yàng)對(duì)于寫作者也有非常大的收益:
幫你構思規範化API: 寫文檔的過(guò)程也是你審視你API的過(guò)程,寫文檔時(shí)會(huì)讓你思考你API設計是否合理,考慮是否周全。如果你沒(méi)法用語言將(jiāng)API描述出來,那麼(me)說(shuō)明你當前的API設計是不合理的。
文檔也是代碼的另一種(zhǒng)展現: 比如你兩(liǎng)年後(hòu)回過(guò)頭來看你寫過(guò)的代碼,如果有注釋和文檔,你可以很快速理解代碼。
讓你的代碼看起(qǐ)來更專業: 我們都(dōu)有個感覺,隻要文檔齊全的API都(dōu)是設計良好(hǎo)的API,雖然這(zhè)個感覺并不完全正确,但這(zhè)兩(liǎng)者确實是強相關的,所以在很多人眼裡(lǐ),文檔的完善度也成(chéng)爲衡量一個産品專業度的指标。
避免被(bèi)重複的問題打擾: 有些問題你隻需要寫在文檔裡(lǐ),這(zhè)樣(yàng)有人來問你的時(shí)候你就(jiù)可以讓他直接去看文檔了,而不是又給他解釋一遍。
爲什麼(me)大多數人都(dōu)不喜歡寫文檔?
關于文檔的重要性,每個技術人或多或少都(dōu)知道(dào)一些,但很多人還(hái)是沒(méi)有寫文檔的習慣,爲什麼(me)? 除了上文中提到的文檔的收益滞後(hòu)性外,還(hái)有以下幾點原因:
很多工程師習慣將(jiāng)寫代碼和寫作割裂開(kāi),不僅僅是在工作上,而且在思想上就(jiù)認爲它們是完全不相關的兩(liǎng)項工作,這(zhè)就(jiù)導緻好(hǎo)多人重代碼不重文檔。
也有很多工程師認爲自己不善寫作,索性就(jiù)不寫了。 這(zhè)實際是個偷懶的借口,寫文檔不需要華麗的辭藻、生動的語言,你隻需要將(jiāng)問題講清楚即可。
有時(shí)候工具不好(hǎo)用也會(huì)影響的文檔寫作。如果沒(méi)有一個很好(hǎo)的寫作工具將(jiāng)寫文檔嵌入到開(kāi)發(fā)工作流程中的話,寫作确實會(huì)增加工作的負擔。
大多數人將(jiāng)寫文檔看做是工作的額外負擔。 我代碼都(dōu)沒(méi)時(shí)間寫,哪有時(shí)間寫文檔!,這(zhè)其實是錯誤的觀念,文檔雖然前期有投入,但能(néng)讓你代碼的後(hòu)期維護成(chéng)本大幅降低,磨刀不誤砍柴工這(zhè)個道(dào)理相信大家都(dōu)還(hái)是能(néng)理解的。
如何産出高質量文檔
既然理解了好(hǎo)文檔的重要性,我們如何保證在時(shí)間的長(cháng)河中維護好(hǎo)一份文檔,這(zhè)裡(lǐ)有些相關的方法論,大家可以參考下。
像管理代碼一樣(yàng)管理文檔
對(duì)于如何寫出好(hǎo)代碼,整個技術圈已經(jīng)有好(hǎo)多經(jīng)驗的總結了,比如書籍《重構》《代碼簡潔之道(dào)》…… 針對(duì)各種(zhǒng)編程語言,也有相關的規範,比如國(guó)外的Google C++規範,國(guó)内的阿裡(lǐ)Java開(kāi)發(fā)規範等…… 但對(duì)于文檔 似乎相關的資料卻很少。但實際上,不應該把文檔和代碼割裂開(kāi)來,你可以簡單粗暴地認爲文檔其實就(jiù)是用一種(zhǒng)特殊語言書寫的代碼,這(zhè)種(zhǒng)語言就(jiù)是人類的語言。這(zhè)麼(me)想的話,實際上我們很多在代碼和工程中總結出來的經(jīng)驗,也可以直接用在文檔中,比如:
有統一的規範
有版本控制
有明确的責任人維護
有變更Review機制
有問題的反饋和更新機制
定期更新
有衡量的指标(比如準确性,時(shí)效性)
明确你的讀者是誰
寫文檔有一個很常見的錯誤,那就(jiù)是很多人文檔都(dōu)是寫給自己看的,這(zhè)種(zhǒng)情況下就(jiù)會(huì)導緻你的文檔隻有自己或者和你有相似知識背景的人才能(néng)看懂,團隊較小時(shí)這(zhè)種(zhǒng)問題還(hái)好(hǎo),你們都(dōu)做著(zhe)類似的工作,所以也都(dōu)能(néng)看懂文檔。但當團隊逐漸壯大後(hòu),問題就(jiù)會(huì)凸顯出來,新人有時(shí)候有著(zhe)和你不同的工作背景,甚至現在都(dōu)做著(zhe)不同的工作内容,這(zhè)時(shí)候你之前寫的文檔他們就(jiù)很難讀懂了。
所以在寫文檔之前請明确你文檔可能(néng)的讀者會(huì)是哪些人,然後(hòu)針對(duì)他們的特點著(zhe)重關注如何才能(néng)讓他們理解。當然,文檔也不一定要非常嚴肅和完美,隻要能(néng)向(xiàng)你潛在的讀者說(shuō)明問題即可。 記住文檔是寫給别人看的,不是給自己看的。
根據專業水平可以大緻將(jiāng)讀者分爲三種(zhǒng) 新手、老手和專家,針對(duì)不同水平的人寫作需要有側重點。比如針對(duì)新手,你需要重點介紹下裡(lǐ)面(miàn)涉及到的術語和概念,然後(hòu)詳細講解具體的的實現。相反,針對(duì)專家 你可以省去這(zhè)些額外的信息。注意,這(zhè)裡(lǐ)沒(méi)有嚴格的标準,因爲有些文章新手會(huì)看,專家也會(huì)看, 這(zhè)裡(lǐ)還(hái)是需要具體情況具體分析。
另外一種(zhǒng)對(duì)讀者分類的方式就(jiù)是根據讀者閱讀文檔的目的來分類,比如有人知道(dào)自己遇到了什麼(me)問題,就(jiù)是來找解決方案的。還(hái)有一批人隻有一個簡單的想法,但不知道(dào)具體的問題。舉個例子,以讀數據庫慢爲例,前者已經(jīng)知道(dào)數據庫慢可能(néng)是因爲數據量巨大且沒(méi)有加索引,解決方案很簡單 加索引,這(zhè)時(shí)候他可能(néng)需要知道(dào)的是如何正确地加索引。而後(hòu)者可能(néng)著(zhe)重關注的是爲什麼(me)讀數據庫會(huì)慢,這(zhè)時(shí)候你可能(néng)需要額外重點介紹下數據庫相關的原理。
清晰的分類
文檔大緻可以分爲以下幾種(zhǒng)類型,每種(zhǒng)類型也有自己不同的特點和寫作側重點。
參考文檔
參考文檔也是大部分開(kāi)發(fā)人員日常會(huì)使用和書寫的文檔,比如我們使用某個框架或者工具,都(dōu)會(huì)有API說(shuō)明文檔,這(zhè)就(jiù)屬于參考類文檔。 它并沒(méi)有太多的要求,隻要能(néng)向(xiàng)讀者展示清楚如何使用即可,但無需向(xiàng)讀者講明具體的實現。
注:參考文檔并不僅限于API文檔,還(hái)包括文件注釋、類注釋、方法注釋,要求都(dōu)是能(néng)準确說(shuō)明其用法。
設計文檔
很多公司或者團隊在項目開(kāi)始前都(dōu)要求有設計文檔,設計是項目實施的第一步,所以在設計文檔書寫的過(guò)程中要求盡可能(néng)考慮周全,例如該項目的存儲、交互、隐私……
好(hǎo)的設計文檔應該包含以下幾個部分:
設計目标
實現的策略
各種(zhǒng)利弊權衡和具體決策
替代方案
各種(zhǒng)方案的優缺點
寫設計文檔的過(guò)程也你對(duì)整個項目做規劃、思考可能(néng)出現問題的過(guò)程,設計的越詳細、思考的越多,未來遇到問題的可能(néng)性就(jiù)會(huì)越小。
引導類文檔
引導類文檔也很常見,一般都(dōu)是Step by Step的形式。比如我們在使用某個框架或者工具的時(shí)候,一般都(dōu)會(huì)有個引導類的文檔一步一步幫助你快速上手。 大家寫引導類文章大家非常容易犯的一個錯誤就(jiù)是預設了很多背景知識。 一般使用文檔都(dōu)是有開(kāi)發(fā)者寫的,他們都(dōu)非常了解這(zhè)個工具的相關的知識,所以習慣性的會(huì)認爲,啊 這(zhè)個知識點很簡單 用戶也肯定會(huì)吧,實際上用戶不一定會(huì)。這(zhè)本質上就(jiù)是一種(zhǒng)認知偏差,這(zhè)種(zhǒng)現象在跨團隊協作 尤其是多端協作的時(shí)候也非常明顯。
這(zhè)類型的文檔寫作中,要求寫作者盡可能(néng)站在用戶的視角上思考,極力避免出現和用戶的認知偏差,力争每個步驟做到明确無歧義,每兩(liǎng)個步驟之間做到緊密銜接。
概念性文檔
當參考文檔無法解釋清楚某些東西的時(shí)候,就(jiù)需要概念性文檔了,比如某個API的具體實現原理。其主要是爲了擴充參考文檔,而不是替代參考文檔。有時(shí)候這(zhè)和參考文檔會(huì)有些内容重複,但主要還(hái)是爲了更深層次的說(shuō)明某些問題、解釋清楚某個概念。
概念性文檔也是所有文檔中寫作最難的,也是被(bèi)閱讀最少的,所以很多情況下工程師最容易忽視。而且還(hái)有另外一個問題,沒(méi)合适的地方放,參考文檔可以寫代碼裡(lǐ),落地頁可以寫項目主頁裡(lǐ),概念性文檔似乎也隻能(néng)在項目文檔裡(lǐ)找個不起(qǐ)眼的角落存放了。
這(zhè)類文檔的受衆會(huì)比較廣,專家和新手都(dōu)會(huì)去看。另外,它需要強調概念清晰明了,因此可能(néng)會(huì)犧牲完整性(可以由參考文檔補齊),也有可能(néng)會(huì)犧牲準确性,這(zhè)不是說(shuō)一定要犧牲準确性,隻是應當分清主次,不重要的就(jiù)沒(méi)必要說(shuō)了。
Landing pages(落地頁)
Landing pages就(jiù)先簡單翻譯成(chéng)落地頁了,沒(méi)想到啥恰當的翻譯詞。比如一個團隊或者項目的導航頁,雖然沒(méi)啥具體的内容,但應該包含其他頁面(miàn)的鏈接。 比如你新入職一個團隊,比較成(chéng)熟的團隊都(dōu)會(huì)扔給你一個文檔,這(zhè)個文檔裡(lǐ)包含常用的工具、文檔鏈接,這(zhè)就(jiù)是這(zhè)個團隊的落地頁。 落地頁的問題就(jiù)是随著(zhe)時(shí)間的推移,頁面(miàn)可能(néng)會(huì)變的越來越亂,而且有些内容會(huì)失效,不過(guò)這(zhè)些問題都(dōu)好(hǎo)解決,做好(hǎo)定期的維護和整理就(jiù)行。 落地頁的技術難度不高,但要求内容的有效性、完整性和分類清晰。
文檔Review
在一個組織内,光靠個人去維護文檔是不行的,必須得借助群體的智慧。在一個組織内部,文檔的變更也應該像代碼的變更一樣(yàng),需要被(bèi)其他人Review,以提前發(fā)現其中的問題并提升文檔的質量。
如何Review文檔:
專業的視角來保證準确性: 一般由團隊裡(lǐ)比較資深的人負責,他們關注的核心點是文檔寫的對(duì)不對(duì),專不專業。如果Code Review做的好(hǎo)的話,文檔的Review也屬于Code Review的一部分。
讀者視角保證簡潔性: 一般由不熟悉這(zhè)個領域的人來Review,比如團隊的新人,或者文檔的使用者。這(zhè)部分主要是關注文檔是否容易被(bèi)看懂。
寫作者視角保證一緻性: 由寫作經(jīng)驗豐富或者相關領域比較資深的人承擔,主要是爲了保證文檔前後(hòu)是否一緻,比如對(duì)同一個專業術語的使用和理解是否有歧義。
寫文檔的哲學(xué)
上面(miàn)部分站在組織和團隊的視角來看如何提高文檔質量,我們接下來看看站在個人寫作者的視角上如何寫出高質量的文檔。
5W法則
5W法則相信大家已經(jīng)聽的多了,分别是Who What When Where Why,這(zhè)是一個廣泛被(bèi)用在各行各業的法則,寫文檔當然也能(néng)用(5W法則堪稱萬金油,啥地方都(dōu)能(néng)用)。
WHO: 前面(miàn)已經(jīng)說(shuō)過(guò)了,文檔是寫給誰看的,讀者是誰。
WHAT: 明确這(zhè)篇文檔的用途,有時(shí)候,僅僅說(shuō)明文檔的用途和目的就(jiù)能(néng)幫你搭建起(qǐ)整個文檔的框架。
WHEN: 明确文檔的創建、Review和更新日期。因爲文檔也有時(shí)效性,明确相關日期可以避免閱讀者踩坑。
WHERE: 文檔應該放在哪! 建議一個組織或者團隊有統一的永久文檔存放地址,并且有版本控制。最好(hǎo)是方便查找、使用和分享。
WHY: 爲什麼(me)要寫這(zhè)篇文檔, 你期望讀者讀完後(hòu)從文檔中獲得什麼(me)!
三段式寫作
寫文章一般都(dōu)會(huì)有三個部分,專業寫作者也講究鳳頭、豬肚、豹尾,這(zhè)三個詞概括出了好(hǎo)文章三部分應有的特點。技術文檔也算是文章的一種(zhǒng),所以一般也都(dōu)會(huì)有這(zhè)三部分,每個部分有其自己的作用,比如第一部分闡述問題,中間部分介紹具體的解決方案,第三部分總結要點。 但這(zhè)也并不以爲著(zhe)文檔應該有三個部分,如果文檔内容比較多,可以將(jiāng)其做更細緻的拆解,可以适當增加一些冗餘的信息幫助讀者理解文檔内容。雖然很多工程師都(dōu)讨厭冗餘 極力追求簡潔,但寫文檔和寫代碼不同,适當的冗餘反而可以幫助讀者理解,很簡單,舉個例子,比如寫作中經(jīng)常舉例子,舉的例子本質上就(jiù)是冗餘信息,生動的例子肯定是能(néng)幫助讀者理解抽象内容的(我想這(zhè)就(jiù)是自舉 吧)。
結語
目前看到比較好(hǎo)的一個現象就(jiù)是大家越來越重視文檔了,但和測試相比 重視的程度還(hái)不夠。測試已經(jīng)是工作流程中不可或缺的一部分了,而文檔依舊還(hái)不是。當然這(zhè)可能(néng)和文檔本身的特性相關,測試很容易被(bèi)自動化,也有非常多的客觀指标來評估。文檔卻做不到,首先文檔的書寫需要人手動介入,而文檔的質量也沒(méi)有太多客觀的指标評估,提升文檔的數量和質量隻能(néng)從文化和工作流程上去逐漸改變。
最後(hòu)總結下本文幾個關鍵點:
随著(zhe)時(shí)間的推移和組織規模的壯大,文檔會(huì)越來越重要。
文檔也應該是開(kāi)發(fā)流程的一部分。
一篇文檔隻專注在一件事(shì)上。
文檔是寫給讀者看的,而不是給你自己看的。