技術(shù)配圖的一些心得
引言
寫過不少技術(shù)文章,以及給不少技術(shù)思路手繪示例配圖之后,在這方面有了一些心得,本文給出一些關(guān)于配圖的見解,僅供大家參考。
關(guān)于技術(shù)配圖
對于理工科出身的同學(xué),對于可以量化的事情,總是很習(xí)慣根據(jù)量化差異來做出判斷,比如一個程序性能優(yōu)化之后,對比優(yōu)化之前快出多少,都能很容易的通過一個量化的數(shù)字來說明。
但是對于那些不能量化的東西,就很難說出具體好在哪里了。
本文主題要討論的“技術(shù)配圖”就屬于這種很難量化的領(lǐng)域,很難有一個標(biāo)準(zhǔn)來量化說明兩幅圖之間差別在哪里。我也是畫了很多圖,以及看了別人的很多配圖之后,才慢慢有一些心得,本文權(quán)當(dāng)個人的一些的總結(jié),拋磚引玉,歡迎交流探討。
本文并不是一個畫圖工具的對比說明,盡管現(xiàn)在各種繪圖工具已經(jīng)很多,也各有自己的優(yōu)缺點,但是在這里并不討論具體工具的使用,會把更多的文字放在配圖的一些注意事項上。但是,也總有人問我文章的配圖是用什么工具做的,在這里再回答一次:OmniGraffle,一款目前僅有 Mac 版本的工具軟件。
配圖的重要性
在開始交代具體的配圖注意事項之前,有必要先說說配圖的重要性。
繪圖,某種程度來說也是輔助自己思考某個技術(shù)點的手段之一,以我個人的體會來說,有時候講不清楚一個技術(shù)點的時候,就手繪圖出來,比樸素的文字更容易說明問題。其中的原因,有可能是:圖片可以有多維的信息,而文字通常只有一維,遇到文字表達(dá)能力不太好的人,這僅有的一維能力可能還不好發(fā)揮出來。
所以,在交代技術(shù)細(xì)節(jié)、溝通交流的時候,盡量多畫圖。反向的,圖畫多了,也自然慢慢會找到感覺,更好的通過圖示表達(dá)思路。
順便一提,還有比樸素的文字表達(dá)更差的技術(shù)溝通方式,就是簡單粗暴的貼一大段代碼上去。這種做法,其實更多時候是對作者的思路沒有太多個人的整理,純粹偷懶的方式,往往最后回頭再看寫過的文字,可能連自己都看不懂了。
如果產(chǎn)出某些內(nèi)容的時候,能假設(shè)自己未來就是這些輸出的讀者、維護(hù)者,那么輸出起來會更完善一些。比如寫的代碼、文章、甚至于提交代碼時候的信息,如果能考慮是寫給未來的自己看的,會更清晰、盡可能留下更多的信息。我最開始要在文章里大量配圖,也是為了將來自己回看的時候能看懂。
總之,盡可能多畫圖來表達(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有這三個組件。
另外還需注意的是,一般這種分組中外圍的矩形,有這樣的講究:
一般使用斜面矩形,即四個角是圓角的矩形,這樣圓潤一些的邊角看起來會更舒服一些,如上圖。
如果這個組合,是一種邏輯上的組合,那么線的形狀一般用虛線;否則就一般用的實線。
在分組時,有時候可以將相同類型的模塊層疊起來,這樣會更加簡潔,如下圖:

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

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

聯(lián)系
這在涉及:
狀態(tài)切換。
數(shù)據(jù)流向。
等場景下是非常常見的手段,比如經(jīng)典的 TCP 狀態(tài)機(jī)切換:

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

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

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

再比如下圖中,使用注解文字來說明查找數(shù)據(jù)的兩步流程:

分類
有時候需要使用類似“{”這樣的符號,對一類元素做一些說明,例如:
下圖中,是說明 sqlite 中 btree 頁面的數(shù)據(jù)組織的,最右邊的以“{”包起來的文字,對每部分做了簡要的說明。

下圖中,將頁面劃分為不同的部分,這些不同的組成部分,既使用了顏色進(jìn)行區(qū)分,也使用了向下的“{”輔以文字說明。

步驟
如果配圖是需要講解某個操作的步驟的,可以配以數(shù)字來輔助理解整個流程。
下圖中,表達(dá)的是根據(jù)幀數(shù)查找頁面編號的兩個步驟:

下圖中的步驟就更多了,并沒有顯得很亂,大概原因在于:
最左邊表達(dá)了每一步的步驟。
每一步寫入數(shù)據(jù)之后,顯示 WAL 文件在寫入之后的內(nèi)容。
最右邊使用“{”表達(dá)修改之后的數(shù)據(jù)。

展開
如下圖中,是用于展示 wal index 索引文件格式的:
左邊示例每部分內(nèi)容的大小,想說明的是,那個索引塊大小為 32 KB,而第一塊的頭 136 字節(jié)為索引文件頭。
于是,在右邊圖中,將左邊不同模塊的具體格式繼續(xù)展開說明。

總結(jié)
以上簡單總結(jié)了一下個人技術(shù)配圖的一些心得,總的大原則是:
區(qū)分:將組件、流程、趨勢等之間的“區(qū)分”盡可能在圖示中通過各種手段(如不同的顏色、形狀、箭頭)表達(dá)出來。
聯(lián)系:組件之間的數(shù)據(jù)流動、狀態(tài)切換等,都是它們之間的聯(lián)系,也需要通過各種手段表達(dá)出來。
說明:可能的話,要在圖中加上一些說明文字,如步驟說明、分類說明,等等。
引用鏈接
[1]?sqlite3.36版本 btree實現(xiàn)(五)- Btree的實現(xiàn) - codedump的網(wǎng)絡(luò)日志:?
https://www.codedump.info/post/20220201-sqlite-btree-5-btree/
[2]?Memory Barriers in .NET · Nadeem Afana’s Blog:
https://afana.me/archive/2015/07/10/memory-barriers-in-dot-net.aspx/
[3]?sqlite3.36版本 btree實現(xiàn)(五)- Btree的實現(xiàn) - codedump的網(wǎng)絡(luò)日志:?
https://www.codedump.info/post/20220201-sqlite-btree-5-btree/
[4]?sqlite3.36版本 btree實現(xiàn)(五)- Btree的實現(xiàn) - codedump的網(wǎng)絡(luò)日志:?
https://www.codedump.info/post/20220201-sqlite-btree-5-btree/
[5]?sqlite3.36版本 btree實現(xiàn)(五)- Btree的實現(xiàn) - codedump的網(wǎng)絡(luò)日志:
https://www.codedump.info/post/20220201-sqlite-btree-5-btree/
[6]?sqlite3.36版本 btree實現(xiàn)(五)- Btree的實現(xiàn) - codedump的網(wǎng)絡(luò)日志:
https://www.codedump.info/post/20220201-sqlite-btree-5-btree/?[7]?sqlite3.36版本 btree實現(xiàn)(四)- WAL的實現(xiàn) - codedump的網(wǎng)絡(luò)日志:
https://www.codedump.info/post/20220106-sqlite-btree-4-wal/?[8]?sqlite3.36版本 btree實現(xiàn)(四)- WAL的實現(xiàn) - codedump的網(wǎng)絡(luò)日志:?
https://www.codedump.info/post/20220106-sqlite-btree-4-wal/?[9]?sqlite3.36版本 btree實現(xiàn)(四)- WAL的實現(xiàn) - codedump的網(wǎng)絡(luò)日志:
https://www.codedump.info/post/20220106-sqlite-btree-4-wal
關(guān)于 Databend
Databend 是一款開源、彈性、低成本,基于對象存儲也可以做實時分析的新式數(shù)倉。期待您的關(guān)注,一起探索云原生數(shù)倉解決方案,打造新一代開源 Data Cloud。
Databend 文檔:https://databend.rs/
Twitter:https://Twitter.com/Datafuse_Labs
Slack:https://datafusecloud.slack.com/
Wechat:Databend
GitHub :https://github.com/datafuselabs/databend
