代碼規范和Android項目中的一些可用工具
來自: http://www.androidchina.net/4266.html
這里主要講一下關于代碼規范的相關問題,和在Android項目中如何利用一些工具進行規范和檢查。代碼規范不是一個Android項目特有的問題,所以前部分內容是不單針對Android的。
什么是代碼規范?
代碼規范一般是指在編程過程中的一系列規則規范。
一般來說代碼規范可以分為兩種。
- 一是編程語言本身在設計時所規定的一些原則,這類規則大部分都是強制的,像Python里用縮進表示邏輯塊,Go里用首字母大小寫表示可見度。
- 另外一種是在一些組織約定的一些規范模式或個人在編寫代碼時的一些偏好,這種一般都是非強制的。比如大括號是放在方法名的同一行呢還是另起一行,不同的人有不同的想法,我也不知道誰好,所以別問我。
假如是強制的,大家暫時也不能反抗,只能吐嘈吐嘈,我們需要關心和規范的是非強制性規范。
一般情況下代碼規范應該包括以下東西:
- 代碼格式和要求:注釋,縮進,空格,空行
- 約定的方法名,變量名,類名等等取名相關問題
- 通用的一些模式和一些要避免的模式
為什么要有統一的代碼規范?
假如你一個人單干,并且基本上也會這么繼續下去的話,那這個東西對你不是太重要,隨心就好,在這個流程里你就可以隨意 continue , break , return 或 exit 。
我們先來看看以下幾種代碼規范不好的情況,雖然情況極端,但多少能看出些問題。
- 一個項目里用Python作為主要編程語言。一部分人用tab做縮進,一部分人用空格做縮進,開發工具也是各種百花齊放。開始的時候大家各自忙著各自的模塊,相安無事。有一天,B要在A寫的一個文件里加幾個方法,然后就會發現有可能程序跑不了,有可能在自己的編輯器里的縮進全亂了。
- 在一個頁面里有很多類似的按鈕,A寫的時候按勾就記2,按叉就記1。后來B寫,按勾記1,按叉記0。再后來C來維護,就傻眼了,到底是要給1或2呢?
那么有一個好的代碼規范有什么好處呢?
- 風格統一,大家讀起來舒心
- 新同事加入項目后,不用再花很多心思去猜測各位前輩們的小技巧,縮短上手時間
- 看或修改別人的代碼,不用再去換IDE,或重新配置了
- 檢查別人代碼的時候更加輕松,一般來講,你比較容易知道那個方法在哪,是干啥的
- 維護的時候會輕松些,一個項目里維護所處的周期比早期開發要更長,更耗時
簡單來說,代碼規范就是為了做到車同軌,書同文。最終的目的就是為了節約時間,提高效率,降低溝通成本。
什么是好的代碼規范?
- 好的代碼規范是有語言特殊性和項目區別的。比如在Android項目中,必然需要引入一些Java中比較好的范例或模式,不能寫著不像Java,反而像Python。假如項目是一個公共庫,那么注釋的要求就得提高些,因為別人要看的。但對于一些其他項目,這個要求可能不會那么高。
- 好的代碼規范必須得到團隊里所有人的接受和認可。就像大家約好了,寫字要用看得懂的中文,不能非有人為了耍酷,非要用火星文,看得大家好累。
- 好的代碼規范是可維護且合理的。a) 大家能輕松且明確知道一個東西有沒有違反規范;b) 不能為了執行這個規范把代碼寫得很長很長,得用非常不人道的方法去實現。
- 好的代碼規范必要小而精簡。首先,繁鎖而龐大的東西,大家大都記不住且不愿意記。其次,過于繁重反而會讓大家花大量的時間在執行規范上。再次,太瑣碎的東西會讓人很煩,反心由然而起。再再次,扼殺個性或創新……總之,既然目的是要讓愉快的寫代碼,那總不能讓人不高興吧。
套用一句廣告來說,適合自己的才是最好的。
Android項目里的代碼規范
到Android了,覺得無關的群眾可以散了。
總體來說,Android的要求應該是要基于Java的。這里推薦 Google 和 Sun 的代碼規范,大家可以借鑒或修改。
不論是在Android Studio或者Eclipse里,這些集成的IDE都對這些規范有很多人性化的提示,但它們在事后檢查或可定制或跨IDE方面有些不足,所以我們需要一些輔助工具。
接下來這里會推薦幾個代碼分析工具幫助大家檢查相關問題,主要環境是Android Studio和Gradle,但在Eclipse和Ant等其他環境下修改應該也能使用。
Checkstyle
checkstyle 幫助開發者實現常用 JAVA 代碼規范的自動化檢查。它的功能比較豐富,相對配置起來比較復雜,你需要根據自己的需求配置你想檢查的東西,比如 Annotations , Block Checks , Class Design , Coding , Duplicate Code , Headers , Imports , Javadoc Comments , Metrics , Miscellaneous , Modifiers , Naming Conventions , Regexp , Size Violations , Whitespace 。
首先,你要在 build.gradle 里加入plugin
apply plugin: ‘checkstyle'
其次,由于gradle默認的checkstyle版本比較老,你需要更新版本才可以使用一些比較新的方法
checkstyle { toolVersion '6.1.1' showViolations true }
再次,你需要把定義好的要求轉化成 config/checkstyle.xml 里的一項項定義。比如你在 這里 就可以找到Google和Sun規范轉化過來的xml。你應該按照自己的實際需求來配置這個文件。在 checkstyle 的官網上,你可以找到各項已經定義好的規則,添加到項目里。例如,這里我們要定義每行最大長度100個字符。
<module name="LineLength"> <property name="max" value="100"/> <property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/> </module>
現在你就可以加入任務了。注意要把剛剛添加的xml文件添加至 configFile 配置里。同時,你也可以用 source 指定你的源代碼所在目錄,并用 include 指明你希望檢查的代碼,用 exclude 排除你希望在檢查中忽略的代碼。
task checkStyle(type: Checkstyle) { configFile file("config/checkstyle.xml") source fileTree('src') include '**/*.java' exclude '**/gen/**' }
Findbugs
findbugs 是一個分析 bytecode 并找出其中可疑部分的一個工具。它給項目字節碼做一個全面掃描,通過一些通用規則去判斷可能潛在的一些問題,比如性能,多線程安全等等。有些時候它也會給出很詳細的說明,為什么這種做法不大好,蠻有意思的。例如:
DL SYNCHRONIZATION ON SHARED CONSTANT: Synchronization on interned String
The code synchronizes on interned String.
</div>
private static String LOCK = "LOCK"; ... synchronized(LOCK) { ...} ...
Constant Strings are interned and shared across all other classes loaded by the JVM. Thus, this could is locking on something that other code might also be locking. This could result in very strange and hard to diagnose blocking and deadlock behavior. See http://www.javalobby.org/java/forums/t96352.html and http://jira.codehaus.org/browse/JETTY-352 .
</div>
首先,在 build.gradle 里加入plugin
apply plugin: 'findbugs'
其次定義任務,這個也非常簡單。你需要用 classes 指定臨時生成的classes目錄, source 指定源代碼所在目錄。同時,你可以用 xml.enabled 或 html.enabled 指定你希望輸出的報告格式。
task findbugs(type: FindBugs) { ignoreFailures = true classes = fileTree('build/intermediates/classes/debug') source = fileTree('src') classpath = files() effort = 'max' reports {xml.enabled = false html.enabled = true } }</pre>
PMD
PMD 也是一個靜態代碼分析工具,它主要用來分析一些常見問題。
PMD 和 Findbugs 功能上有很多重疊的地方,二者區別主要體現在分析對象上, Findbugs 掃描的是字節碼,所以找到問題的級別有可能不一樣。推薦大家可以各自選擇,也可以兩者都用
它有很多定義好的 rule ,例如在 Android 里,目前有三項規則:
- CallSuperFirst ,它會檢查在 Activity 或 Service 里的子類里,是否在錯誤位軒調用父類 onCreate 等應該放在方法前的方法。
- CallSuperLast ,和 CallSuperFirst ,但它會檢查一些應該在方法結束時才調用父類實現的情況。
- DoNotHardCodeSDCard ,這也是一個常見錯誤,你應該用 Environment.getExternalStorageDirectory() 而不是硬編碼去取得擴展存儲目錄。
目前為止 PMD 對于 Android 的檢查項并不多,使用它主要是用來檢查一些 JAVA 中的常見錯誤。
首先,在 build.gradle 里加入plugin
apply plugin: 'pmd'其次定義任務, ruleSets 是需要檢查的一些規則,大家可以根據需要自己修改。點擊 這里 可以找到所有的預定義規則。
task pmd(type: Pmd) { source fileTree('src')ruleSets = [ 'java-android', 'java-basic', 'java-braces', 'java-clone', 'java-codesize', 'java-comments', 'java-controversial', 'java-coupling', 'java-design', 'java-empty', 'java-finalizers', 'java-imports', 'java-j2ee', 'java-javabeans', 'java-junit', 'java-logging-jakarta-commons', 'java-logging-java', 'java-migrating', 'java-naming', 'java-optimizations', 'java-strictexception', 'java-strings', 'java-sunsecure', 'java-typeresolution', 'java-unnecessary', 'java-unusedcode' ] reports { xml.enabled = false html.enabled = true } }</pre>
總結
工具和方法很多,并且很多工具和方法有重復功能,大家都可以根據需要修改和調整。但需要切記:
- 制定規范和使用規范的目的是為了讓團隊能一起愉快的寫代碼
- 不能因為過多和繁鎖的工具和規范讓大家不能愉快的寫代碼
</ol> </article>