只懂 Git 如何成為架構磚家?從代碼的物理分析說起
物理分析這一詞,來源于我同事 @NoaLand 所推薦的《大規模 C++ 程序設計》一書中所介紹的物理設計。
物理設計集成于研究系統中的物理實體,及它們之間如何相互關聯。邏輯設計只研究體系結構(架構)問題,物理設計研究組織問題。
在粗粗了這本書的一些概念之后,我對整體的物理設計思路有更深入的了解。于是,在結合了《系統重構與遷移指南》一書中引入的『四級重構』,重新論證了我先前的一個想法:并不需要成為 xx 語言的熟練開發者,我也能分析這個語言的系統設計得是否合理?(PS:這是建立在我已經熟練使用多門語言 Copy/Paste 的前提下。)
于是乎,只需要學會對物理設計進行分析,就能成為架構上的磚家 —— 對于這部分的分析,是個程序員都會做。
而一系列的理論建立在幾個基本的前提之下:
- 代碼組件方式使用文件系統的方式組件。即包和組件使用文件夾管理等。
- 項目使用的是 Git,絕大多數的 Git 修改都是自然發生的,即技術需求和業務需求。
- 項目所使用的是主流的企業開發語言。如 Java、Golang、JavaScript/TypeScript、C#、C++ 等,而不是 Haskell 等。
這里,我們使用的分析工具是 Inherd 開源小組開發的研發效能分析工具 Coco,GitHub:https://github.com/inherd/coco。
文中使用的是 Redis 案例在線版本見:https://inherd.org/cases/redis/
“物理”架構設計
我們所熟知的包,可以定義為:一個包就是被組織成一個物理內聚單位的組件集合。而包的呈現形式便是文件夾,其中的一個個物理單元就是文件。通過對文件的修改的監測,我們可以知道文件夾的變化,進而觀測到整個包的變化。
通過這些物理上的變化,我們可以知道一個包是否是穩定的,從它的大小,我們還能知道整體的設計是否合理。如下是 自 2020.3.1 號起, Redis 中不同模塊的源碼變化情況:
Redis Changes
(PS:該圖是交互式的網頁。左側的五彩斑斕部分是 src/,也就是主要源碼,右側是依賴的了模塊,上方是測試模塊的變化。)
從上圖中:
觀測頻繁修改模塊。可以清晰地看到哪個模塊變化較多。對于業務代碼來說,我們則可以通過時間軸的大小,來觀測不同時代段的修改。
了解包的大小。如圖中的 redis-cli.c:41,其中的 41 是自 2020.3.1 起的修改次數,hover 在上面之后,可以知道這個文件的行數為 7012 行。
根據我們《系統重構與遷移指南》定義的高引用、高修改的關系:
高引用-高修改
我們也可以建議一個輕微地模型(不會那么準確),來證明一個長行數 + 頻繁修改這是一個非常不穩定、容易出錯的包。而在業務場景之下,如果我們實現的一個功能,為于 A 業務之下,但是一直在修改 B 業務,那么說明引用是不正確的,存在一定的耦合度。
變更頻率
變更頻率是一個非常有意思的指標,從版本管理工具中,我們可以獲得歷史上發生的一些變化。從結論上來說,我們常知道的一些事實有:
- 隨著代碼行數的上升,新增代碼的占比會越來越少,修改成本也越來越高,因此提交量會呈一定的下降趨勢。
- 軟件開發是周期性的活動。修改頻率與軟件發布成正比例關系。
下圖展示的是 Redis 的所有提交與時間的關系:
Redis Commit Contributions
從圖上來看,在 2014 ~ 2015 之前發生了大量的代碼提交。與它與后面的發布頻率,做一個對比,我們就會發現這一段時間發布了大量的新版本。從這些現象來看,它可能意味著:
- 在這段時間引入了大量的功能。
- 因為過多的功能,并因此引入了大量的 bug,所以需要更多地版本發布。
除此,另外一個不是那么有意思的指標就是行數上的變化:
Redis Line History
從圖中我們可以看到在 2011 ~ 2012 這個時間點上,代碼量突然發生了劇烈的變化。其中原因,我想就是因為他們所采用的是 feature branche 的機制。即,功能在開發完成后,才會合并到主分支。
從下面的發布頻率中,我們也可以看到這個變化的趨勢。
發布頻率與部署
從 Git 中想看到發布頻率相關的內容,只能從以下兩部分:
- 分支。可以展示分支的使用情況,以及不同分支的變化。
- Git Tag。展示軟件的發布頻率與時間等的關系。
如下是 Redis 的分支歷史:
Redis Branches
從圖中,我們可以清晰地看到 Redis 的不同特性地開發,如 arm,如 acl-log。除此,還有不同版本的維護情況,如 2.8 的修改在 3.0 之后。
同樣的,因為 Redis 采用的是標準的 Git 實踐來發布軟件。所以,從 2019 年的 tags,我們可以看到軟件的整體發布情況:
Redis Tags
咦,從上圖來看,這個是 6.0 是不是來得非常快。沒有 5.1.x 就直接 666 了。
學習成本與知識管理
軟件開發是一個知識生產和消費的過程。—— 《軟件開發管理為什么這么難》
在一個項目的不同時期(技術準備、業務回補、成長優化、架構演進),其對于不同級別的開發人員的難度都是不一樣的。這一點從理論上來講,我們可以從分析其的提交資料,來分析它的學習成本。開發人員的提交量會隨著在項目的年限逐漸變多,直到趨于穩定。
于是,我們嘗試從 Redis 項目里建立這個模型:
Redis Curve
然后失敗了。后來,發現這個模式并不適合于開源項目。
與商業軟件相比,開源軟件的更加動態,團隊的生命周期很少超過六個月,并且常常會以各種方式重組。——《軟件之道:軟件開發爭議問題剖析》
但是,我們相信它對于常規的軟件開發團隊是適用的。
隨后,我們再正視了一下這個問題,重新考量了適合于開源項目的模型 —— 通過人員在項目的提交時間,來看一個項目是否穩定,知識傳播是否靠譜。
如下是 Redis 項目中,開發人員的第一次提交時間和最后一次開發時間產生的 timeline:
Redis Members
它從側面反應了,開源項目的團隊模式,只有少數的開發人員。對于商業軟件來說,如果 timeline 如上的話,那么這個軟件仍然能夠開發下去。但是,如果核心開發人員離開團隊,項目將非常不穩定,那么這個軟件將充斥著大量未知的 bug。
其它
這樣一看,Coco 是不是降低了架構分析的門檻。歡迎試用 Coco,可以從 GitHub 直接下載:https://github.com/inherd/coco/releases
文中說的一些分析內容,已經在我之前的另外一分析工具 Coca 中引入過。但是,受限于語法分析的成本,所以在 Coco 中采用了輕量級的分析方式。我們會在后續的文章中,介紹更多想多的實現方式。你也可以通過添加微信號 phodal02 (注明 Inherd),參與到相關的討論中。
文中使用的是 Redis 案例在線版本見:https://inherd.org/cases/redis/
相關資源:
《Introducing the Polyglot Code Explorer》
《Your code as a crime scene》
本文轉載自微信公眾號「phodal」,可以通過以下二維碼關注。轉載本文請聯系phodal公眾號。