設計文檔是軟件工程設計中的重要組成部分,是對一個技術問題的解決方案的系統性描述。設計文檔的目的,是闡明設計的總體思想和設計中考慮的權衡點。
作為一名軟件工程師,我們的工作本質不僅僅是編寫程序代碼,而是解決真正的問題。因此,相比最終的程序代碼,文字形式的設計文檔,在早期能夠更加簡明扼要地傳達信息,便于讓讀者理解問題,找到解決方案。
除了作為系統設計的最初體現,設計文檔在軟件工程的開發周期中起到下面重要作用:
通過設計文檔,我們可以:
本身撰寫設計文檔是需要編寫成本的。如果問題的解決方案非常清晰,沒有明确的取舍,設計文檔中基本都是實現描述,則應該省略設計文檔而直接實現。換言之,如果編寫設計文檔的時間主要消耗在“寫”而不是在“思考”上,則這個設計文檔可省略。當你考慮編寫一個設計文檔時,想一想以下這幾點:
如果以上的問題的答案為“是”,那麼設計文檔可能是開始你的下一個軟件項目的絕佳方法。
3、設計文檔要怎麼寫?在考慮通過用設計文檔解決問題,開始着手準備設計文檔前,需要厘清設計文檔易混淆的三個概念,它們也是創作設計文檔的根基。一旦出現偏差,我們認真撰寫的文檔很有可能完全不可用,在糾正偏差時也會出現大量工作返工,造成資源的浪費。所以,撰寫設計文檔前需要搞清楚這些前提。
3.1 撰寫設計文檔的三個前提在搞清楚設計文檔撰寫的三個前提後,就會進入文檔的編寫階段。設計文檔是非正式的文檔,因此他們的内容不會遵循嚴格的準則,一個首要原則是,針對項目的具體情況可以用相對合理的方式來編寫。盡管如此,筆者也參考文獻并結合自身經驗給出一些建議。
寫作風格的三要素設計文檔的寫作也是技術寫作(Technical Writing),因此同樣強調以下三要素:
系統設計及編寫設計文檔時需要注意的 5 個要點。
1. 任何架構問題都是取舍。在軟件設計中,沒有任何一個維度有絕對意義上的優劣。每一個設計決定都需要考量很多相違背的因素。例如,可擴展性和效率相背;長期效率和短期收益相背;規模化提升了效率,但降低了靈活性。“高内聚低耦合” 便于叠代,但是會增加短期的開發成本。NoSQL 比 SQL 性能高,但代價是功能的大幅降低。如果一個設計決策看上去沒有任何的取舍,往往是因為取舍還沒有被識别。在設計時應從取舍視角切入,尋找不同需求間的平衡。
2. “為什麼” 比 “怎麼做” 更重要。設計所解決的問題往往是複雜而模糊的,因此,解決方案往往是不唯一的。對工程設計,方案的論證通常比方案本身更重要。
3. 考慮時間維度做設計取舍時不能忽略時間維度,隻設計某個階段的終态。設計需要考慮以下方面:
設計伊始,界定問題的範圍。
一個良好界定的問題是一個良好設計的必要條件。不要迷信設計模型、設計模式、XX 驅動設計。這些是工具,而非法則。不要為了制造問題而解決問題。不要通過複雜的設計來體現工作的難度和深度: 一個困難的問題可能會有一個簡單的答案。也不要過于擔憂設計被迅速淘汰。保留可擴展性,但不要在未知時浪費精力擴展。
【文章福利】另外小編還整理了一些C/C 後台開發教學視頻,相關面試題,後台學習路線圖免費分享,需要的可以自行添加:點擊 正在跳轉 加入~群文件共享小編強力推薦C 後台開發免費學習地址:C/C Linux服務器開發/後台架構師【零聲教育】-學習視頻教程-騰訊課堂
最重要的是要知道如何設計,知道自己在設計什麼。列甯·克魯格效應告訴我們,這未必顯然。
I think test-driven design is GREat. I do that a lot more than I used to do. But you can test all you want and if you don’t know how to approach the problem, you’re not going to get a solution. ——Coders at Work, Peter Norvig
3.2 設計文檔的核心原則前提一:設計文檔的讀寫比最高實現代碼、系統接口、設計文檔,讀寫比(内容被所有人閱讀花費的時間:内容寫作花費的時間)是逐步上升的。通常,設計文檔供閱讀讀的時間往往遠多于寫的時間。因此,編寫設計文檔時就更多考慮讀者的體驗而非作者的體驗。為提升設計可讀性的時間非常值得投資。
前提二:設計文檔不是文學寫作設計文檔的目的是為了溝通設計,而不是為了自我表達。把精力放在如何清晰、簡潔地表達,而非放在文采上
前提三:設計文檔為誰而寫首先先了解你的讀者是誰?在良好的文檔分享文化下,讀者不應該隻是你的 TL 以及該設計文檔的實施者,你的設計文檔實際讀者的範圍往往大得多。在不确定的時候,經驗做法是,假設的讀者群體為:公司内部的、有一定工程經驗的、但對該系統的上下文隻有初步了解的軟件工程師。通常,設計文檔的範圍越大,假定的受衆群也會更大。這意味着受衆對目标系統的平均了解程度更低,也就意味着設計文檔往往需要:
其次,考慮讀者喜歡如何閱讀?大部分讀者不會逐字逐句閱讀你的設計文檔。大家都很忙。讀者通常隻會掃描大體結構,然後閱讀(或者跳讀)自己感興趣的部分。讀者喜歡“故事”。将内容以故事的結構呈現最容易被接受,即使我們并不是需要講述一個傳統的打怪升級的故事。雖然故事内容各有不同,但大部分故事都遵循一些基本的範式。例如,約瑟夫·坎伯 總結提出全世界大部分神話故事都符合“ 英雄之旅 ”-- “啟程、啟蒙、歸程”三幕 -- 這個模式。
對于設計文檔/科技論文寫作,通用安全的選擇是 Writing Science 所介紹的 OCAR 故事結構。
設計文檔通常遵循特定的組織結構,我們可以将每一個結構對應到 OCAR 的不同部分,以此講述故事。
最後,辯證看待設計文檔可讀性。設計文檔可讀性 vs. 代碼可讀性都稱作可讀性,兩者有些共通之處:
設計文檔 |
代碼文檔 |
說明背景 |
說明上下文 |
強調 Why/權衡/其它方案 |
強調 Why |
注意事項 |
注意事項 |
代碼可以清晰表達的内容不需要文檔 |
代碼可以清晰表達的内容不需要文檔 |
用詞要簡練、準确、直白。
“_系統形式問題就是下面這樣一個問題:怎樣把各種不同的對象種類安排在一個系統中,以使較高的對象種類總能從較低的對象種類構造出來,也就是說前者可還原為後者。為了解決這個問題,我們必須從其相互可還原性來研究各種不同的對象種類。
為此目的,我們要根據所涉及的對象領域的實際科學知識為每一個要考察的對象尋找其基本事實存在的充分而必要的條件的各種可能性。對此我們可采取下面的辦法來進行,即要求這門實際科學給出基本事實的一個(确實而常在的)表征_。”Excerpt From: 【德】魯道夫·卡爾納普. “世界的邏輯構造.”
段落應該盡量短。通常,一個段落不要超過 8 個完整的句子。每個段落有且僅有一個清晰的主題。每個段落開頭應該是主題句,方便讀者快速了解段落大意。段落中的每一句話應該與主題緊密相關;否則,它應該另起段落,或者應該删掉。
注意段落的流動。段落句子應該始于一個讀者已經熟悉的概念,将新的内容放在句子結尾。這樣,讀者可以更連貫地理解。
使用列表使用 Bullet point 标明無順序的列表,使用數字序号明确前後順序。如何正确使用列表不在本文詳細展開,會在後續文章介紹,也可參見文末的參考文獻。
結構設計文檔不要過長。太多内容堆積在一個文檔中會讓讀者喪失興趣。
對于一個大型項目來說,10 頁(~5000 字)左右是一個合适的長度。當超過這個長度時,可以考慮将問題拆分成子問題分别編寫設計文檔,并在總體設計文檔中鍊接子設計文檔。
對于小問題做增量的改進,考慮使用單頁文檔(one-pager)。通常這類文檔的範圍較小,解決問題較簡單,目标用戶群體僅限于對問題已經有充分了解的内部成員。這時,可以省略背景等内容,而僅使用 目标 -- 方案 兩段式論證的結構。
排版使用統一的字體。用戶不會意識到不同的字體代表不同的含義,隻會感受到混亂。微軟雅黑是安全選擇。
不要使用不同顔色來區分内容。不要在文中使用超過三種顔色。可以在标題及分級标題使用标志性的顔色,同時正文使用黑色。
附錄:設計文檔模闆設計文檔沒有定式。即使如此,筆者參考谷歌設計文檔的結構和格式,并結合實際工作經驗加以完善。在此提供一個可供新手參考的設計文檔模版,您可以使用此文檔模闆作為思考的基礎。通常,無須事無巨細地填寫每一部分,不相關的内容直接略過即可。
目标“我們要解決什麼問題?”
用幾句話說明該設計文檔的關鍵目的,讓讀者能夠一眼得知自己是否對該設計文檔感興趣。如:“本文描述 Spanner 的頂層設計"
繼而,使用 Bullet Points 描述該設計試圖達到的重要目标,如:
非目标也可能很重要。非目标并非單純目标的否定形式,也不是與解決問題無關的其它目标,而是一些可能是讀者非預期的、本可作為目标但并沒有的目标,如:
設計不是試圖達到完美,而是試圖達到平衡。顯式地聲明哪些是目标,哪些是非目标,有助于幫助讀者理解下文中設計決策的合理性,同時也有助于日後叠代設計時,檢查最初的假設是否仍然成立。
背景“我們為什麼要解決這個問題?”
為設計文檔的目标讀者提供理解詳細設計所需的背景信息。按讀者範圍來提供背景。見上文關于目标讀者的圈定。設計文檔應該是“自足的”(self-contained),即應該為讀者提供足夠的背景知識,使其無需進一步的查閱資料即可理解後文的設計。保持簡潔,通常以幾段為宜,每段簡要介紹即可。如果需要向讀者提供進一步的信息,最好隻提供鍊接。警惕知識的詛咒(知識的詛咒(Curse of knowledge)是一種認知偏差,指人在與他人交流的時候,下意識地假設對方擁有理解交流主題所需要的背景知識)
背景通常可以包括:
不要在背景中寫你的設計,或對問題的解決思路。
總體設計“我們如何解決這個問題?”
用一頁描述高層設計。說明系統的主要組成部分,以及一些關鍵設計決策。應該說明該系統的模塊和決策如何滿足前文所列出的目标。
本設計文檔的評審人應該能夠根據該總體設計理解你的設計思路并做出評價。描述應該對一個新加入的、不在該項目工作的騰訊工程師而言是可以理解的。
推薦使用系統關系圖描述設計。它可以使讀者清晰地了解文中的新系統和已經熟悉的系統間的關系。它也可以包含新系統内部概要的組成模塊。
注意:不要隻放一個圖而不做任何說明,請根據上面小節的要求用文字描述設計思想。
不要在這裡描述細節,放在下一章節中;不要在這裡描述背景,放在上一章節中。
詳細設計在這一節中,除了介紹設計方案的細節,還應該包括在産生最終方案過程中,主要的設計思想及權衡(tradeoff)。這一節的結構和内容因設計對象(系統,API,流程等)的不同可以自由決定,可以劃分一些小節來更好地組織内容,盡可能以簡潔明了的結構闡明整個設計。
不要過多寫實現細節。就像我們不推薦添加隻是說明"代碼做了什麼"的注釋,我們也不推薦在設計文檔中隻說明你具體要怎麼實現該系統。否則,為什麼不直接實現呢?以下内容可能是實現細節例子,不适合在設計文檔中讨論:
通常可以包含以下内容(注意,小節的命名可以更改為更清晰體現内容的标題):
各子模塊的設計闡明一些複雜模塊内部的細節,可以包含一些模塊圖、流程圖來幫助讀者理解。可以借助時序圖進行展現,如一次調用在各子模塊中的運行過程。每個子模塊需要說明自己存在的意義。如無必要,勿添模塊。如果沒有特殊情況(例如該設計文檔是為了描述并實現一個核心算法),不要在系統設計加入代碼或者僞代碼。
API 接口如果設計的系統會暴露 API 接口,那麼簡要地描述一下 API 會幫助讀者理解系統的邊界。避免将整個接口複制粘貼到文檔中,因為在特定編程語言中的接口通常包含一些語言細節而顯得冗長,并且有一些細節也會很快變化。着重表現 API 接口跟設計最相關的主要部分即可。
存儲介紹系統依賴的存儲設計。該部分内容應該回答以下問題,如果答案并非顯而易見:
數據的抽象以及數據間關系的描述至關重要。可以借助 ER 圖(Entity Relationshiop) 的方式展現數據關系。
回答上述問題時,盡可能提供數據,将數據作為答案或作為輔助。不要回答“數據規模很大,讀寫頻繁”,而是回答“預計數據規模為 300T, 3M 日讀出, 0.3M 日寫入, 巅峰 QPS 為 300”。這樣才能為下一步的具體數據庫造型提供詳細的決策依據,并讓讀者信服。注意:在選型時也應包括可能會造成顯著影響的非技術因素,如費用。
避免将所有數據定義(data schema)複制粘貼到文檔中,因為 data schema 更偏實現細節。
其他方案“我們為什麼不用另一種方式解決問題?”
在介紹了最終方案後,可以有一節介紹一下設計過程中考慮過的其他設計方案(Alternatives Considered)、它們各自的優缺點和權衡點、以及導緻選擇最終方案的原因等。通常,有經驗的讀者(尤其是方案的審閱者)會很自然地想到一些其他設計方案,如果這裡的介紹描述了沒有選擇這些方案的原因,就避免讀者帶着疑問看完整個設計再來詢問作者。這一節可以體現設計的嚴謹性和全面性。
交叉關注點基礎設施如果基礎設施的選用需要特殊考量,則應該列出。如果該系統的實現需要對基礎設施進行增強或變更,也應該在此讨論。
可擴展性你的系統如何擴展?橫向擴展還是縱向擴展?注意數據存儲量和流量都可能會需要擴展。
安全 & 隐私項目通常需要在設計期即确定對安全性的保證,而難以事後補足。不同于其它部分是可選的,安全部分往往是必需的。即使你的系統不需要考慮安全和隐私,也需要顯式地在本章說明為何是不必要的。安全性如何保證?
如何保證數據完整性(Data Integrity)?如何發現存儲數據的損壞或丢失?如何恢複?由數據庫保證即可,還是需要額外的安全措施?為了數據完整性,需要對穩定性、性能、可複用性、可維護性造成哪些影響?
延遲聲明延遲的預期目标。描述預期延遲可能造成的影響,以及相關的應對措施。
冗餘 & 可靠性是否需要容災?是否需要過載保護、有損降級、接口熔斷、輕重分離?是否需要備份?備份策略是什麼?如何修複?在數據丢失和恢複之間會發生什麼?
穩定性SLA 目标是什麼?如果監控?如何保證?
外部依賴你的外部依賴的可靠性(如 SLA)如何?會對你的系統的可靠性造成何種影響?如果你的外部依賴不可用,會對你的系統造成何種影響?除了服務級的依賴外,不要忘記一些隐含的依賴,如 DNS 服務、時間協議服務、運行集群等。
實現計劃描述時間及人力安排(如裡程碑)。這利于相關人員了解預期,調整工作計劃。
未來計劃未來可能的計劃會方便讀者更好地理解該設計以及其定位。
我們确實應該把設計限定在當前問題,但是該設計可能是更高層系統所要解決問題的一部分,或者隻是階段性方案。讀者可能會對方案的完整性有所疑問,會質疑到底問題是否得到完整解決,甚至會質疑該問題在更高層的系統中是否确實值得解決。“背景(過去)-- 當前方案 -- 未來計劃” 三者的結合會為讀者提供更好的全景圖。
參考資料
推薦一個零聲教育C/C 後台開發的免費公開課程,個人覺得老師講得不錯,分享給大家:C/C 後台開發高級架構師,内容包括Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒體,CDN,P2P,K8S,Docker,TCP/IP,協程,DPDK等技術内容,C/C Linux服務器開發/後台架構師【零聲教育】-學習視頻教程-騰訊課堂 立即學習
原文:如何寫一份高可讀性的軟件工程設計文檔
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!