如果要接手一個(gè)已經(jīng)運(yùn)行了好幾年的軟件項(xiàng)目,那么怎樣才能得到對(duì)項(xiàng)目開(kāi)發(fā)歷史的認(rèn)識(shí)呢?最好的方法可能就是與曾經(jīng)參與該項(xiàng)目的開(kāi)發(fā)人員對(duì)話,但是這說(shuō)起來(lái)容易,做起來(lái)卻很困難。原有的開(kāi)發(fā)人員通常都已轉(zhuǎn)到了其他項(xiàng)目中,而且要找到他們也很難。您可以查看釋出頻率(release frequency),盡管這可能受非技術(shù)性的強(qiáng)制規(guī)定控制(有時(shí)可能只是出于“我們要在本財(cái)政年度末做一個(gè)發(fā)布”的理由)。您可以查看 bug 和特性請(qǐng)求跟蹤器,還可以在開(kāi)放和關(guān)閉的 bug 討論中挖掘信息?;蛘呖梢灾苯舆M(jìn)入源代碼歷史記錄,用 StatCVS 這樣的工具查看曾做過(guò)哪些記錄,這些記錄是誰(shuí)修改的。我將 StatCVS 運(yùn)用在各種大型項(xiàng)目上已經(jīng)有好幾年的時(shí)間了,它生成的報(bào)告一直都很不錯(cuò)。在本文中,將演示如何在項(xiàng)目上設(shè)置、運(yùn)行 StatCVS,如何閱讀它生成的報(bào)告,以及 StatCVS 需要改進(jìn)的地方。
安裝 StatCVS
StatCVS 是一個(gè) Java 程序,需要 JDK 1.4 或更高版本的支持。從命令行安裝 StatCVS 最容易:只要下載最新的發(fā)行版,將它解壓到一個(gè)目錄中即可;我用的是 /usr/local/statcvs/ 目錄。而且,如清單 1 所示,我還創(chuàng)建了一個(gè)符號(hào)鏈接,叫作 statcvs
,它鏈接到剛剛安裝的版本上。這可以節(jié)約日后的一些打字工作時(shí)間,更重要的是,日后只要把符號(hào)鏈接修改為指向要使用的版本,就可以在 StatCVS 的不同版本間切換。
|
如果列出 statcvs 目錄中的文件,就可以看到那里沒(méi)有任何適用于 StatCVS 的支持 JAR 文件(supporting JAR file)。惟一的 JAR 文件是 statcvs.jar,它包含 StatCVS 使用的惟一的第三方庫(kù):JFreeChart。這種方法使得開(kāi)始了解 StatCVS 變得更容易,因?yàn)椴恍枰P(guān)于類(lèi)路徑的更多知識(shí)。
運(yùn)行 StatCVS
為了演示 StatCVS 的工作方式,需要找到一個(gè)帶有有趣的 CVS 歷史記錄的項(xiàng)目,并生成一些活動(dòng)報(bào)告。developerWorks 的項(xiàng)目 Jikes 已經(jīng)進(jìn)行了一段時(shí)間,有大量開(kāi)發(fā)人員,還有一個(gè)公共的 CVS 儲(chǔ)存庫(kù),所以它是一個(gè)好例子。
從 CVS 中獲得源代碼
為了從 StatCVS 得到 Jikes 的報(bào)告,需要得到最新的源代碼,并生成一個(gè) CVS 日志文件讓 StatCVS 分析。所以,需要從 Jikes 的 CVS 儲(chǔ)存庫(kù)簽出它的源代碼。Jikes 的開(kāi)發(fā)人員允許擁有只讀權(quán)限的匿名用戶(hù)對(duì)其儲(chǔ)存庫(kù)進(jìn)行訪問(wèn),所以可以用這個(gè)方法得到源代碼,如清單 2 所示:
|
創(chuàng)建 CVS 日志文件
現(xiàn)在機(jī)器上已經(jīng)有了 Jikes 代碼,需要?jiǎng)?chuàng)建一個(gè) CVS 日志文件供 StatCVS 處理。要?jiǎng)?chuàng)建這個(gè)文件,需要進(jìn)入 jikes 目錄,運(yùn)行 cvs log
命令。正如從清單 3 中看到的,我把命令的輸出重定向到了一個(gè)叫作 logfile.txt 的文件:
|
只是為了好玩,我對(duì)此進(jìn)行了計(jì)時(shí)。在我的工作站上,這大約花費(fèi)了 40 秒的時(shí)間,生成的日志文件大小約為 3.3 MB。
命令行界面
現(xiàn)在可以運(yùn)行 StatCVS 生成報(bào)告了。可以從命令行運(yùn)行 StatCVS,也可以從 Ant 運(yùn)行。首先來(lái)看一下命令行界面,然后再來(lái)討論 Ant。
StatCVS 從命令行運(yùn)行很容易,因?yàn)橹挥幸粋€(gè) JAR 文件,而且可以把 JAR 文件名直接傳給虛擬機(jī)??梢杂貌煌倪x項(xiàng)控制輸出。這里是一些比較有用的選項(xiàng):
-title [標(biāo)題]
—— 放在報(bào)告上的顯示標(biāo)題。
-output-dir [目錄](méi)
—— 報(bào)告文件存放的位置;如果目錄不存在,則自動(dòng)創(chuàng)建該目錄。
-include [模式]
—— 只包含與指定模式匹配的文件。
-viewcvs [ViewCVS url]
—— 儲(chǔ)存庫(kù)的 ViewCVS Web 界面的 URL。
下面用以上選項(xiàng)創(chuàng)建報(bào)告。首先,必須移動(dòng)到 jikes/ 目錄上,然后從命令行運(yùn)行 StatCVS,如清單 4 所示:
清單 4. 從命令行運(yùn)行 StatCVS
|
注意,上面使用了 -include
參數(shù),只捕獲 C++ 源代碼文件和頭文件。在 CVS 模塊中有許多其他文件(文檔、配置腳本、報(bào)告、Web 頁(yè)面等),但是本文只關(guān)心源代碼。
Ant 任務(wù)
清單 5 顯示了與清單 4 的命令行調(diào)用功能相同的 Ant 任務(wù)定義:
|
圖表和圖形
報(bào)告放在清單 4 指定的報(bào)告目錄中。如果用瀏覽器打開(kāi)該目錄中的 index.html 頁(yè)面,該頁(yè)面如圖 1 所示:
圖 1. Jikes 的 StatCVS 主報(bào)告頁(yè)面
可以看到可用報(bào)告的分類(lèi):關(guān)于代碼作者的一些統(tǒng)計(jì)數(shù)據(jù)、查看提交日志、代碼段的行,以及關(guān)于文件和目錄大小的一些統(tǒng)計(jì)。
代碼行
代碼行圖表如清單 2 所示,它可能非常有趣:
圖 2. Jikes 一段時(shí)間內(nèi)的代碼行數(shù)
從這個(gè)圖表中可以看出,代碼最初是在 1999 年初導(dǎo)入的。從那以后,它增長(zhǎng)得非常穩(wěn)定,一直到 2001 底,那時(shí)代碼的數(shù)量開(kāi)始略有下降。還有幾次,新的代碼被引入或者舊的代碼被重構(gòu)出去,這些可以從代碼行計(jì)數(shù)的急劇升降上表現(xiàn)出來(lái)。從 2004 年開(kāi)始,似乎沒(méi)有加入太多代碼,這可能表明 Jikes 已經(jīng)成熟到了某種程度,主要對(duì)它做些維護(hù)工作即可。
如果從主報(bào)告頁(yè)上單擊 Authors 鏈接,就可以看到數(shù)字和圖表,它們指出每個(gè)參與者貢獻(xiàn)了多少代碼,如圖 3 所示:
很明顯,ericb 和 shields 對(duì) lion 負(fù)責(zé)的代碼有所貢獻(xiàn),而其他參與者也偶爾參與其中。注意,沒(méi)有任何一個(gè)參與者從頭到尾都參與了該項(xiàng)目。這個(gè)事實(shí)清楚地證明:長(zhǎng)期項(xiàng)目需要那些擁有良好變量名和干凈設(shè)計(jì)的清晰代碼。
偶爾,StatCVS 在生成報(bào)告時(shí)表現(xiàn)得更聰明。如果 CVS 儲(chǔ)存庫(kù)只有一個(gè)參與者,那么主報(bào)告頁(yè)上的鏈接只會(huì)寫(xiě)上“Author page for joe_smith”,而且不會(huì)生成比較圖表。這樣 StatCVS 會(huì)運(yùn)行得更快,報(bào)告頁(yè)也會(huì)更整潔。
現(xiàn)在再來(lái)看一個(gè)參與者的活動(dòng)圖表。在主報(bào)告頁(yè)面上,單擊 Authors 鏈接可以訪問(wèn) Author Activity,如圖 4 所示,圖中顯示了每個(gè)參與者是添加了文件,還是修改了文件:
您可以看到,shields 添加了大多數(shù)代碼,這在預(yù)料之中,因?yàn)檫@個(gè)人顯然是代碼導(dǎo)入 CVS 之后的第一個(gè)維護(hù)者。同樣,ericb 在項(xiàng)目啟動(dòng)之后幾年之間一直進(jìn)行類(lèi)似的工作,主要在修改文件。
提交日志
提交日志(Commit Log)僅僅是對(duì)模塊做的全部修改的一個(gè)列表。這個(gè)報(bào)告顯示了誰(shuí)做了修改,以及提交者在所做修改上附加的注釋。而且,因?yàn)?Jikes 的儲(chǔ)存庫(kù)中有一個(gè) ViewCVS 界面,運(yùn)行 StatCVS 時(shí)還使用了一個(gè) -viewcvs
參數(shù),所以報(bào)告中包含了到已實(shí)際修改的源代碼的鏈接。例如,在 2004 年 12 月 12 日,src/decl.cpp
有一個(gè)改動(dòng)。如果點(diǎn)擊 decl.cpp,會(huì)看到添加了一個(gè) if
語(yǔ)句,還有一個(gè)注釋。圖 5 顯示了 ViewCVS 的一部分,展示了兩個(gè)文件版本之間的差異:
還有其他一些報(bào)告:一個(gè)報(bào)告顯示了平均文件大小,另外一個(gè)顯示了如何通過(guò)目錄樹(shù)分布代碼,還有一個(gè)則顯示了哪個(gè)文件的版本改動(dòng)最多。Jikes 的整個(gè)報(bào)告可以通過(guò)單擊本文頂部或底部的 代碼 圖標(biāo)得到。只要將它解壓,并用瀏覽器打開(kāi) index.html,就可以看到這個(gè)報(bào)告。
為多個(gè)項(xiàng)目生成報(bào)告
前面已經(jīng)看到了如何在一個(gè) CVS 儲(chǔ)存庫(kù)上運(yùn)行 StatCVS。但是,如果擁有多個(gè)儲(chǔ)存庫(kù),那么您就會(huì)希望有一種方法能夠每天夜里為所有的儲(chǔ)存庫(kù)生成 StatCVS 報(bào)告。因?yàn)榭梢詮拿钚羞\(yùn)行 StatCVS,所以這是一個(gè)用腳本就可以解決的簡(jiǎn)單問(wèn)題。以下是一些需要牢記的事項(xiàng):
- StatCVS 是一個(gè) Java 程序,所以需要大量?jī)?nèi)存才能啟動(dòng)。處理大型 CVS 儲(chǔ)存庫(kù)時(shí)也需要相當(dāng)一段時(shí)間。所以如果運(yùn)行它的機(jī)器還有其他用途,那么最好在處理不同的儲(chǔ)存庫(kù)之間讓機(jī)器休息一會(huì)。如果運(yùn)行的系統(tǒng)支持優(yōu)先級(jí)設(shè)置,那么用低優(yōu)先級(jí)來(lái)運(yùn)行耗時(shí)比較長(zhǎng)的任務(wù)是一個(gè)好主意。
- 如果定期將儲(chǔ)存庫(kù)添加到機(jī)器或從機(jī)器中刪除儲(chǔ)存庫(kù),那么某些儲(chǔ)存庫(kù)可能不包含模塊。所以請(qǐng)事先檢測(cè)這種可能性,免得沒(méi)有必要地啟動(dòng) StatCVS。
清單 6 顯示了一個(gè)小小的 Ruby 腳本,可以在擁有公共父目錄的多個(gè)儲(chǔ)存庫(kù)上運(yùn)行 StatCVS;在下載代碼中也有這個(gè)腳本:
清單 6. 運(yùn)行 StatCVS 處理多個(gè)儲(chǔ)存庫(kù)的腳本
|
StatCVS 內(nèi)幕和限制
因?yàn)?StatCVS 是一個(gè)開(kāi)源項(xiàng)目,所以您可以得到它的代碼。要得到 StatCVS 的代碼,請(qǐng)從 StatCVS 的頁(yè)面下載源代碼 zip 文件,或者從這個(gè) Web 站點(diǎn)上的 CVS 儲(chǔ)存庫(kù)簽出代碼。
內(nèi)幕
這里是一些關(guān)鍵的統(tǒng)計(jì)數(shù)字:
- 4,463 行代碼,由 JavaNCSS 測(cè)量。
- 176 個(gè) JUnit 測(cè)試。
- 一個(gè)很好的 Ant 構(gòu)建文件,可以促進(jìn)定制構(gòu)建的編輯。
- 一個(gè)好標(biāo)志 —— PMD 在 StatCVS 中找不到未使用代碼的例子。
StatCVS 用 JFreeChart 來(lái)創(chuàng)建圖表和圖形。所有的圖表都用可移植網(wǎng)絡(luò)圖形(Portable Network Graphics - PNG)格式生成,大多數(shù)現(xiàn)代 Web 瀏覽器都支持這種格式。生成圖表的代碼被很好地封裝在 net.sf.statcvs.renderer
包中。
限制
最大的限制可能是 StatCVS 不支持分支;它只能報(bào)告對(duì)每個(gè)模塊的 HEAD 所做的修改。所以,如果開(kāi)發(fā)團(tuán)隊(duì)的應(yīng)用模式是為產(chǎn)品的每個(gè)版本建立一個(gè)新分支,并且只提交到這個(gè)分支,那么 StatCVS 無(wú)法返回正確的結(jié)果。這個(gè)問(wèn)題曾在 StatCVS 的郵件列表上討論過(guò),但是看起來(lái)近期不會(huì)得到解決。但是,既然它是開(kāi)源的,誰(shuí)會(huì)知道以后會(huì)怎樣呢?
另一個(gè)限制是 StatCVS 只支持 CVS。隨著 Subversion 正在迅速贏得 CVS 繼承人的地位,所以如果 StatCVS 能夠兩者都支持,那就太棒了。在 StatCVS 的郵件列表上已經(jīng)有了一些關(guān)于這點(diǎn)的討論,但是 Subversion 修改集的格式看來(lái)正是目前的障礙。
結(jié)束語(yǔ)
挖掘 CVS 儲(chǔ)存庫(kù)來(lái)查找使用信息,可能產(chǎn)生大量的數(shù)字和圖表。但是要認(rèn)識(shí)這些數(shù)字的有用性,以及它們能夠?yàn)樘囟?xiàng)目開(kāi)發(fā)提供什么樣的深入觀察,這些則要取決于您的判斷。在腦子里要有這樣一些概念,StatCVS 可以提供一些有趣的可視快照,讓您了解項(xiàng)目源代碼在其生命期間發(fā)生的事。
而且,StatCVS 也是開(kāi)源項(xiàng)目良好運(yùn)行的一個(gè)優(yōu)秀模型。它的代碼整潔、構(gòu)建過(guò)程簡(jiǎn)單、文檔清晰。如果您對(duì)于如何做好開(kāi)源項(xiàng)目有興趣,那么可以從了解 StatCVS 中學(xué)到許多東西。
- 您可以參閱本文在 developerWorks 全球站點(diǎn)上的 英文原文。
- 獲得 StatCVS 的最新發(fā)行版。請(qǐng)務(wù)必參閱 discussion of branch support 和 discussion of Subversion support。最后,獲得 latest StatCVS release 的源代碼。
- Jikes 是 Java 程序的一個(gè)快速的開(kāi)源編譯器。Jikes 的 Web 站點(diǎn)中還包括 instructions on how to access its CVS repository。
- 學(xué)習(xí)更多有關(guān) JFreeChart 的內(nèi)容,它是 StatCVS 使用的圖形庫(kù)。
- 請(qǐng)下載 CVS 的最新發(fā)行版。其中還有大量的 文檔,CVS 郵件列表 上的一些高手可能對(duì)您很有幫助。
- 不要錯(cuò)過(guò)這個(gè)介紹 CVS client and the CVS server 用法的教程(developerWorks,2003 年 7 月)。
- 還應(yīng)該參閱以下這篇文章,它介紹了 using Eclipse with CVS and Ant(developerWorks,2003 年 3 月)。
- Open Source Development with CVS, Third Edition(Paraglyph Press,2003 年)是一個(gè)對(duì)所有 CVS 特性都有用的指南??梢杂?PDF format 免費(fèi)得到它。
- Ruby 是一個(gè)解釋型腳本語(yǔ)言,可以進(jìn)行迅速而容易的面向?qū)ο缶幊?。它有許多處理文本文件和進(jìn)行系統(tǒng)管理任務(wù)的特性。它簡(jiǎn)單、直接、可擴(kuò)展、可移植,還有友好的、活躍的 郵件列表。
- 在 RubyForge 上可以找到數(shù)百個(gè)開(kāi)源的 Ruby 項(xiàng)目,其中包括一些有助于 Java 開(kāi)發(fā)的項(xiàng)目。例如,Ruby JDWP 是創(chuàng)建 Java Debug Wire Protocol 客戶(hù)機(jī)的 Ruby 實(shí)現(xiàn)的一個(gè)嘗試。
- Michael Squillace 和 Barry Feigenbaum 在他們的文章 Take a shine to JRuby(developerWorks,2004 年 9 月)中討論了 Ruby 與 Java 代碼的交互。
- ViewCVS 提供了 CVS 儲(chǔ)存庫(kù)的只讀 HTTP 界面。它會(huì)顯示文件版本之間的差異,顯示分支和標(biāo)志,還支持語(yǔ)法著色,使代碼更易閱讀。
- JavaNCSS 計(jì)數(shù) Java 程序中的代碼行數(shù)。它能提供正確的測(cè)量,因?yàn)樗鼤?huì)跳過(guò)注釋和空白行。
- JUnit 框架自動(dòng)運(yùn)行單元測(cè)試。它提供了良好的 GUI ,當(dāng)所有測(cè)試通過(guò)時(shí)顯示綠色進(jìn)度條。這使得“如果條是綠的,代碼就是干凈的”這句話用得越來(lái)越多。而且 developerWorks 還有一篇關(guān)于 用 Jython 構(gòu)建 JUnit 測(cè)試包 的文章。
- Apache Ant 是一個(gè)基于 Java 編程語(yǔ)言的構(gòu)建工具,developerWorks 上有許多關(guān)于 Ant 的文章和教程,其中包括:
- 讓編譯和測(cè)試過(guò)程自動(dòng)化(2001 年 8 月)
- Extending Ant to support interactive builds(2001 年 11 月)
- Apache Ant 101: Make Java builds a snap(2003 年 12 月)
- Maven 是為 Java 程序設(shè)計(jì)的項(xiàng)目管理和項(xiàng)目范圍的工具。它定義了標(biāo)準(zhǔn)的項(xiàng)目描述模型,可以自動(dòng)執(zhí)行許多標(biāo)準(zhǔn)的項(xiàng)目任務(wù)。
- 請(qǐng)務(wù)必參閱 StatCVS-XML plug-in for Maven 的文檔。
- Charles Chan 寫(xiě)了以下這篇有趣的文章,描述了 項(xiàng)目管理:Maven 讓事情變得簡(jiǎn)單(developerWorks,2003 年 4 月)。
- PMD 是一個(gè) Java 源代碼的靜態(tài)源代碼分析工具,可以找出沒(méi)有使用的變量、空的 catch 塊、沒(méi)有必要的對(duì)象創(chuàng)建,等等。
- Elliotte Harold 對(duì) PMD 的世界進(jìn)行了思考,并撰寫(xiě)了這篇文章,解釋如何 用 PMD 鏟除 bug(developerWorks,2005 年 1 月)。
Tom Copeland 從 TRS-80 Model III 上開(kāi)始編程,但是對(duì)這項(xiàng)技能的需求已經(jīng)衰退了,所以他現(xiàn)在主要編寫(xiě) Ruby 和 Java 代碼。他參與過(guò)各種開(kāi)源項(xiàng)目,其中包括 PMD 和 GForge,他還幫助管理 RubyForge,這是一個(gè)開(kāi)源的 Ruby 項(xiàng)目?jī)?chǔ)存庫(kù)。他和妻子 Alina 有四個(gè)孩子(Maria、Tommy、Anna 和 Sarah),他們一起住在北佛吉尼亞。