雖然程序員多數時候都在與字符打交道,但偶爾也會像建築或製造業的工程師同樣,畫一些圖,好比:node
除此以外,還有流程圖、甘特圖、火焰圖,等等。git
儘管軟件開發過程當中產出的這些圖不必定逼真、漂亮,或嚴謹,但憑着圖上不一樣的形狀、顏色,以及佈局,也能夠作到一圖勝千言的效果。程序員
圖頗有用,畫圖的工具也一樣舉足輕重。若是是本地的桌面應用,多數人可能會選擇用Windows平臺的Visio或macOS平臺的OmniGraffle;若說到做圖網站,則可能會選擇ProcessOn或Draw.io。github
但比起用鼠標拖拖拉拉,我更喜歡用代碼來畫圖。web
用代碼畫圖大體上能夠分爲兩類:算法
我所說的用代碼畫圖指的是上述的第二類。shell
百聞不如一見,以最容易上手的DOT
語言爲例,將下列內容保存在名爲hello.dot
的文件中數據庫
digraph G { Hello -> World }
而後在shell中運行以下命令npm
dot -Tpng hello.dot -o hello.png
便獲得了相應的PNG文件編程
下面就帶各位讀者蜻蜓點水地看看不一樣的圖能夠用哪些工具來繪製。
說到程序員畫的圖,最出名的當屬流程圖了。依稀記得在高中的時候,某一冊的數學課本中講到了算法(也許是展轉相除法),而且給出了圖示,那應當就是我第一次見到流程圖。上大學後也有一段時間癡迷於尋找可以繪製流程圖的DSL,不過一直未果。直到遇到Boostnote後,才知道的確有這樣的DSL,那即是flowchart.js。
flowchart.js
是一個JS編寫的、用來繪製流程圖的庫。好比下面這張圖
即是依據下列的DSL生成的
st=>start: Start op=>operation: Your Operation cond=>condition: Yes or No? e=>end st->op->cond cond(yes)->e cond(no)->op
flowchart.js
生成的是SVG格式的圖片文件,但SVG文件不方便嵌入到Markdown或Confluence的文檔中,所以我會把它轉換爲PNG格式。折騰了一番後,發如今Mac上最靠譜的方法,是將SVG文件嵌入一個HTML文檔,再用瀏覽器打開這個HTML,而後複製圖片到預覽程序上保存下來。
遺憾的是,不論是Emacs仍是VSCode,彷佛都沒有輔助編輯flowchart.js
的DSL的插件。
有限狀態機的示意圖也是很常見的圖形,尤爲是在講解編譯器的書的語法分析章節中。在Graphviz項目官網的Gallery板塊中,便有一個有限狀態機的例子
它由以下的DOT
代碼描述
digraph finite_state_machine { rankdir=LR; size="8,5" node [shape = doublecircle]; LR_0 LR_3 LR_4 LR_8; node [shape = circle]; LR_0 -> LR_2 [ label = "SS(B)" ]; LR_0 -> LR_1 [ label = "SS(S)" ]; LR_1 -> LR_3 [ label = "S($end)" ]; LR_2 -> LR_6 [ label = "SS(b)" ]; LR_2 -> LR_5 [ label = "SS(a)" ]; LR_2 -> LR_4 [ label = "S(A)" ]; LR_5 -> LR_7 [ label = "S(b)" ]; LR_5 -> LR_5 [ label = "S(a)" ]; LR_6 -> LR_6 [ label = "S(b)" ]; LR_6 -> LR_5 [ label = "S(a)" ]; LR_7 -> LR_8 [ label = "S(b)" ]; LR_7 -> LR_5 [ label = "S(a)" ]; LR_8 -> LR_6 [ label = "S(b)" ]; LR_8 -> LR_5 [ label = "S(a)" ]; }
很多工具將DOT
語言做爲中間媒介來實現繪圖的功能。
與flowchart.js
不一樣,Emacs和VSCode均可以很好地支持DOT
代碼的編輯和預覽。Emacs上有dot-mode
,VSCode則有Graphviz (dot) language support for Visual Studio Code這個插件。
我畫得最多的當屬時序圖。在舊文《時序圖繪製工具蜻蜓點水》中,提到了三個工具:
當時傾向於使用sdedit
。時過境遷,現在的WebSequenceDiagrams
變得更好看了,而我也選擇了PlantUML做爲繪製時序圖的主力工具。下面這張圖是PlantUML
官網給出的例子
它依據以下的代碼生成
@startuml 用戶 -> 認證中心: 登陸操做 認證中心 -> 緩存: 存放(key=token+ip,value=token)token 用戶 <- 認證中心 : 認證成功返回token 用戶 -> 認證中心: 下次訪問頭部攜帶token認證 認證中心 <- 緩存: key=token+ip獲取token 其餘服務 <- 認證中心: 存在且校驗成功則跳轉到用戶請求的其餘服務 其餘服務 -> 用戶: 信息 @enduml
Emacs的plantuml-mode
,以及VSCode的PlantUML插件均可覺得PlantUML
的DSL提供語法高亮。
下載了PlantUML
的jar
包後,在Emacs中添加以下的配置,就能夠不依賴遠程服務器來生成PNG格式的圖片了
(setq plantuml-default-exec-mode 'jar) (setq plantuml-jar-path "/path/to/plantuml.jar")
在《架構整潔之道》一書中,做者提出了一個軟件架構模式,其中有一層即是用例。看完這本書後,我愈加地喜歡做者這一套架構模式,漸漸開始在設計文檔中給出需求的典型用例——儘管是文字描述。再後來,才知道原來UML中已經有一類專門用於描述用例的圖形方法——用例圖。
用於畫用例圖的依然是PlantUML
。下列這張圖
即是依據以下的源代碼生成的
@startuml left to right direction actor 員工 as yg actor 顧客 as gk actor 餐廳員工 as ctyg actor A2 as a2 actor 送餐員 as scy rectangle cos { note "沒註冊工資\n支付的採用\n送餐時收費" as mzc usecase 查看菜單 as ckcd usecase 註冊 as zc usecase 登陸 as dl usecase 訂餐 as dc usecase "預定/覆蓋預定" as yy usecase 備餐 as bc usecase 請求送餐 as qqsc usecase 記錄送餐 as jlsc usecase 打印送餐說明 as dyscsm usecase 記錄收費 as jlsf zc .> dl : <<extends>> dl .> dc : <<extends>> } actor A1 as a1 note bottom of a1 : 已註冊工資支付 yg <|-- gk gk <|-- ctyg ctyg <|-- a2 ctyg <|-- scy yg -- ckcd yg ---- zc yg --- dl gk -- dc gk ---- yy ctyg -- bc ctyg --- qqsc scy -- jlsc scy --- dyscsm scy -- mzc jlsf -- mzc @enduml
比較遺憾的是,PlantUML
自動排版的結果顯得不那麼整齊,左下角有一個明顯的三角形空白區域——這也是DSL大法的一個缺點,即沒法完美地控制最終的排列效果。
最開始接觸UML的時候,學習的即是類圖——儘管接觸得最先,畫得卻最少。比起類圖,ER圖反而畫得更多一點。
若是要畫類圖,首選的工具是mermaid
。跟PlantUML
同樣,mermaid
也是一個大而全的東西,除了畫UML類圖,也能夠畫流程圖、時序圖,以及UML狀態圖等。下面這張圖
即是mermaid-cli
依據以下的源代碼生成的
classDiagram Image <|-- BMP Image <|-- GIF Image <|-- JPEG Image: +setImpl() Image: +parseFile() ImageImpl <|-- WinImpl ImageImpl <|-- LinuxImpl ImageImpl: +doPaint() Image ..> ImageImpl
Emacs用戶能夠安裝mermaid-mode
,VSCode用戶則可使用Mermaid Preview這個插件,來輔助編輯mermaid
的源文件。
方纔提到的mermaid-cli
是一個命令行程序,用於在本地根據mermaid
的源文件產生PNG格式的圖片,安裝也很簡單
npm install -g mermaid.cli
還有許多的圖能夠用DSL來繪製,感興趣的讀者能夠到mermaid
或PlantUML
的官網瞭解一番,這裏再也不一一舉例。
用DSL來繪圖有一些優勢:
但也有一些缺點:
就像軟件開發中沒有銀彈同樣,畫圖工具也沒有萬金油,關鍵仍是要因地制宜地選擇最合適的工具來解決眼前的問題。