Categories
程式開發

文檔代碼化實踐


文檔代碼化,將文檔以類代碼的領域特定語言的方式編寫,並藉鑑軟件開發的方式(如源碼管理、部署)進行管理。它可以藉助於特定的工具進行編輯、預覽、查看,又或者是通過專屬的系統部署到服務器上。面向非技術人員的文檔代碼化的一種常見架構模式是:編輯-發布-開發分離

最近一個月裡,我在開發一個基於 Git + Markdown 的全新文檔系統。我定制了一個基於 markdown 的標記語言,以支持起雷達圖、條形統計圖、思維導圖等圖表的文檔系統。這個系統將在未來幾個月內發布。當然了,視進度而看,也可能是月底。

過去的幾年裡,我們一直在討論各種各樣的代碼化,基礎設施代碼化、設計代碼化、需求代碼化……。在我的那一篇《雲研發:研發即代碼》中,設計了一個完全代碼化的軟件開發流程。而今天我們將討論另外一個有趣的存在:文檔。

在《架構金字塔》中,我將文檔定義為支撐五層架構模型的一種存在。因為文檔在一個系統中是非常重要的存在,我們用它來指導開發工作,用它來記錄問題,用它來寫下規範……。總而言之,它很重要,所以我們重新討論一下這個話題。

引子 1:架構決策記錄:格式化文檔

三年前,當我第一次接觸到『架構決策記錄』的概念時,我被它的理念所吸引:

  • 使用輕量級文本格式化語言描述重大決策
  • 跟隨代碼一起版本化
  • 使用某種特定的文檔格式(標題、上下文、決策、狀態、後果)

隨後,我使用 Node.js + TypeScript 寫了一個 ADR 工具。現在,在我的大部分開源薦中,我都會使用它來管理一些技術決策。因為基於這個理論設計的這個文檔系統真非常棒,我可以查詢到:

  • 一個技術決策發生的時間和架構改變,對應的修改人
  • 回溯所有的技術決策,從中整理出架構發展過程
  • 所有的決策都是記錄在版本控制系統中,可恢復
  • 易於管理和維護

對於一個長期開發的系統來說,它真的非常有用。

引子 2:靜態站點生成:數據代碼化

靜態站點生成是一種混合式的 Web 開發方法,它通過部署預先構建的靜態文件進行部署,來讓開發者在本地構建基於服務器的網站。

當 GitHub Pages 成為了程序員首選的 博客/內容/文檔 服務器時,他/她也採用了靜態站點生成這一項技術。靜態站點生成有各種各樣的優點:

  • 可靠性、安全性、穩定性、可用性等更好
  • 可版本控制
  • 易於測試
  • 易於實踐持續部署。提交即可上線
  • 靈活,易於定制

而事實上,靜態站點生成所做的最主要的一件事是:將數據庫中的數據進行代碼化。採用諸如 WordPress 這樣的 CMS 時,我們是將數據存儲在數據庫中,以實現對於數據的 CRUD。一篇文章變為數據庫二進製文件中的一個片段。

隨後,靜態站點生成工具做了第二件事情便是將文本內容可視化出來,便於人們閱讀。這樣一來,我們便實現了發布-開發分離。

引子 3:定制的標記語言:擴充

將數據代碼化時,我們面臨了一個非常大的挑戰:易於編寫、閱讀的標記語言(如markdown)只設計了內容的形式,缺少了內容相關的其它信息,諸如於創建時間、作者、修改時間等等。

於是各個靜態站點生成器定制了自己的 markdown,添加了一些額外的信息,如 hexo 採用 :year-:month-:day-:title.md 的形式來管理文章的日期和標題等。這樣一來說,就不需要通過讀取這個文章的 Git 信息來構建出整個信息。

我們所熟悉的 GitHub Flavored Markdown 也是如此,通過不明顯破壞內容格式的兼容模式來擴展 markdown 數據字段。

除此,我們可以定制基於 markdown 數據的圖表、思維導圖等內容。

引子 4:編輯-發布-開發分離:面向非技術人員

面向非技術人員設計是代碼文檔化的一大挑戰。作為一個程序員,我們覺得 markdown 語法再簡單不過了,但是對於非技術人員來說並非如此。他/她需要:一個易於上手的可視化編程器。而要實現這樣一個目的,我們需要在架構上做一些轉變,我們可以嘗試使用 『編輯-發布-開發分離』 模式來解決這個問題。

即,我們將過程拆為了三步:

  • 編輯人員,可以使用常用的編輯器或者是定制的編輯器
  • 開發人員,編寫內容的展示
  • 發布的時候,集成這兩部分代碼

我們依舊可以選擇用源碼管理的方式來管理內容。只需要將數據庫接口,轉變為 Git 服務器接口即可 —— 當然它們是稍有不同的。不過呢,把本地的 Git 轉換為 Git remote 那就基本一致了。

如此一來,最後我們的成本就落在改造出一個基於 Git 的 markdown 編輯器。

文檔代碼化

完美,我又一次在引子裡,把中心思想表達完了。

為什麼你需要將文檔代碼化?

主要原因有:文檔不代碼化,就沒有重構的可能性。

剩下的原因有:

  • 二進制的文檔難以進行版本管理。想像一下 2020-02-30.docx2020-02-31.docx
  • 無法準確地知道誰是文檔的修改者,大家可能都是 admin,又或者是會議上的張三
  • 找不到哪個是最新的文檔
  • 文檔寫得很爛,但是你沒辦法重構二進製文檔
  • 供應商綁定
  • ……

應該還有更多。

什麼是文檔代碼化?

回到正題上:

文檔代碼化,將文檔以類代碼的領域特定語言的方式編寫,並藉鑑軟件開發的方式(如源碼管理、部署)進行管理。它可以藉助於特定的工具進行編輯、預覽、查看,又或者是通過專屬的系統部署到服務器上。

它具備這麼一些特徵:

  • 使用標記語言編寫內容。如 markdown
  • 可通過版本控制系統進行版本控制。如 git
  • 與編程一致的編程體驗(除了內容寫不了測試)

而一個高效的文檔代碼化系統,還具備這麼一些特徵:

  • 持續部署,即修改完內容可自動發布。
  • 與特定的形式組織內容索引。如以知識庫的形式來組織內容。
  • 特定的文本格式。如架構決策記錄、靜態內容生成,以用於以提供更好的用戶體驗
  • 可支持 REST API。以通過編輯器來修改內容
  • 可以支持多種方式的輸出。如網站標準 HTML,又或者是 Docx、Latex 等
  • 支持編輯、校對工作流
  • 支持搜索
  • 多人協作

而事實上,大部分的團隊並不需要上述的高級功能,而且它們都已經有了成熟的方案。

如何設計一個文檔代碼化系統?

事實上,我們在四個引子中標明了我們所需要的要素:

  1. 使用格式化的文檔
  2. 借助靜態站點生成技術來發布系統
  3. 通過定制標記語言擴充能力
  4. 面向非技術人員實現編輯器

設計一個標記語言及其擴展語法,然後實現它即可。

1. 確立關鍵因素

考慮到我和我的同事們最近實現了這麼一個系統,我還是忍受一下手的痛楚,簡單說一下怎麼做這樣一個系統。我們所考慮的主要因素是:

  • 圖表渲染
  • 流程圖渲染
  • 可視化展示

因為由 DSL 轉換成的圖表易於修改,並且可以索引。於是乎,我們:

  1. 通過 markdown 的 Code 語法來擴充這些能力
  2. 使用 markdown 的 table 和 list 來提供數據
  3. 使用 D3.js 來支持流程圖繪製
  4. 使用 Echarts 來進行圖表繪製
  5. 盡量使用 SVG 圖片
  6. ……

2. 實現一個 MVP

我們使用 Angular + GitHub,快速實現了一個 MVP:

  1. 我們使用 Git 作為數據庫.它就可以實現多人協作的目的,並且可以追踪所有的變化
  2. 我們使用 GitHub Pages 作為服務器。只要一修改文檔或者代碼,就會部署最新的文檔。
  3. 我們使用 marked.js,它可以讓我們快速擴展語法。
  4. 使用 textarea 結合 markdown 製作了一個簡易的編輯器。

隨後,我們在這個基礎上進行了快速的迭代。

3. 擴展語法

我們使用了 markdown 的 code 作為圖表的 DSL,擴展了這麼一些語法:

  • echarts。直接渲染 Echarts 圖表

  • mindmap。 Markdown List 轉為思維導圖

  • radar。 Markdown List 轉為雷達圖

  • process-table。帶流程的圖表

  • process-step。另外一種帶流程的圖表

  • pyramid。金字塔圖形

  • quadrant。四象限圖

  • class。直接調用 CSS 的 class

  • graphviz。使用 Dot 渲染圖片

  • mermaid。使用 mermaid 可視化

  • webcomponents。調用 WebComponents 組件

  • toolset。調用 Toolset 相關的組件

    • slider。權衡滑塊
    • line-chart。表圖

所以,對於使用者來說,只需要編寫下面的代碼:

1. `````radar``
2.  `- 质量成熟度评估模型`
3.  ` - 质量内建: 3 -> 4`
4.  ` - 优化业务价值: 2 -> 2`
5.  ` - 质量统一,可视化: 1 -> 5`
6.  ` - 全员参与: 3 -> 4`
7.  ` - 快速交付: 4 -> 5`
8.  ` - 测试作为资产: 2 -> 3`
9.  ` - 快速反馈: 5 -> 5`
10.  ``
11.  `config: {"legend": ["当前", "未来"]}`
12.  `` `````

就可以生成對應的圖表:

文檔代碼化實踐 1

我們還通過 config 來輸入 JSON,進行一定的懶惰化處理(不要累死自己)。

3.1 重寫 markdown 渲染器

我們在這個過程中,遇到的最大的挑戰是,隨著我們對 markdown 語法的不斷擴充,相關的代碼已經變成了一坨大泥球。所以,我們不得不重寫了這部分代碼:

  1. 借助於 marked.js 的 lexer 解析出 token
  2. 根據 token 修改生成新的 token
  3. 遍歷新生成的 token,渲染出元素
  4. 結合虛擬滾動,解決性能問題

已經開源在 GitHub,並發布對應的 npm 包:@ledge-framework/render

4. 發布這個項目

我們已經在 GitHub 上發布了這個文檔化系統,你可以參與到其中的使用和開發。

GitHub

項目首頁

總結

然後,你就成為了一個 Markdown 工程師,D3.js 設計師,Echart 配置管理員。

本文轉載自zybuluo技術網站。

原文鏈接:https://www.zybuluo.com/phodal/note/1687776