我的架構(gòu)圖到底是怎么畫出來的?
引言:寫過不少技術(shù)文章,以及給不少技術(shù)思路手繪示例配圖之后,在這方面有了一些心得,本文權(quán)當(dāng)個人的一些的總結(jié),拋磚引玉。
技術(shù)配圖的一些心得
我覺得我們理工科出身的,對于可以量化的事情,總是很容易根據(jù)量化差異來做出判斷,比如一個程序性能優(yōu)化之后,能比優(yōu)化之前快出多少,都能有一個量化的數(shù)字來說明。
但是對于那些不能量化的東西,就很難說出具體好在哪里了。
本文主題要討論的“技術(shù)配圖”就屬于這種很難量化的領(lǐng)域,很難有一個標(biāo)準(zhǔn)來量化說明兩幅圖之間差別在哪里。我也是畫了很多圖,以及看了別人的很多配圖之后,才慢慢有一些心得,本文權(quán)當(dāng)個人的一些的總結(jié),拋磚引玉。
本文并不是一個畫圖工具的對比說明,盡管現(xiàn)在各種繪圖工具已經(jīng)很多,也各有自己的優(yōu)缺點(diǎn)以及個人喜好,但是在這里并不討論具體工具的使用,會把更多的文字放在配圖的一些注意事項(xiàng)上。但是,也總有人問我文章的配圖使用什么工具做的,在這里再回答一次:OmniGraffle,一款目前僅有Mac版本的工具軟件。
一圖勝千言
在開始交代具體的配圖注意事項(xiàng)之前,有必要先說說配圖的重要性。
繪圖,某種程度也是輔助自己思考某個技術(shù)點(diǎn)的手段之一,以我個人的體會來說,有時候講不清楚一個技術(shù)點(diǎn)的時候,就手繪圖出來,比樸素的文字更容易說明問題。其中的原因,有可能是:圖片可以有多維的信息,而文字通常只有一維,遇到文字表達(dá)能力不太好的人,這僅有的一維能力可能還不好發(fā)揮出來。
所以,在交代技術(shù)細(xì)節(jié)、溝通交流的時候,盡量多畫圖。反向的,圖畫多了,也自然慢慢會找到感覺,如何更好的通過圖示表達(dá)思路。
順便一提,還有比樸素的文字表達(dá)更差的技術(shù)溝通方式,就是簡單粗暴的貼一大段代碼上去。這種做法,其實(shí)更多時候是沒有對作者的思路有太多個人的整理,想偷懶的方式,最后回頭再看寫過的文字,可能連自己都看不懂了。
個人的一個體會:如果產(chǎn)出某些輸出的時候,能假設(shè)自己未來就是這些輸出的讀者、維護(hù)者,那么輸出起來會更“友善”一些。比如寫的代碼、文章、甚至于提交代碼時候的信息,如果能考慮是寫給未來的自己看的,會更清晰、盡可能留下更多的信息。我最開始要在文章里大量配圖,也是為了將來自己回看的時候能看懂。
扯遠(yuǎn)了,總之,盡可能多畫圖來表達(dá)技術(shù)思路。
下面開始正題,以下會以簡單的幾個原則及示例來說明。
區(qū)分、聯(lián)系、組合
配圖中,應(yīng)該盡量將不同的模塊、組件等區(qū)分開來,“區(qū)分”的方式有很多,常見的有:
使用不同的顏色。 使用不同的形狀。 使用箭頭、曲線等表示數(shù)據(jù)的走向、趨勢。
等等,所有的這些手段,概括起來就是盡量在圖中,將不同的元素區(qū)分開來,“有區(qū)分”意味著至少有一個維度的不同,這樣能給讀者更加清晰的感覺。可以結(jié)合下面的例子來理解區(qū)分、聯(lián)系和組合的繪圖表達(dá)。
分組
一個模塊里,可能由多個組件構(gòu)成,可以把這些組件分組到一個更大的模塊中。
分組是非常常見的一種手段,這里多舉幾個例子。

上圖中,每個CPU Core中有L1、L2緩存,于是把這些組件合并在一起放在Core組件中,周圍使用一個正方形包裹起來,同時這個正方形左上角有一個Core的說明文字,這樣一目了然:Core模塊,由L1、L2緩存構(gòu)成。

上圖出自Raft論文,整體上劃分為了Client、Server這兩大部分。而每個Server又有以下三部分組成:
一致性算法模塊。 狀態(tài)機(jī)。 持久化的日志。
所以,圖示中將這三部分合在一起放在同一個矩形里,表示一個Server有這三個組件。
另外還需注意的是,一般這種分組中外圍的矩形,有這樣的講究:
一般使用斜面矩形,即四個角是圓角的矩形,這樣圓潤一些的邊角看起來會更舒服一些,如上圖。 如果這個組合,是一種邏輯上的組合,那么線的形狀一般用虛線;否則就一般用的實(shí)線。
在分組時,有時候可以將相同類型的模塊層疊起來,這樣會更加簡潔,如下圖:

上圖是出自Raft論文中的狀態(tài)機(jī)模型,其中想要表達(dá)的一個點(diǎn)是:
有多個client向server發(fā)起請求。 server要達(dá)成一致,需要將日志在server之間同步。
但是上圖中,并沒有把這些同類型的組件分開表達(dá),而是巧妙的使用層疊的方式,簡潔得表達(dá)了有多個client、多個server的情況。
趨勢
如果不同的組件之間,有不同的趨勢,可以在圖中使用類似箭頭這樣的符號表達(dá)出來。
下圖是描述不同層次存儲的訪問速度,于是用了兩個方式來表達(dá)訪問速度的變化趨勢:
左邊的箭頭表達(dá)速度和成本的變化。 不同大小的多邊形表達(dá)了這些存儲空間的變化:越往上訪問速度越快,但是對應(yīng)的存儲空間也更小。

再比如,下圖中,是說明sqlite中btree頁面的數(shù)據(jù)組織的。其中的兩部分內(nèi)容,Cell地址數(shù)組以及Cell內(nèi)容區(qū)為變長大小,前者從地址低位向高位生長,后者反之,于是在圖中,就用箭頭示例出地址的高低位區(qū)別,以及兩者的增長方向:

(出自sqlite3.36版本 btree實(shí)現(xiàn)(五)- Btree的實(shí)現(xiàn) - codedump的網(wǎng)絡(luò)日志)
聯(lián)系
用箭頭等表示數(shù)據(jù)、狀態(tài)等的走向,或者模塊之間的聯(lián)系。
這在涉及:
狀態(tài)切換。 數(shù)據(jù)流向。
等場景下是非常常見的手段,比如經(jīng)典的TCP狀態(tài)機(jī)切換:

以及TCP三次握手流程,也是典型的“狀態(tài)切換”:

需要說明的是,以上的圖示中:
箭頭代表的狀態(tài)切換走向中,同時也配以文字說明是什么動作導(dǎo)致的狀態(tài)切換,這樣這個圖示就更清晰了。 箭頭也分為實(shí)線和虛線,一般而言,虛線表示數(shù)據(jù)的走向,實(shí)線表示狀態(tài)的走向。
禁止
需要禁止或者錯誤的行為,可以用特殊的符號,如帶顏色的“×”符號示意出來;反之,可以用帶顏色的“√”符號示意出來,而且表示禁止的時候,一般用紅色會更顯眼,下圖就是一個示例:

(出自 Memory Barriers in .NET · Nadeem Afana's Blog)
說明
如果不好說明問題,可以在圖示中搭配簡短的說明文字。注意:這類型文字一定要足夠的簡短,否則可能會喧賓奪主。
比如下圖中,有兩部分藍(lán)色注解的文字來說明不同的表類型:

(出自sqlite3.36版本 btree實(shí)現(xiàn)(五)- Btree的實(shí)現(xiàn) - codedump的網(wǎng)絡(luò)日志)
再比如下圖中,使用注解文字來說明查找數(shù)據(jù)的兩步流程:

(出自sqlite3.36版本 btree實(shí)現(xiàn)(五)- Btree的實(shí)現(xiàn) - codedump的網(wǎng)絡(luò)日志)
分類
有時候需要使用類似{這樣的符號,對一類元素做一些說明,例如:
下圖中,是說明sqlite中btree頁面的數(shù)據(jù)組織的,最右邊的以{包起來的文字,對每部分做了簡要的說明。

(出自sqlite3.36版本 btree實(shí)現(xiàn)(五)- Btree的實(shí)現(xiàn) - codedump的網(wǎng)絡(luò)日志)
下圖中,將頁面劃分為不同的部分,這些不同的組成部分,既使用了顏色進(jìn)行區(qū)分,也使用了向下的{輔以文字說明。

(出自sqlite3.36版本 btree實(shí)現(xiàn)(五)- Btree的實(shí)現(xiàn) - codedump的網(wǎng)絡(luò)日志)
步驟
如果配圖是需要講解某個操作的步驟的,可以配以數(shù)字來輔助理解整個流程。
下圖中,表達(dá)的是根據(jù)幀數(shù)查找頁面編號的兩個步驟:

(出自sqlite3.36版本 btree實(shí)現(xiàn)(四)- WAL的實(shí)現(xiàn) - codedump的網(wǎng)絡(luò)日志)
下圖中的步驟就更多了,并沒有顯得很亂,大概原因在于:
最左邊表達(dá)了每一步的步驟。 每一步寫入數(shù)據(jù)之后,顯示W(wǎng)AL文件在寫入之后的內(nèi)容。 最右邊使用 {表達(dá)修改之后的數(shù)據(jù)。

(出自sqlite3.36版本 btree實(shí)現(xiàn)(四)- WAL的實(shí)現(xiàn) - codedump的網(wǎng)絡(luò)日志)
展開
在講解例如文件格式,或者協(xié)議格式等內(nèi)容的時候,格式由多個部分劃分組成,其中又可以針對其中的某些內(nèi)容展開說明。
如下圖中,是用于展示wal index索引文件格式的:
左邊示例每部分內(nèi)容的大小,想說明的是,那個索引塊大小為32KB,而第一塊的頭136字節(jié)為索引文件頭。 于是,在右邊圖中,將左邊不同模塊的具體格式繼續(xù)展開說明。

(出自sqlite3.36版本 btree實(shí)現(xiàn)(四)- WAL的實(shí)現(xiàn) - codedump的網(wǎng)絡(luò)日志)
總結(jié)
以上簡單總結(jié)了一下個人技術(shù)配圖的一些心得,總的大原則是:
區(qū)分:將組件、流程、趨勢等之間的”區(qū)分“盡可能在圖示中通過各種手段(如不同的顏色、形狀、箭頭)表達(dá)出來。 聯(lián)系:組件之間的數(shù)據(jù)流動、狀態(tài)切換等,都是它們之間的聯(lián)系,也需要通過各種手段表達(dá)出來。 說明:可能的話,要在圖中加上一些說明文字,如步驟說明、分類說明,等等。
