設(shè)計(jì)模板解析:結(jié)構(gòu)化文檔如何驅(qū)動高效研發(fā))
簡介華為軟件詳細(xì)設(shè)計(jì)模板是一份源自華為研發(fā)流程的標(biāo)準(zhǔn)化文檔模板定位用于規(guī)范軟件詳細(xì)設(shè)計(jì)并直接指導(dǎo)編碼、測試與維護(hù)適合嵌入式、通信及企業(yè)級軟件研發(fā)團(tuán)隊(duì)和初次接觸詳細(xì)設(shè)計(jì)的工程師參考。模板不僅提供產(chǎn)品名稱、密級、版本、修訂記錄、目錄、圖表清單等文檔管理要素還圍繞目的、范圍、設(shè)計(jì)原則與約束、功能設(shè)計(jì)、數(shù)據(jù)設(shè)計(jì)、接口設(shè)計(jì)、性能設(shè)計(jì)、安全性設(shè)計(jì)、錯誤處理與異常設(shè)計(jì)、測試設(shè)計(jì)等研發(fā)關(guān)鍵環(huán)節(jié)搭建了完整章節(jié)框架且大多配有中英文對照說明能夠幫助讀者快速理解每個章節(jié)的編寫要求與填寫方式降低詳細(xì)設(shè)計(jì)文檔的編寫門檻。資源為單個doc文件壓縮包大小約89KB打開即可參考或二次修改為團(tuán)隊(duì)內(nèi)部模板。目前已有1071人學(xué)習(xí)下載適合作為軟件設(shè)計(jì)規(guī)范學(xué)習(xí)、研發(fā)流程培訓(xùn)或相關(guān)課程教學(xué)的輔助材料。1. 這份華為詳細(xì)設(shè)計(jì)模板值得每個研發(fā)團(tuán)隊(duì)抄一遍很多開發(fā)團(tuán)隊(duì)的設(shè)計(jì)文檔寫著寫著就變成“代碼粘貼板”或者“需求復(fù)述稿”。評審時(shí)大家翻一遍發(fā)現(xiàn)問題全靠運(yùn)氣。華為這份軟件詳細(xì)設(shè)計(jì)模板之所以值得拆解在于它把“設(shè)計(jì)文檔”這件事從自由寫作變成了結(jié)構(gòu)化表達(dá)什么位置寫什么內(nèi)容、字段怎么填、粒度到哪一層全都有明確約束。寫的人知道要交代什么評審的人知道往哪兒挑毛病后來接手的人也能按圖索驥。本文不討論這份模板怎么下載、怎么打開而是把它拆成一套可以直接落地的寫作規(guī)范適合正在建立設(shè)計(jì)流程的團(tuán)隊(duì)也適合剛轉(zhuǎn)崗做設(shè)計(jì)的開發(fā)者對照自查。2. 文檔骨架從文檔頭到縮略語清單每一頁都在消解溝通成本2.1 文檔頭與密級先回答“這份文檔能不能被帶走”模板第一頁有產(chǎn)品名稱、密級、產(chǎn)品版本還有擬制、評審、批準(zhǔn)三個簽名位。密級這里很多人直接復(fù)制模板里的“Low”實(shí)際上華為內(nèi)部對密級的定義會對應(yīng)到具體的信息安全策略Low通常指內(nèi)部公開Medium以上就要做訪問控制。簽名位對應(yīng)的是一條質(zhì)量管理鏈路擬制人對內(nèi)容負(fù)責(zé)評審人對技術(shù)方案負(fù)責(zé)批準(zhǔn)人對發(fā)布負(fù)責(zé)。最容易被跳過的是簽字日期格式寫的是“yyyy-mm-dd”這條在追溯文檔版本演進(jìn)時(shí)非常重要沒有日期的簽字等于沒有簽字。版本號建議和產(chǎn)品版本號體系保持一致不要單獨(dú)另起一套。2.2 修訂記錄比 Git 提交日志更早的變更追蹤手段修訂記錄表格里有日期、修訂版本、CRID/Defect ID、修改章節(jié)、修改描述、作者六列。CRID 是 Change Request ID 的縮寫Defect ID 是缺陷編號這列的作用是把文檔變更和研發(fā)管理系統(tǒng)里的具體訴求或缺陷關(guān)聯(lián)起來。沒有項(xiàng)目管理系統(tǒng)支撐的小團(tuán)隊(duì)也建議在修改描述里寫清楚“改了什么為什么改”。修訂版本從 1.1 起步不要用 v1.0、v1.1、V2.0 這種混雜的寫法建議統(tǒng)一為兩位數(shù)字語義第一位是大版本升級第二位是修訂累積。修改章節(jié)列直接寫“2.1.2/2.2”這種帶層級的編號比寫章節(jié)名更利于對照閱讀。2.3 目錄、表目錄與圖目錄讓百頁設(shè)計(jì)文檔可被快速翻閱模板里同時(shí)給出了 Catalog、Table List、Figure List 三套目錄看起來繁瑣但對大型模塊設(shè)計(jì)文檔來說必不可少。圖目錄和表目錄不是手工維護(hù)的靜態(tài)文字而是利用 Word 的“插入題注”功能生成的可更新域。具體做法是先給每張圖、每個表添加題注題注格式設(shè)為“圖 2-1 模塊結(jié)構(gòu)圖”“表 2-3 數(shù)據(jù)結(jié)構(gòu)定義”然后在文檔靠前位置插入“圖表目錄”域右鍵選擇“更新域”即可自動同步。純文字目錄則在大綱視圖下統(tǒng)一設(shè)置標(biāo)題級別再插入目錄域。手工手動改頁碼編號的做法在文檔超過 30 頁以后必然會出錯不推薦。2.4 關(guān)鍵詞、摘要與縮略語清單讓搜索引擎和外行都能讀懂關(guān)鍵詞字段看起來只是個供檢索用的標(biāo)簽但模板里要求 Abstract 對全文做精煉概括這恰恰是很多工程師最不愿意寫的一節(jié)。實(shí)際上摘要寫得好的設(shè)計(jì)文檔評審效率會高很多??s略語清單必須覆蓋全篇所有縮寫格式是三列表縮寫、英文全稱、中文解釋。比如“M2UA”這一項(xiàng)要寫全 MTP2 User Adaptation Layer中文解釋為“MTP2 用戶適配層”。這條規(guī)則的價(jià)值在多人協(xié)作場景中最明顯團(tuán)隊(duì)里不同人來自不同產(chǎn)品線對同一縮寫的理解可能完全不同。提示縮略語清單建議放在文檔開頭而不是文末附錄。讀者遇到看不懂的縮寫時(shí)不會翻到最后一頁去查。3. Introduction 與 Scope把設(shè)計(jì)邊界寫到?jīng)]有歧義3.1 Purpose一句“能直接指導(dǎo)編碼”的標(biāo)準(zhǔn)模板里對 Purpose 的要求是“詳細(xì)設(shè)計(jì)必須能夠直接指導(dǎo)編碼活動”這句話是整份 LLD 文檔的驗(yàn)收標(biāo)準(zhǔn)。寫 Purpose 時(shí)可以分兩層落筆第一層寫清楚這份文檔服務(wù)于哪個產(chǎn)品或模塊第二層注明讀者的預(yù)期能力比如“讀者應(yīng)具備 M3UA 協(xié)議基礎(chǔ)并熟悉 VOS 消息框架的調(diào)用方式”。這樣一來新加入項(xiàng)目的開發(fā)也能判斷這份文檔是否適合自己作為入門資料對于文檔管理者來說也更加清楚受眾在什么位置。3.2 Scope把“不做什么”寫入定義Scope 部分要求描述文檔“包括什么、不包括什么”這是詳細(xì)設(shè)計(jì)和概要設(shè)計(jì)最容易重疊的地方。HLD 管的是系統(tǒng)怎么拆模塊、模塊間怎么交互LLD 管的是一個模塊內(nèi)部的數(shù)據(jù)結(jié)構(gòu)和函數(shù)怎么實(shí)現(xiàn)。如果某個模塊在 HLD 里定義為“調(diào)用外部計(jì)費(fèi)接口”LLD 里就不需要寫計(jì)費(fèi)系統(tǒng)的內(nèi)部實(shí)現(xiàn)只需要在 Scope 里聲明“計(jì)費(fèi)相關(guān)邏輯不在本文檔范圍內(nèi)”。邊界切分的價(jià)值在多人并行開發(fā)時(shí)尤其明顯上下游模塊同時(shí)開工誰依賴誰、誰提供接口在 Scope 里先對齊才不會出現(xiàn)開發(fā)到一半才發(fā)現(xiàn)兩個模塊對接口定義各寫了一套的情況。3.3 設(shè)計(jì)約束與全局假設(shè)雖然模板正文里沒有單獨(dú)設(shè)“約束”章節(jié)但經(jīng)驗(yàn)上建議在 Introduction 末尾補(bǔ)一個“Assumptions and Constraints”子節(jié)。例如目標(biāo)硬件平臺的處理能力、協(xié)議棧內(nèi)存上限、必須兼容的歷史版本接口這類信息直接影響后續(xù)的數(shù)據(jù)結(jié)構(gòu)和函數(shù)設(shè)計(jì)。文檔里寫不下的要給出指向其他參考文檔的鏈接規(guī)則是每一條約束都能回溯其來源。這里的思路在代碼實(shí)現(xiàn)中的體現(xiàn)是不要讓設(shè)計(jì)文檔中出現(xiàn)無法驗(yàn)證的約束每一條都要能對應(yīng)到某個具體的硬件規(guī)格或協(xié)議規(guī)范。4. 詳細(xì)設(shè)計(jì)核心數(shù)據(jù)描述與函數(shù)描述的結(jié)構(gòu)化寫法4.1 數(shù)據(jù)描述從簡單數(shù)據(jù)到復(fù)合數(shù)據(jù)的分層模板把模塊數(shù)據(jù)分為簡單數(shù)據(jù)和復(fù)合數(shù)據(jù)兩類簡單數(shù)據(jù)包括模塊級全局變量、常量、宏復(fù)合數(shù)據(jù)包括結(jié)構(gòu)體、聯(lián)合體等。簡單數(shù)據(jù)的描述格式必須包含兩個字段功能描述和數(shù)據(jù)定義。功能描述說清楚這個數(shù)據(jù)“是用來干什么的”數(shù)據(jù)定義給出實(shí)際的聲明語句。如果全局變量的命名沒有統(tǒng)一前綴規(guī)范建議在數(shù)據(jù)定義里寫上清晰的命名解釋例如以“g_”前綴表示全局變量、以“M2UA_MAX_”前綴表示常量宏。這些細(xì)節(jié)在代碼規(guī)范不完善的團(tuán)隊(duì)里是設(shè)計(jì)文檔最直接的補(bǔ)充價(jià)值。復(fù)合數(shù)據(jù)的描述格式比簡單數(shù)據(jù)多一層必須包含數(shù)據(jù)結(jié)構(gòu)描述、數(shù)據(jù)結(jié)構(gòu)定義、數(shù)據(jù)項(xiàng)描述三部分。數(shù)據(jù)結(jié)構(gòu)描述交代用途數(shù)據(jù)結(jié)構(gòu)定義用實(shí)際編程語言寫出完整定義數(shù)據(jù)項(xiàng)描述用表格逐項(xiàng)列出每個字段。以下是一個參考格式#define M2UA_MAX_SSN_LEN 16 typedef struct { unsigned char ucDstSsn; /* MTP3 目的子系統(tǒng)號 */ unsigned char ucSrcSsn; /* MTP3 源子系統(tǒng)號 */ unsigned short usCic; /* 電路識別碼 Circuit Identification Code */ unsigned char aucData[M2UA_MAX_SSN_LEN]; /* 用戶數(shù)據(jù)緩沖區(qū) */ } m2ua_data_t;數(shù)據(jù)項(xiàng)描述對應(yīng)填入表格包含字段名、字段類型、字段定義。數(shù)據(jù)項(xiàng)定義要說明取值范圍和默認(rèn)值比如“ucDstSsn 范圍 0x00-0xFF默認(rèn)值為 0x0A”。對于枚舉字段可以用表格列出枚舉名和值。這里描述的目的在于讓編碼人員在寫代碼前就對數(shù)據(jù)的生命周期有完整認(rèn)識而不是一邊寫一邊設(shè)計(jì)。4.2 函數(shù)描述八個字段加一個實(shí)現(xiàn)段模板中函數(shù)描述的標(biāo)準(zhǔn)格式是八個字段加一個實(shí)現(xiàn)段覆蓋了“別人怎么用我、我怎么用別人、我改了什么、我返回什么”的全部信息。這八個字段逐一對應(yīng)Function 函數(shù)名、Description 函數(shù)功能與性能描述、Calls 被本函數(shù)調(diào)用的函數(shù)清單、Data Accessed 被訪問的全局變量與數(shù)據(jù)庫表、Data Updated 被修改的全局變量與數(shù)據(jù)庫表、Input 輸入?yún)?shù)說明、Output 輸出參數(shù)說明、Return 返回值說明。寫函數(shù)設(shè)計(jì)時(shí)最容易被忽略的是 Calls 和 Data Accessed / Data Updated 兩個字段它們記錄了函數(shù)的外部依賴和副作用也是編碼與代碼 review 時(shí)最需要關(guān)心的部分。函數(shù)調(diào)用關(guān)系的部分用層次圖或結(jié)構(gòu)圖來描述比較直觀。以下是一個完整的函數(shù)描述示例/* * Function: m2ua_nif_sendto_mtp2 * Description: 向 MTP2 模塊發(fā)送 M2UA 消息包 * Calls: VOS_AllocMsg, Dev_FromVspCardNoGetCpuid, VOS_FreeMsg, VOS_SendMsg * Data Accessed: 設(shè)備信息表消息發(fā)送相關(guān)全局計(jì)數(shù) * Data Updated: 消息發(fā)送計(jì)數(shù)字段 * Input: ucLinkNo 鏈路號取值 0x00-0x1FpMsg 消息緩沖區(qū)指針 * Output: 無 * Return: M2UA_SUCCESS 或 M2UA_FAILURE * Others: 該函數(shù)復(fù)用 MTP3 模塊向 MTP2 發(fā)消息的既有通路 */ m2ua_return_t m2ua_nif_sendto_mtp2(unsigned char ucLinkNo, m2ua_msg_t *pMsg) { /* 參數(shù)合法性檢查 */ if (ucLinkNo M2UA_MAX_LINK_NO) { return M2UA_FAILURE; } if (pMsg NULL) { return M2UA_FAILURE; } /* 申請消息包空間 */ void *pMsgBuf VOS_AllocMsg(sizeof(m2ua_msg_t)); if (pMsgBuf NULL) { return M2UA_FAILURE; } /* 填寫目標(biāo) CPU 信息 */ if (Dev_FromVspCardNoGetCpuid(ucLinkNo, pMsg-usDstCpuid) ! OK) { VOS_FreeMsg(pMsgBuf); return M2UA_FAILURE; } pMsg-ucDstModuleId M2UA_MODULE_ID_MTP2; pMsg-usMsgLen sizeof(m2ua_msg_t); /* 發(fā)送消息 */ VOS_SendMsg(M2UA_MODULE_ID_MTP2, pMsgBuf); return M2UA_SUCCESS; }這是一段典型的模板化實(shí)現(xiàn)設(shè)計(jì)文檔里給出的實(shí)現(xiàn)段用偽碼或流程圖展開。偽碼不用寫到每行代碼但要能體現(xiàn)完整的錯誤處理路徑。以上面這個 m2ua_nif_sendto_mtp2 為例偽碼至少應(yīng)該包含參數(shù)合法性檢查、消息包申請、失敗回滾路徑、消息內(nèi)容填充、最終發(fā)送。這里的重點(diǎn)是培養(yǎng)設(shè)計(jì)人員對資源管理的全局意識確保任何一條失敗路徑都不會造成內(nèi)存泄漏或狀態(tài)殘留。接口錯誤的處理方式也在這里一并體現(xiàn)失敗的 return 值是否定義了對應(yīng)的錯誤碼。協(xié)議棧類模塊通常還要在 Others 字段里補(bǔ)充并發(fā)調(diào)用注意事項(xiàng)比如“該函數(shù)可能被多個任務(wù)同時(shí)調(diào)用調(diào)用方需保證消息包生命周期有效”。5. 錯誤處理系統(tǒng)錯誤、接口錯誤、協(xié)議錯誤的三層劃分5.1 系統(tǒng)錯誤與接口錯誤的處理策略模板把錯誤處理拆成系統(tǒng)錯誤、接口錯誤、協(xié)議錯誤三類。系統(tǒng)錯誤指內(nèi)存分配失敗、任務(wù)創(chuàng)建失敗、信號量超時(shí)這類資源性故障接口錯誤指模塊對外輸出的錯誤碼協(xié)議錯誤指協(xié)議規(guī)范里沒有明確規(guī)定的情況。這三個層次的劃分在代碼實(shí)現(xiàn)上有直接映射系統(tǒng)錯誤一般用返回值配合 errno 或錯誤日志接口錯誤用模塊自定義的錯誤碼枚舉協(xié)議錯誤則需要定義專門的告警和恢復(fù)機(jī)制。比如 M2UA 模塊收到未知消息類型時(shí)模板建議在“協(xié)議錯誤”一節(jié)描述處理策略是丟棄消息、回送錯誤通知還是直接斷鏈。5.2 錯誤碼定義規(guī)范與可追溯性新定義接口錯誤碼時(shí)需要列出錯誤碼與錯誤原因。錯誤碼的命名要有統(tǒng)一規(guī)則模塊縮寫加場景加錯誤語義。例如錯誤碼含義觸發(fā)場景M2UA_E_LINK_INVALID鏈路號不合法ucLinkNo 超過最大鏈路號M2UA_E_MSG_ALLOC_FAIL消息申請失敗VOS_AllocMsg 返回 NULLM2UA_E_CPUID_GET_FAILCPU 信息獲取失敗Dev_FromVspCardNoGetCpuid 調(diào)用失敗M2UA_E_PARAM_NULL參數(shù)為空pMsg 指針為 NULL錯誤碼需要和日志系統(tǒng)配合每個錯誤碼的出現(xiàn)位置、記錄方式都要在設(shè)計(jì)階段定好而不是等測試發(fā)現(xiàn)后再補(bǔ)。系統(tǒng)錯誤的處理策略一般遵循“誰申請誰釋放”的原則局部資源申請失敗時(shí)清理已占用資源再返回任務(wù)創(chuàng)建失敗這種進(jìn)程級錯誤則需要考慮是否觸發(fā)主控復(fù)位或降級運(yùn)行。資料引用格式遵循常見的三種情況英文文章中作者、篇名、期刊、卷號、年份、頁碼英文書籍中作者、書名、出版社、年份中文文獻(xiàn)中作者、篇名、期刊、卷號、年份。版本較新的資料可以補(bǔ)充“訪問日期”涉及內(nèi)部文檔時(shí)引用編號和發(fā)布日期即可。對于工程團(tuán)隊(duì)參考資料清單的價(jià)值不止是學(xué)術(shù)規(guī)范更是在后續(xù)文檔追溯時(shí)快速判斷哪些設(shè)計(jì)決策來自哪些依據(jù)避免技術(shù)演進(jìn)過程中因?yàn)橐胄路桨付鴣G失決策上下文。注意模板中明確標(biāo)注了“文檔內(nèi)容僅供參考”這一點(diǎn)在對外輸出設(shè)計(jì)方案時(shí)能起到免責(zé)作用內(nèi)部使用時(shí)則要求設(shè)計(jì)者對內(nèi)容真實(shí)性負(fù)責(zé)。從數(shù)據(jù)描述的結(jié)構(gòu)化到錯誤碼定義規(guī)范整套模板的核心價(jià)值在于把設(shè)計(jì)經(jīng)驗(yàn)沉淀成團(tuán)隊(duì)共識。真正用得好的團(tuán)隊(duì)會把模板中的章節(jié)按照自身項(xiàng)目情況裁剪并固化到公司文檔系統(tǒng)里讓所有新項(xiàng)目一開張就沿用同一套表達(dá)語言。文檔模板本身并不產(chǎn)生設(shè)計(jì)質(zhì)量但它讓優(yōu)秀的設(shè)計(jì)實(shí)踐有了可復(fù)制的載體。本文還有配套的精品資源點(diǎn)擊獲取