在程序開發的過程中,我們希望團隊成員的代碼風格保持一致。
但是,如果只是口頭或者書面協定的話,結果往往不太好,甚至更糟,可能會導致多種代碼風格混雜在同一個源文件中的局面出現。
一個改進的方法是,每個人都使用自己的代碼風格,但是在修改其他人代碼的時候,尊重他人的代碼風格;這個方法實際實行起來也是非常困難的,大多數時候也只是一廂情願而已;很多人在自己的源文件中都做不到代碼風格統一,原因是Eclipse支持自動代碼生成,而風格又與他自己的不一致。
一個更進一步的解決方案是,在SVN提交的時候,強制檢查代碼風格,拒絕那些不符合規范的代碼。
在這里,我只針對Java代碼工程,且SVN作為版本工具的情況,具體的方案是:SVN PreCommitChecks + CheckStyle + svnchecker。
先說一下我個人的機器環境:Ubuntu 12.04,svn 1.6.17,版本庫建立在本地文件系統的個人目錄之下。
具體的步驟如下(假定你已經安裝過svn):
1.下載並安裝CheckStyle
項目主頁:http://checkstyle.sourceforge.net/
下載頁面:http://sourceforge.net/projects/checkstyle/files/
下載之后,解壓,然后將里面的jar包加上可執行權限,我個人是將它放在目錄$HOME/bin/svn-tools/checkstyle-5.6/之下
2.下載並安裝svnchecker
項目主頁:http://svnchecker.sourceforge.net/ 和 http://svnchecker.tigris.org/
下載頁面:http://svnchecker.sourceforge.net/download.php
下載之后,解壓,然后將里面的py文件加上可執行權限,我個人是將它放在目錄$HOME/bin/svn-tools/svnchecker-0.3/之下
3.建立本地版本庫(主要用於調試配置與腳本,在實際環境下,應該使用真正的版本庫)
我建立的個人本地版本庫是在目錄$HOME/demosvn/之下,注意它里面的hooks目錄
4.確定checkstyle.xml文件
確定一個適合本團隊的checkstyle.xml是非常重要的,它直接決定了事情的效果。
對於新起項目,一開始就應該確定一個比較完善的風格規則。
對於遺留項目,應該先簡單,然后逐漸豐富,留好過渡期。
checkstyle.xml的具體書寫規則以及它的能力與限制,請參考:
http://checkstyle.sourceforge.net/checks.html
一個示例checkstyle.xml,它來自Google:
http://code.google.com/p/google-api-java-client/source/browse/checkstyle.xml?repo=samples
網上有一些知名公司的代碼規范,你可以下載他們的checkstyle.xml然后再做修改。
在使用第三方checkstyle.xml的時候,有時候會出現CheckStyle運行時錯誤,一般是因為checkstyle.xml中使用了不被識別的規則,去掉就好了。
我將checkstyle.xml放在目錄$HOME/demosvn/hooks/之下,你可以自行選擇其它地方。
5.確定svncheckerconfig.ini配置文件
svncheckerconfig.ini文件的具體格式是Python的ConfigParser類定義的標准配置文件格式,非常容易出錯,因此要小心書寫。
svncheckerconfig.ini既可以放在svnchecker的安裝目錄之下($HOME/bin/svn-tools/svnchecker-0.3/),也可以放在hooks目錄之下($HOME/demosvn/hooks/);前者起全局作用,后者則只對該版本庫起作用。
我選擇將它放在目錄$HOME/demosvn/hooks/之下,只對版本庫demosvn起作用。
如果svncheckerconfig.ini沒有出現在這兩個位置之一,運行的時候就會報錯,提示找不到配置文件。
如果你確信svncheckerconfig.ini放在了正確的位置,但是運行時仍然提示找不到配置文件,一般是因為svncheckerconfig.ini的內容不符合格式規范。
一個示例配置:

1 [Default] 2 3 #This property tells Subversionchecker about all checks 4 #(UnitTests, AccessRights, XMLValidator etc) it should execute. 5 #Separated with comma (",") 6 Main.PreCommitChecks=Checkstyle 7 8 #Path of java executable to run Checkstyle command 9 Checkstyle.Java=/usr/bin/java 10 11 #Classpath for executing Checkstyle rules 12 Checkstyle.Classpath=$HOME/bin/svn-tools/checkstyle-5.6/checkstyle-5.6-all.jar 13 14 #Configuration file for Checkstyle to run its rules. 15 Checkstyle.ConfigFile=$HOME/demosvn/hooks/checkstyle.xml 16 17 #In case of failures, where should Subversionchecker redirect the errors 18 Checkstyle.FailureHandlers=Console
注意將里面的路徑換成適合你自己的路徑,請使用全路徑;注意給腳本文件加上可執行權限。
6.編寫svn pre-commit腳本
在hooks目錄下定義一個名字為pre-commit的腳本文件,具體內容如下:

1 #!/bin/sh 2 3 REPOS="$1" 4 TXN="$2" 5 6 # Make sure that the log message contains some text. 7 SVNLOOK=/usr/bin/svnlook 8 $SVNLOOK log -t "$TXN" "$REPOS" | \ 9 grep "[a-zA-Z0-9]" > /dev/null || exit 1 10 11 # Exit on all errors. 12 set -e 13 14 # Do the check 15 $HOME/bin/svn-tools/svnchecker-0.3/Main.py PreCommit $REPOS $TXN || exit 1 16 17 # All checks passed, so allow the commit. 18 exit 0
注意將里面的路徑換成適合你自己的路徑,請使用全路徑。
以上這種方案實現起來,也是有一些缺點的:
1.定義的一些規則可能太死板,導致大面積已有代碼不符合規范(盡早實施,還是定義一組寬松且合適的規范?)
2.如何處理第三方代碼(是否可以定義例外規則?)
3.如何定義強制提交后門(沒有后門是否更好?)
4.如何做到只檢查修改的部分(全文件檢查不宜實施,考慮修改其他人源文件的情況)
最后,最具決定性的一點,我認為還是團隊管理者對代碼風格的重視程度。