活文档总结
幾年前在 oreilly 看到一本叫 《living documentation》的書,可惜當時爛尾了。
最近圖靈出版了該書的中文翻譯版,才想起來有這么回事。。。正好最近有時間,把這個坑了幾年的東西給填上了。
簡單來說,這本書基本可以叫 living java doc(誤。我們可以先看看日常開發中會涉及到哪些文檔:
需求文檔
接口文檔
業務詞匯表文檔
模塊業務流程文檔
系統間交互文檔
系統架構文檔
系統依賴文檔
發布文檔
示例文檔(tutorial)
項目進度文檔
案例文檔
匯報文檔
要寫的類型文檔還是不少的,無論哪種文檔,都與項目的代碼是脫節的。所以軟件行業以往的文檔編寫方式有很多缺點:
文檔易過時,因為與代碼是分開的,改了代碼忘改文檔是很正常的,代碼是新版本,而文檔是歷史版本
文檔誤導人,因為前一條,功能上的修改沒有反映到文檔上,讀文檔的人會被錯誤信息所誤導
多余的工作量,工程師在寫完代碼之后還要再去寫一遍文檔(也可能是先寫文檔后寫代碼),基本是雙倍工作量
文檔的編寫工具無統一的規范,大家喜歡不停地嘗試新工具,從 word 到 markdown 到 asciidoc 到 notion
文檔與真實的代碼內容是脫節的,比如在 DDD 中常講的業務詞匯表,在文檔與代碼中可能用的不是同一個詞,編碼和看文檔的時候需要腦內額外做映射
為了克服這些缺點,這本書提出了一些讓代碼變 living 的方法。既然代碼和文檔分開使得兩者不易統一,那么我們就去追求把代碼與文檔寫在一起,并通過技術手段把文檔從代碼中生成出來。
live_doc上面提到的幾種文檔,挨個來看看:
需求文檔
因為需求最終會變成 BDD 測試,所以可以直接用 BDD 測試來生成這些需求文檔。
詞匯表
用 DDD 來做業務的話,一般可以用一些一眼就能看出含義的詞對類型和接口做注解:@DomainService,@DomainEvent,@BusinessPolicy,@AbastractFactory,@Adapter,@BoundedContext,@ValueObject。
同時為了強調一些業務概念,也可以用一些自定義的詞匯,比如:@CoreConcept,@CoreBehavior,@StateMachine。
然后通過掃描代碼,就可以直接把項目中的上述概念抽出,每次代碼有更新,能夠自動生成業務的詞匯表。
自動接口文檔
這個應該很多人也見過了,就是類似 swagger 的項目。框架做的好的企業基本也都會有基于類似 swagger 的手段來做自己的接口平臺(其實做的好的沒幾個)。下面是在 beego 中使用 swagger 的例子:
swagger因為 Go 語言不支持 annotation,所以這些在注釋里寫的注解沒有語法層面的檢查和約束,這點上可能比那些支持的語言算是個弱勢。
業務流程文檔
在代碼中編寫相應的流程節點和前后關聯節點:
business_process通過掃描代碼生成文檔:
business_process2跨系統的交互流程:
business_process3掃描生成相應的文檔,其實和前面的差不多:
business_process4除了上面這些風格的注解,以前就已經存在從文本生成文檔的手段,比如 plantuml,graphviz
plantuml上圖這樣的 plantuml 的文本,本身就可以和代碼一起在同一個代碼倉庫中進行管理。
在一些業務邏輯中,涉及到難懂的邏輯,可以用 @Policy 或者 @BusinessConvention 來說明相應的業務決策原因。
發布文檔
現在 Github 上的很多開源項目,已經可以根據 commit message 自動生成 release note 了。這歸功于其 commit message 本身就有一定的規范:
commit_msg只要用簡單的 bash 腳本就可以將兩個版本之間的 commit message 進行匯總,并寫出完整規范的 release note。
國內不少開源項目現在還是人肉寫 release note 的。
tutorial
新人入職需要看一些代碼范例,如果項目內有寫的規范的代碼,可以專門挑出來作為例子:@Exemplar(“這個訂單流程是一個很好的 CQRS 學習示例”)。掃描代碼找到所有的 @Exemplar 注解就可以成為 tutorial 文檔了。
穩定文檔
穩定文檔指的是那些基本不怎么變動的文檔,這種文檔和代碼分開是可以接受的,為了使我們的文檔穩定,應該遵循一些基本的編寫原則,比如:
不要帶公司的那些容易變化的信息:公司名,子公司,品牌,商標等等
如果在文檔中附帶有鏈接,應該從非穩定文檔指向穩定文檔,比如你可以從自己的 blog 貼一個 wikipedia 的鏈接,但是如果你去編輯 wiki 并粘貼了個人獨立 blog 的鏈接,那么可能就不太合適
不要復制粘貼,盡量用鏈接引用原有內容
匯報文檔
如果是項目進度相關的內容,可以用 @wip 或 @pending 之類的注解。
如果是給老板展示的案例,老板忙的沒時間,所以可以用 @keyexample 把這些需要單獨展示的案例摘出來,
如果是給新人學習的,除了前面說到的 tutorial,還可以有 @normalcase,@specs 等。
架構文檔
一種是單模塊架構,常見的是 DDD 中的六邊形架構,可以引入 DDD 中的關鍵詞,并生成最終的文檔,比如 @HexagonalArchitecture.DomainModel,@Adapter,最終生成的文檔是下面這樣的:
hex如果是跨系統的文檔,比如 CQRS 之類的,本身也是 Given(event),When(cmd),Then(output event) 的形式,所以用 BDD 可以生成這樣的文檔,前文有提到。
運行時文檔
作者認為 zipkin 和 dapper 這種 tracing 系統也是一種形式的文檔。服務發現系統中繪制出的服務依賴也是一種文檔。
聲明式配置
聲明系統配置、資源需求、依賴的,也可以生成文檔。
從這個意義上講 k8s 的 yaml 既是文檔,也是代碼。
架構全景圖
當我們可以將所有文檔都通過掃描代碼生成之后,最好能夠將這些文檔管理在統一的架構全景圖中,相應的全景圖可能也可以用一些注解的輔助手段來生成,比如 @Layer(LayerType.INFRASTRUCTURE),@Repository(aggregateRoot = Customer.class)。
總結
- 上一篇: 改来改去把微服务改成了分布式单体
- 下一篇: 深度阅读之《Mastering Go》