Google 如何寫設(shè)計文檔

來源:技術(shù)瑣話
作者:Malte
時間:2023-01-29
1523
Google 軟件工程文化中關(guān)鍵元素之一,是使用設(shè)計文檔來定義軟件設(shè)計。這些文檔通常不是非常正式,主要是軟件系統(tǒng)或應(yīng)用程序的作者在著手寫代碼之前編寫的。這些設(shè)計文檔記錄了 high-level 的實現(xiàn)策略和關(guān)鍵的設(shè)計決策,而后者重點描述了決策過程中思考的權(quán)衡。

作為軟件工程師,我們的工作并不是生產(chǎn)代碼本身,而是解決問題。非結(jié)構(gòu)化的文本,例如以設(shè)計文檔的形式,在項目早期或許是解決問題更適宜的工具。因為設(shè)計文檔可能更簡明、更容易被理解,相比代碼能在更高的層面溝通問題及解決方案。

除了用作軟件設(shè)計的原始文檔記錄,設(shè)計文檔還在軟件研發(fā)生命周期中實現(xiàn)了下述功能:

在修改成本還比較低的時候,盡早地識別設(shè)計缺陷。

在組織中圍繞設(shè)計達(dá)成共識。

確保橫切關(guān)注點(Cross-cutting concern)得到充分考慮。

在組織中傳播資深工程師的知識。

就設(shè)計決策形成組織記憶基礎(chǔ)。

成為軟件設(shè)計者技術(shù)資產(chǎn)中的一個摘要性制品。

1. 設(shè)計文檔的構(gòu)成

設(shè)計文檔是非正式的文檔,因此其內(nèi)容不需要遵循嚴(yán)格的準(zhǔn)則。因此首要原則就是:在特定的項目中,用任何最合理的形式編寫。

在此原則之外,Google 也建立了一種頗有效果的設(shè)計文檔結(jié)構(gòu)。

1.1 上下文和范圍(Context and scope)

這一小節(jié)給讀者展現(xiàn)一個有關(guān)這個系統(tǒng)在哪里被構(gòu)建,以及什么會被構(gòu)建的非常粗的概覽。這不是需求文檔。保持言簡意賅!這里的目標(biāo)是讓讀者快速進(jìn)入狀態(tài),可以假設(shè)讀者知道一些前置的知識,相關(guān)詳情可以給到鏈接。這一節(jié)內(nèi)容應(yīng)該完全關(guān)注在客觀的背景事實。

1.2 目標(biāo)和非目標(biāo)(Goals and non-goals)

給出一個簡單的列表,講述系統(tǒng)的目標(biāo)是什么。有時候更重要的是講述非目標(biāo)是什么。注意,非目標(biāo)不是對目標(biāo)的否定,例如“系統(tǒng)不應(yīng)該 crash”,而是顯示地挑選出來的不是目標(biāo)的內(nèi)容。一個好的例子是 “遵循 ACID”,當(dāng)設(shè)計一個數(shù)據(jù)庫的時候,你必然想要知道這是目標(biāo)還是非目標(biāo)。進(jìn)一步的,你仍然可以選擇一個方案來實現(xiàn)非目標(biāo),只要它不會給實現(xiàn)目標(biāo)帶來不必要的權(quán)衡。

1.3 實際設(shè)計(The actual design)

這一部分應(yīng)該以一個概述開頭,然后逐漸展開細(xì)節(jié)。

  設(shè)計是文檔是在你設(shè)計軟件的過程中,記錄設(shè)計取舍的地方。應(yīng)該關(guān)注這些取舍,以產(chǎn)出一個具備長期價值的文檔。具體就是,在既定的上下文(事實),目標(biāo)和非目標(biāo)(需求)下,設(shè)計文檔應(yīng)該提出解決方案,并闡明為什么某個特定的解決方案是滿足這些目標(biāo)的最佳方案。

相較于更為正式媒體形式,編寫文檔的意義在于可以用合適的方式靈活地表述手頭的問題集合。因此,如何描述設(shè)計并沒有顯式的指引。

話雖如此,對于大多數(shù)設(shè)計文檔來說,一些最佳實踐和重復(fù)出現(xiàn)的主題還是有意義的:

1.3.1 系統(tǒng)上下文圖(System-context-diagram)

對于很多文檔來說,系統(tǒng)上下文圖是很有用的。這類圖展示了當(dāng)前系統(tǒng)是更大技術(shù)圖景的一部分,能讓讀者在一個他們已經(jīng)熟悉的上下文環(huán)境中去理解新的設(shè)計。

系統(tǒng)上下文圖的例子

1.3.2 APIs

如果設(shè)計的系統(tǒng)會暴露 API,那么草擬出 API 通常是好想法。不過,在大多數(shù)情況,我們應(yīng)該克制住把正式接口和數(shù)據(jù)定義復(fù)制粘貼到文檔中的沖動,因為這么做會導(dǎo)致文檔過于冗長,包含不必要的細(xì)節(jié),并很快過期。相對應(yīng)的,我們應(yīng)當(dāng)關(guān)注和設(shè)計及取舍相關(guān)的那部分 API。

1.3.3 數(shù)據(jù)存儲(Data storage)

需要存儲系統(tǒng)的系統(tǒng)應(yīng)該討論數(shù)據(jù)是如何以何種形式,如何被存儲的。和前面描述 API 的建議一樣,基于相同的理由,應(yīng)該避免復(fù)制粘貼完整的 schema 定義,正確的做法是關(guān)注在那些和設(shè)計取舍相關(guān)的部分。

1.3.4 代碼和偽代碼(Code and pseudo-code)

設(shè)計文檔應(yīng)當(dāng)很少包含代碼或偽裝代碼,除非有一些情況需要描述新的算法。合理的做法是給到設(shè)計原型實現(xiàn)的鏈接。

1.3.5 約束條件(Degree of constraint)

軟件設(shè)計形態(tài)(因此設(shè)計文檔)的主要影響因素是解決方案空間(solution space)中的約束條件。

一個方向的極端情況是 “綠地軟件項目(greenfield)”,在這種情況下我們知道所有的目標(biāo),解決方案只要是合理的,沒什么限制。這樣的文檔可能就會顯得很寬泛,但是也應(yīng)該快速定義一組規(guī)則,以便讓大家盡快把目光收斂到一組可控的解決方案中。

另一個方向的極端情況是,所有可能的解決方案都被定義得很清楚了,但是如何把它們結(jié)合起來以達(dá)成目標(biāo),卻毫不清晰。這往往是因為遺留系統(tǒng)難以改動,或者遺留系統(tǒng)不是被設(shè)計用來解決當(dāng)前所面臨的問題的,又或者是一個類庫的設(shè)計要求我們在它的宿主編程語言限制下工作。

在這種情況下,你或許可以遍歷所有可行的簡單方法,但更需要創(chuàng)新地把所有這些方法整合起來以完成目標(biāo)。也許存在多種方案,每一種方案都不是特別出色的,因此文檔應(yīng)該關(guān)注在如何從已經(jīng)識別的各項取舍中,選擇最合適的方案。

1.4 候選設(shè)計(Alternatives considered)

這一小節(jié)列出那些同樣可以實現(xiàn)類似產(chǎn)出的可選設(shè)計。這里關(guān)注的應(yīng)該是各種方案各自的取舍,以及這些取舍的對比如何引向最終的設(shè)計 —— 文檔的核心主題。

雖然描述候選設(shè)計可以簡潔一些,但是這一小節(jié)實際上非常核心的,因為這里非常清晰地展示了,在給定的項目目標(biāo)和所有可選方案下,為什么選擇了最終方案,在給定目標(biāo)下權(quán)衡的判斷是如何做出的,而這正是文檔的讀者所關(guān)注的核心。

1.5 橫切關(guān)注點(Cross-cutting Concerns)

在這里組織可以確保一些橫切關(guān)注點如安全,隱私,可觀測性,總是被考慮到。這部分內(nèi)容通常相對較短,只是用來解釋設(shè)計會如何影響到橫切關(guān)注點,以及相關(guān)影響如何得到解決。團(tuán)隊?wèi)?yīng)該標(biāo)準(zhǔn)化在他們場景下的關(guān)注點。

例如,由于隱私非常重要,Google 的項目就必須寫一個專門的隱私設(shè)計文檔,這個文檔會別專門用來 Review 隱私和安全。雖然 Review 只要在項目啟動前完成,但通常最好是盡早讓隱私和安全團(tuán)隊介入,確保設(shè)計從一開始就重視他們的意見。關(guān)于這部分內(nèi)容更專門的細(xì)節(jié),核心文檔不一定要全部包含,有時候給到這些專門文檔的引用即可。

1.6 設(shè)計文檔的長度(The length of a design doc)

設(shè)計文檔應(yīng)該具備充分的細(xì)節(jié),但同時足夠簡短以能夠被忙碌的人閱讀。對于一個大型項目來說,最佳的長度似乎是 10 到 20 頁。如果你的內(nèi)容超過這個大小,更合理的做法可能是把這個問題劃分成更易管理的子問題。當(dāng)然,需要注意的是,編寫 1-3 頁的“迷你設(shè)計文檔”完全是可能的。這類文檔對于敏捷項目中的增量改進(jìn)或者子任務(wù)尤其有用 —— 但你仍然需要和編寫長文檔一樣執(zhí)行一樣的步驟,區(qū)別只是讓內(nèi)容更精煉,并且只關(guān)注有限的問題集合。

2. 什么時候不要編寫設(shè)計文檔(When not to write a design doc)

編寫設(shè)計文檔是需要成本的。關(guān)于是否編寫設(shè)計文檔的決定,實際上是在做權(quán)衡。權(quán)衡的一邊是圍繞設(shè)計、文檔、高層評審等工作形成組織共識的益處,權(quán)衡的另一邊是這塊工作投入的精力成本。決策的核心在于設(shè)計問題的解決方案是否模糊 —— 這往往是因為問題復(fù)雜度,或者解決方案的復(fù)雜度引起的(或者兩者皆有)。如果不存在這個問題,那么走一個設(shè)計文檔編寫的流程價值就有限。

設(shè)計文檔可能沒有必要的一個明顯征兆是:設(shè)計文檔實際上是實現(xiàn)手冊。如果文檔基本上說的是“這是我們將如何實現(xiàn)之”,而沒有深入討論取舍、可選方案、沒有解釋決策(或者說解決方案太明顯了以致于沒什么取舍可討論),那么很有可能直接編寫真實代碼是更好的選擇。

最后,創(chuàng)建和評審設(shè)計文檔的投入可能與快速制作原型并迭代理念并不相容。但是大多數(shù)軟件項目都是有一組實際上已知的問題。擁抱敏捷方法不應(yīng)該成為不花時間去尋找已知問題正確解決方案的借口。此外,原型本身可能就是創(chuàng)建設(shè)計文檔過程的一部分。“我試過了,這么做可行” 就是選擇一種設(shè)計最好的論據(jù)之一。

3. 設(shè)計文檔的生命周期(The design doc lifecycle)

一份設(shè)計文檔的生命周期包括如下階段:

1.創(chuàng)建和快速迭代

2.審查(可能有多輪)

3.實現(xiàn)和迭代

4.維護(hù)和學(xué)習(xí)

3.1 創(chuàng)建和快速迭代(Creation and rapic iteration)

你編寫文檔,有時候是和幾個合作者一起編寫。

這一階段快速演進(jìn)成為快速迭代的時期,文檔被分享給一些同事,他們擁有關(guān)于問題空間(problem space)的最多的知識(通常屬于同一個團(tuán)隊),通過他們不斷澄清問題并提出建議,文檔逐漸形成第一個相對穩(wěn)定的版本。

你會發(fā)現(xiàn)很多工程師和團(tuán)隊更偏向于使用版本控制和代碼審查工具來管理文檔,但是 Google 的大多數(shù)文檔是使用 Google Docs 創(chuàng)建的,并重度使用了協(xié)作特性。

3.2 評審Review)

在評審階段,設(shè)計文檔被分享給原始作者和緊密協(xié)作者之外更廣范的一批受眾。評審可以給文檔增加很多價值,但是也有可能是危險的投入成本陷阱,因此要明智對待。

評審可以有很多形式:最輕量的版本就是簡單把文檔發(fā)給更大范圍的團(tuán)隊,讓大伙有機(jī)會可以看一眼。隨著而來的討論主要就發(fā)生在文檔的評論區(qū)。而形式較重的評審,就是發(fā)起正式的設(shè)計文檔評審會議,在會議中作者面向通常是較為資深的工程師聽眾演示文檔(通常是專門的演示)。Google 有很多團(tuán)隊為此目的排了周期性的會議,工程師可以注冊用來發(fā)起設(shè)計評審。自然的,等待此類會議來評審設(shè)計文檔會大幅降低研發(fā)速度。工程師可以通過直接向同事獲取最關(guān)鍵的反饋,同時也不阻塞更廣泛的評審,進(jìn)而降低這一風(fēng)險。

當(dāng) Google 是一個小一些的公司的時候,大家習(xí)慣上會把設(shè)計發(fā)到一個中心的郵件列表中,在這里資深的工程師會抽空進(jìn)行評審。這種方式對公司來說可能就不錯。這種方式一大好處是,它在整個公司層面建立了一種相對一致的軟件設(shè)計文化。但是隨著公司逐漸增長細(xì)形成一個較大的工程師團(tuán)隊,維護(hù)這種中心化的方法就不可行了。

設(shè)計評審增加的主要價值是,它形成了一個讓組織的綜合經(jīng)驗可以融合到設(shè)計中的機(jī)會。如何讓設(shè)計能夠充分考慮橫切關(guān)注點如可觀測性、安全性、以及隱私,這一點就能夠非常一致地在評審階段得到保障。評審的主要價值不是問題被發(fā)現(xiàn)本身,而是讓問題在軟件研發(fā)階段相對早期的時候,也就是修復(fù)成本相對較低的時候被發(fā)現(xiàn)。

3.3 實現(xiàn)和迭代(Implementation and iteration)

當(dāng)事情獲得了充分的進(jìn)展,看起來進(jìn)一步的評審不太會要求設(shè)計做重大的改變,那就是時候開始實現(xiàn)了。當(dāng)計劃和現(xiàn)實沖突,不可避免的會發(fā)現(xiàn)設(shè)計的缺陷,未被充分考慮的需求,或者基于經(jīng)驗的推測實際上錯誤的,進(jìn)而發(fā)現(xiàn)需要對設(shè)計做修改。在這種情況下強(qiáng)烈推薦更新設(shè)計文檔,一般說來:如果系統(tǒng)還沒有上線,那么很確定應(yīng)該更新文檔。在實踐中,我們普通人在更新文檔方面都做得不好,以及因為一些其他的實際因素,更新還通常會落到新的獨(dú)立的文檔中去。這就導(dǎo)致了一種近似美國憲法的最終態(tài):有一堆修正案,而非一份一致的文檔。對于將來維護(hù)系統(tǒng)的可憐程序員來說,當(dāng)他們像考古學(xué)家一樣翻閱歷史設(shè)計文檔,去試圖理解目標(biāo)系統(tǒng)的時候,原始文檔中給出這些“修正案”的鏈接會非常有幫助。

3.4 維護(hù)和學(xué)習(xí)(Maintenance and learning)

當(dāng) Google 工程師首次接觸一個系統(tǒng)的時候,他們的第一個問題通常是“設(shè)計文檔在哪里? 。雖然說設(shè)計文檔和所有其他文檔一樣,都會隨著時間的流逝變得和現(xiàn)實不一致,但它們依舊是學(xué)習(xí)系統(tǒng)在創(chuàng)建之初其背后思考的最佳起步材料。

作為作者,從為自己著想的角度考慮,可以在一兩年后重新閱讀自己的設(shè)計文檔。你哪里做對了?哪里做錯了?在今天來看你會做哪些不同的決策?對于工程師來說,回答這些問題是一種絕佳的提升軟件設(shè)計能力和自我進(jìn)步的方式。

4. 結(jié)論(Conclusions)

在軟件項目中,圍繞解決最難的問題,設(shè)計文檔是一種獲得清晰度以并達(dá)成共識的絕佳方法。設(shè)計文檔可以節(jié)省金錢,因為在前期足夠的調(diào)研可以幫助避免過早就進(jìn)入編碼細(xì)節(jié)卻未能完成項目目標(biāo);設(shè)計文檔又花費(fèi)金錢,因為編寫和審查文檔消耗時間。因此,在你項目中明智地做出選擇。

在考慮是否編寫設(shè)計文檔的時候,思考如下問題:

你是否對正確軟件設(shè)計不確信?在前期消耗時間來獲取確定性是否合理?

在設(shè)計階段引入相關(guān)的資深工程師是否有幫助?他們可能沒有時間審查所有代碼。

軟件設(shè)計是否是模糊的,甚至是有爭議的?因此圍繞這一問題在組織層面達(dá)成共識會很有價值?

我團(tuán)隊是否有時候會在設(shè)計中忘記考慮隱私、安全、日志或者其他橫切關(guān)注點?

在組織中是否非常需要遺留系統(tǒng)設(shè)計的文檔?這樣可以讓大家在 high-level 快速了解系統(tǒng)。

如果對于上述的問題你有三個或更多“是”的回答,那么在你開始下一個軟件項目的時候,設(shè)計文檔大概率是個不錯的方法。


原文鏈接:點擊前往 >
版權(quán)說明:本文內(nèi)容來自于技術(shù)瑣話,本站不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。文章內(nèi)容系作者個人觀點,不代表快出海對觀點贊同或支持。如有侵權(quán),請聯(lián)系管理員(zzx@kchuhai.com)刪除!
個人VIP