本文首發(fā)于 vivo互聯(lián)網(wǎng)技術(shù) 微信公眾號(hào)
創(chuàng)新互聯(lián)公司主要從事成都網(wǎng)站設(shè)計(jì)、做網(wǎng)站、成都外貿(mào)網(wǎng)站建設(shè)公司、網(wǎng)頁(yè)設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)禹州,十余年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):13518219792
鏈接: https://mp.weixin.qq.com/s/VWjB83NBTg6FwPBDg8G0HQ
作者:Shi Zhengxing
本文對(duì)自己工作中碰到的大量日常咨詢進(jìn)行經(jīng)驗(yàn)總結(jié),說明一款開發(fā)框架文檔應(yīng)該要寫哪些內(nèi)容。從 功能框架、 特性使用流程、 功能描述三個(gè)維度說明文檔編寫的邏輯性。希望能給同樣從事開發(fā)框架的開發(fā)與維護(hù)的同行帶來一點(diǎn)啟發(fā)。
曾經(jīng)有一段較為短暫的時(shí)間,接手了超過10個(gè)開發(fā)框架的日常維護(hù),其中大部分還是處于活躍的開發(fā)迭代狀態(tài)。平均下來,那段時(shí)間可能每周都有那么一天會(huì)被內(nèi)部即時(shí)通訊軟件不停打斷以至于無法進(jìn)入既定的工作任務(wù)中去,一旦碰到三兩個(gè)非常棘手,排查起來非常耗時(shí)的支持或者問題時(shí),那一周的產(chǎn)出就會(huì)比較低了。
有人會(huì)說,你不能集中去回答用戶的咨詢嗎?答案是最好不要,因?yàn)槲覀儼延脩魸M意度放在很重要的位置,回復(fù)的及時(shí)性無疑對(duì)用戶滿意度有重要影響。
經(jīng)過對(duì)問題的總結(jié)歸類:
(1)第一類約占40%的日常支持,是關(guān)于在某個(gè)特定的場(chǎng)景下如何使用這個(gè)開發(fā)框架(因?yàn)榻邮志S護(hù)時(shí)用戶使用文檔結(jié)構(gòu)混亂,難以在文檔中快速找到想要的內(nèi)容,或者根本就沒有這部分內(nèi)容,用戶只能電話咨詢或者面詢);
(2)第二類約占30%的是使用過程中出現(xiàn)了預(yù)期外的狀況,需要幫助定位排查問題;
在多次的思考與總結(jié)后,我認(rèn)為這里面有很大的優(yōu)化空間,按照我的想法對(duì)文檔進(jìn)行優(yōu)化落地后,預(yù)估每周能為我節(jié)省出接近1天的時(shí)間,接下來我將介紹我的想法及實(shí)踐經(jīng)驗(yàn)。
下面我分別給出理想狀態(tài)(下圖左)與現(xiàn)實(shí)狀態(tài)(下圖右)下,文檔、框架開發(fā)者、框架使用者之間的關(guān)系。
(圖一)
從圖中可以看出,理想狀態(tài)下,開發(fā)者只需通過文檔向使用者傳遞信息,實(shí)際上很多開源框架在使用的時(shí)候也是如此,雖然使用者還是具備與開發(fā)者溝通的渠道(例如郵件或者github的issue),但是那是低頻的。現(xiàn)實(shí)情況下,大公司內(nèi)部的基礎(chǔ)開發(fā)框架不僅要編寫文檔,還需要不停與內(nèi)部使用者進(jìn)行多種類多渠道的溝通。
為了能讓大家大致理解這是什么樣的溝通,以及我面臨的文檔方面的問題,這里我將過往真實(shí)案例,稍作修飾——以期達(dá)到較少的案例抽象出較多的問題——陳述如下。
一個(gè)老員工希望使用熔斷框架保護(hù)自己的系統(tǒng),通過自己保存的我們團(tuán)隊(duì)的wiki主頁(yè)鏈接找到了熔斷框架的文檔鏈接,花了15分鐘認(rèn)真仔細(xì)看完全部文檔后,不太確定為啥要用我們團(tuán)隊(duì)提供的熔斷框架,而不直接用開源的,他沒有多想,直接按照文檔描述寫了個(gè)demo,最終跑起來了;
接著準(zhǔn)備正式應(yīng)用在業(yè)務(wù)代碼上,他從文檔上了解到可能需要根據(jù)自己業(yè)務(wù)情況調(diào)整一些初始化參數(shù),但是因?yàn)閰?shù)說明很簡(jiǎn)單,以前也沒有使用過熔斷框架,加上領(lǐng)域知識(shí)專業(yè)性較強(qiáng),看了基本不理解具體能達(dá)到什么效果,就準(zhǔn)備打電話過來咨詢下,于是他看到文檔的創(chuàng)建人和最近修改人不是同一個(gè)人,猶豫了一下,他給最近修改人打了電話。
一個(gè)南京的有多年java開發(fā)經(jīng)驗(yàn)的同學(xué),接手了一個(gè)有較大數(shù)據(jù)量的開發(fā)任務(wù);由于前面參加了vivo內(nèi)部基于spirng boot的腳手架(下文簡(jiǎn)稱腳手架)培訓(xùn)分享,從ppt里找到我們的項(xiàng)目網(wǎng)站,并下載了工程,嘗試性的從wiki上搜索,找到了我們的文檔“使用腳手架快速集成vivo-mybatis”,看完文檔后還是不確定他的分庫(kù)分表之單庫(kù)多表場(chǎng)景是否支持,于是他打電話過來咨詢;咨詢完確認(rèn)支持并了解單庫(kù)多表與多庫(kù)多表的配置差異后,他在mybatis的配置文件中加上了分庫(kù)分表的插件,但是文檔沒有介紹分庫(kù)分表的原理,也沒有單庫(kù)多表的配置示例,試了好幾次都不行,最后他反編譯后看了框架部分源碼后明確了配置方式,問題都解決了,但是花費(fèi)了較大精力。
一個(gè)同事在wiki上搜索到了2個(gè)關(guān)于spring boot工程接入vivo配置中心的文檔,是由不同的人編輯維護(hù)的,不知道該以哪個(gè)文檔為準(zhǔn),于是打電話其中一個(gè)人反饋了這個(gè)情況。后面兩個(gè)文檔的編寫者驗(yàn)證情況屬實(shí),需要合并,但是難以決定合并后的文檔放到配置中心用戶文檔目錄下還是放到腳手架用戶文檔目錄下。
問題1:文檔入口需要口口相傳;如果沒有保存這個(gè)鏈接信息,那就要從其他同事那里詢問。
問題2:文檔內(nèi)容存在缺漏,用戶短時(shí)間就可以看完所有的文檔,并且沒有按照功能特性進(jìn)行分類,需要看全部文檔。
問題3:沒有做競(jìng)品分析,沒有明確介紹內(nèi)部框架與開源同類框架到底有什么差異。
問題4:框架配置參數(shù)說明過于簡(jiǎn)單,沒有相應(yīng)的領(lǐng)域知識(shí)介紹,用戶看不明白或者不理解。
問題5:維護(hù)的基于開源的基礎(chǔ)框架,沒有根據(jù)公司開發(fā)環(huán)境進(jìn)行定制優(yōu)化,需要調(diào)整參數(shù)后才能使用上線。
問題6:框架當(dāng)前的owner從用戶角度來說不清晰。
問題1:項(xiàng)目網(wǎng)站地址要人為單獨(dú)記憶,宣傳難度極大。
問題2:框架文檔沒有做到能輕易獲取,需要用戶嘗試不確定性搜索。
問題3:用戶需要打電話詢問是否支持他的場(chǎng)景,說明這個(gè)文檔沒有準(zhǔn)確描述支持哪些場(chǎng)景,有遺漏,也沒有把相關(guān)場(chǎng)景下的demo示例給出來。
問題4:框架在打包的時(shí)候,沒有打源碼包。
問題5:文檔缺乏對(duì)實(shí)現(xiàn)原理的介紹。
問題1:多個(gè)文檔說一件事情,說明文檔存在混亂的情況。
問題2:文檔歸屬到哪個(gè)模塊難以達(dá)成一致,說明沒有站在用戶角度去劃歸職責(zé)。
本文到現(xiàn)在為止,描述的關(guān)于文檔的問題以及這些問題出現(xiàn)在什么場(chǎng)景下,已經(jīng)清晰的浮現(xiàn)于眼前了。但是我們?cè)趯懳臋n之前,得先有一個(gè)判斷標(biāo)準(zhǔn),怎樣的文檔才算是好的文檔呢?我認(rèn)為答案很簡(jiǎn)單,就是只要能減少使用者與開發(fā)者間的溝通,只要能提升溝通效率,無限靠近圖一中所示的理想狀態(tài),那么這個(gè)框架的用戶文檔就算是好的文檔。所以你看,文檔也是用來解決某個(gè)問題的,它可以被視作一款獨(dú)立的產(chǎn)品。文檔該寫什么,也就是這個(gè)產(chǎn)品應(yīng)該有什么功能。
接下來我們對(duì)文檔這款產(chǎn)品進(jìn)行產(chǎn)品關(guān)鍵特性分析:
根據(jù)自己的過往經(jīng)驗(yàn),結(jié)合上述產(chǎn)品關(guān)鍵特性分析,我認(rèn)為完整的框架文檔應(yīng)當(dāng)包含以下分類的內(nèi)容。
因?yàn)椴煌蚣艿奈臋n各個(gè)部分的重要性會(huì)有所差異,因此以上分類的描述篇幅、呈現(xiàn)方式、內(nèi)容載體,會(huì)有很大差異,下圖是我們團(tuán)隊(duì)開發(fā)的分布式鎖框架基于wiki呈現(xiàn)方式的文檔目錄。前面的序號(hào)是為了方便與用戶基于文檔的溝通(與用戶的直接溝通是難以避免的)。
(圖二)
看完上面示例圖后,理解會(huì)稍微直觀點(diǎn),接下來我將上面的6種較為抽象的分類,細(xì)化成具體的wiki的功能頁(yè)面,當(dāng)然這只是示例性的:
(1)框架首頁(yè):對(duì)當(dāng)前框架進(jìn)行概述性描述,比如宣傳標(biāo)語(yǔ),具備的功能特性,能解決什么問題,使用場(chǎng)景;下一步引導(dǎo),社區(qū)引導(dǎo);如果是基于開源版本開發(fā),也可以在此介紹在開源版本基礎(chǔ)上做了什么;如果不是,最好能類比下開源同類產(chǎn)品(競(jìng)品分析);還可以有核心指標(biāo),用以展示競(jìng)爭(zhēng)力和受歡迎程度,提升用戶的使用信心。
(2)領(lǐng)域知識(shí):目標(biāo)為讓用戶的相關(guān)知識(shí)水平與你貼近,讓用戶理解你的行為與做法,提升用戶認(rèn)可度或者滿意度。
(3)快速開始:只有最小依賴下的簡(jiǎn)單場(chǎng)景的快速接入及使用描述,用戶拷貝上面的代碼即可直接運(yùn)行,同時(shí)描述如何獲得它。此處也應(yīng)該給出示例的demo獲取方式。
(4)依賴與限制:描述當(dāng)前框架運(yùn)行的依賴項(xiàng),包含運(yùn)行環(huán)境依賴,maven必須依賴與選擇依賴列表(例如dubbo使用zookeeper與使用nacos作為注冊(cè)中心的依賴項(xiàng)有差異),依賴的中間件或者業(yè)務(wù)系統(tǒng);限制信息比如不能使用fastjson作為json工具,必須使用cluster模式的redis集群等。
(5)配置項(xiàng):詳細(xì)描述每一個(gè)配置的使用方法,起到什么作用,注意事項(xiàng),配置key最好有一定設(shè)計(jì)邏輯,方便理解。
(6)詳細(xì)使用說明:綜合性的用戶文檔,針對(duì)所有的能力特性如何使用,進(jìn)行描述說明,需要說明全部細(xì)節(jié)。
(7)多場(chǎng)景使用示例:從用戶各種不同的使用場(chǎng)景出發(fā),給出配置/示例代碼,同時(shí)給出下載導(dǎo)入IDE即可運(yùn)行的demo,方便不同需求的用戶來閱讀。
(8)版本發(fā)布記錄:用于追溯、記錄版本的發(fā)布時(shí)間、變動(dòng)內(nèi)容。
(9)升級(jí)指導(dǎo):用于指導(dǎo)用戶如何升級(jí)版本。
(10)設(shè)計(jì)及原理:包含各種類型的設(shè)計(jì)文檔、原理說明、源碼導(dǎo)讀。幫助深度用戶了解運(yùn)行原理,為源碼閱讀提供一定的指導(dǎo);也需要說明設(shè)計(jì)時(shí)遵循了什么規(guī)范,幫助用戶識(shí)別底層特性。
(11)質(zhì)量信息:功能測(cè)試報(bào)告、性能測(cè)試報(bào)告、漏洞掃描報(bào)告、遵循的標(biāo)準(zhǔn)化規(guī)范。
(12)FAQ:可以在此頁(yè)面歸納整理較為典型的/常見的用戶疑問,方便其他有類似疑問的同事看(類似最佳實(shí)踐),減少溝通工作量。需要注意的是,此處只是臨時(shí)性的公共問題導(dǎo)引地址,從長(zhǎng)遠(yuǎn)看,用戶常問的問題需要從系統(tǒng)設(shè)計(jì)層面進(jìn)行優(yōu)化,或者要在詳細(xì)使用說明處進(jìn)行顯著提示。
文檔的閱讀者一般是程序員,程序員的思維邏輯性較強(qiáng),因此我們寫出來的文檔具備較強(qiáng)的邏輯性是基礎(chǔ)要求,以下從三個(gè)維度來描述文檔的邏輯性。
文檔的整體邏輯建議依據(jù)上面的6個(gè)分類內(nèi)容進(jìn)行“總-分-總”式編寫。首先要對(duì)框架進(jìn)行整體介紹,這個(gè)可以放到框架首頁(yè),接著明確要輸出文檔的類別(按照框架的不同可以選擇性的寫對(duì)應(yīng)類別的文檔,當(dāng)然不是一定要輸出全部6個(gè)類別的文檔)及對(duì)框架功能特性進(jìn)行枚舉,這是一個(gè)“總-分”的過程。接著可以將單個(gè)類別的文檔或者單個(gè)特性的說明文檔作為獨(dú)立的模塊,進(jìn)行詳細(xì)說明。另外,用戶查看頻率較高的部分,也應(yīng)該添加菜單單獨(dú)編寫,方便用戶快讀查找瀏覽。我們看下分布式鎖框架文檔的主頁(yè):
(圖三)
單個(gè)類別的文檔在編寫的時(shí)候,也需要視具體內(nèi)容的復(fù)雜度,多次進(jìn)行“總-分”形式的拆分。多次拆分后一般需要再次“總”的過程,來組合成一個(gè)完整的功能特性。
在圖二分布式鎖框架的文檔目錄中,從功能框架邏輯上來說,“依賴與限制”內(nèi)容雖然也會(huì)比較少,但是一般在使用一個(gè)框架的時(shí)候是必看的內(nèi)容,因此這里將其作為獨(dú)立的模塊。“快速開始”顧名思義就是引導(dǎo)用戶快速了解框架,非常重要,注意要以最簡(jiǎn)潔的話語(yǔ)、最簡(jiǎn)的配置、最少的代碼、最少的依賴,以最小的篇幅來進(jìn)行說明,目標(biāo)是2分鐘內(nèi)能看懂。“配置手冊(cè)”當(dāng)然是羅列的全部的框架配置相關(guān),包含功能、性能的調(diào)節(jié)參數(shù),還要注意將常用配置與不常用的分開,總之一個(gè)原則,保持全面完整但是也要按使用頻次歸類。“詳細(xì)說明”主要從用戶接入、使用、調(diào)優(yōu)、注意事項(xiàng)等角度,對(duì)框架進(jìn)行全方位的說明,一般會(huì)占有大的篇幅。“多場(chǎng)景demo示例”建議枚舉用戶所有的使用場(chǎng)景,針對(duì)場(chǎng)景提供示例代碼。“版本與升級(jí)”其實(shí)就是發(fā)布與變更日志,版本兼容性說明,相應(yīng)的用戶的升級(jí)注意事項(xiàng)。
如下為我們團(tuán)隊(duì)開發(fā)的分布式鎖框架”詳細(xì)說明“頁(yè)面的目錄:
(圖四)
功能流程邏輯可以理解為一個(gè)功能使用時(shí)的多個(gè)具體步驟的串聯(lián)。例如使用分布式鎖框架的典型步驟如下:
通過maven依賴分布式鎖框架jar包->配置zookeeper或者redis的地址->編碼(獲取鎖)->編碼(釋放鎖)
這個(gè)過程這么寫大家會(huì)不會(huì)覺得就很明白也很不明白?雖然整體流程是很簡(jiǎn)單,但是文檔絕不可以只是寫這些內(nèi)容,否則會(huì)給開發(fā)者帶來無盡的用戶溝通。例如文檔還應(yīng)當(dāng)包含:指明某個(gè)功能最低版本(依賴什么版本的包合適),spring環(huán)境、spring boot環(huán)境、純java環(huán)境如何依賴,依賴的三方包沖突范圍及排查方法,zookeeper配置參數(shù)以及集群可用性與框架穩(wěn)定性說明,zookeeper連接管理說明,鎖獲取與釋放過程可重入性說明,異常處理指導(dǎo),最佳實(shí)踐等等,這還是API最基本的使用方式,換做是注解的使用方式,需要說明的細(xì)節(jié)就更多了。至于應(yīng)該寫清楚哪些細(xì)節(jié),可以是逐漸完善的,文檔也是需要不斷迭代更新的。
為了用戶好閱讀,建議以流程圖的形式,分使用場(chǎng)景逐個(gè)進(jìn)行說明。每個(gè)步驟要將相關(guān)的細(xì)節(jié)說清楚,避免用戶使用過程的電話溝通確認(rèn)。
在進(jìn)行框架原理或者源碼的描述時(shí),時(shí)常涉及到狀態(tài)變化描述、生命周期描述等等,顯然使用常規(guī)流程圖不足以表達(dá)清晰,此時(shí)換做狀態(tài)轉(zhuǎn)化圖、時(shí)序圖、加上了泳道的流程圖,效果會(huì)更好。我們看下TCP連接生命周期狀態(tài)轉(zhuǎn)化圖:
(圖五)
在功能流程邏輯中有寫到,流程中的每一個(gè)步驟,都要寫清楚相應(yīng)的細(xì)節(jié),通過文檔的不斷更新迭代來完善。這里如何把這些細(xì)節(jié)有條理、完整的描述清楚,需要注意以下幾點(diǎn):
最后,要意識(shí)到每個(gè)人的思維方式、邏輯習(xí)慣是有差異的,無論花多少心思去寫文檔,都難以做到十全十美不遺漏無疏忽,因此還需要一個(gè)用戶反饋的渠道,例如大多數(shù)文檔系統(tǒng)都有評(píng)論功能。下圖是文檔聯(lián)系起使用者與開發(fā)者后的成熟態(tài)。
(圖六)
文檔編寫的基本目的,是幫助使用者來使用框架,但是不能忽略的是,框架的開發(fā)者也是文檔的重要用戶,文檔在方便用戶的同時(shí),也要方便自己。
本文從日常咨詢存在的問題引發(fā)出思考,聯(lián)想到文檔也是一個(gè)產(chǎn)品,用來解決特定人群的問題。因?yàn)椴欢a(chǎn)品,不能從產(chǎn)品的專業(yè)角度對(duì)文檔進(jìn)行解構(gòu),只能根據(jù)自己經(jīng)驗(yàn)說明文檔應(yīng)該要寫哪些內(nèi)容,從功能框架、特性使用流程、功能描述時(shí)注意事項(xiàng)等說明了文檔編寫的邏輯性。希望對(duì)同樣從事開發(fā)框架的開發(fā)與維護(hù)的同行一點(diǎn)啟發(fā)。
作為框架的開發(fā)者,用戶的肯定與點(diǎn)贊是我們最好的回報(bào)。我們會(huì)注重編碼質(zhì)量,但是往往忽略文檔的重要性,框架很牛逼但是文檔寫得很爛,用戶用起來不順暢,會(huì)讓框架的價(jià)值大打折扣。意識(shí)到這一點(diǎn)很重要,寫出牛逼的代碼,文檔也寫得清晰易讀,用戶才會(huì)覺得框架牛逼,順帶才會(huì)認(rèn)為作者牛逼。牛逼的事情做多了,你的技術(shù)影響力自然就上來了。