這裡主要講一下關於程式碼規範的相關問題,和在Android專案中如何利用一些工具進行規範和檢查。程式碼規範不是一個Android專案特有的問題,所以前部分內容是不單針對Android的。

什麼是程式碼規範?

程式碼規範一般是指在程式設計過程中的一系列規則規範。

一般來說程式碼規範可以分為兩種。

  1. 一是程式語言本身在設計時所規定的一些原則,這類規則大部分都是強制的,像Python裡用縮排表示邏輯塊,Go裡用首字母大小寫表示可見度。
  2. 另外一種是在一些組織約定的一些規範模式或個人在編寫程式碼時的一些偏好,這種一般都是非強制的。比如大括號是放在方法名的同一行呢還是另起一行,不同的人有不同的想法,我也不知道誰好,所以別問我。

假如是強制的,大家暫時也不能反抗,只能吐嘈吐嘈,我們需要關心和規範的是非強制性規範。

一般情況下程式碼規範應該包括以下東西:

  1. 程式碼格式和要求:註釋,縮排,空格,空行
  2. 約定的方法名,變數名,類名等等取名相關問題
  3. 通用的一些模式和一些要避免的模式

為什麼要有統一的程式碼規範?

假如你一個人單幹,並且基本上也會這麼繼續下去的話,那這個東西對你不是太重要,隨心就好,在這個流程裡你就可以隨意continue, break, returnexit

我們先來看看以下幾種程式碼規範不好的情況,雖然情況極端,但多少能看出些問題。

  1. 一個專案裡用Python作為主要程式語言。一部分人用tab做縮排,一部分人用空格做縮排,開發工具也是各種百花齊放。開始的時候大家各自忙著各自的模組,相安無事。有一天,B要在A寫的一個檔案里加幾個方法,然後就會發現有可能程式跑不了,有可能在自己的編輯器裡的縮排全亂了。
  2. 在一個頁面裡有很多類似的按鈕,A寫的時候按勾就記2,按叉就記1。後來B寫,按勾記1,按叉記0。再後來C來維護,就傻眼了,到底是要給1或2呢?

那麼有一個好的程式碼規範有什麼好處呢?

  1. 風格統一,大家讀起來舒心
  2. 新同事加入專案後,不用再花很多心思去猜測各位前輩們的小技巧,縮短上手時間
  3. 看或修改別人的程式碼,不用再去換IDE,或重新配置了
  4. 檢查別人程式碼的時候更加輕鬆,一般來講,你比較容易知道那個方法在哪,是幹啥的
  5. 維護的時候會輕鬆些,一個專案裡維護所處的週期比早期開發要更長,更耗時

簡單來說,程式碼規範就是為了做到車同軌,書同文。最終的目的就是為了節約時間,提高效率,降低溝通成本。

什麼是好的程式碼規範?

  1. 好的程式碼規範是有語言特殊性和專案區別的。比如在Android專案中,必然需要引入一些Java中比較好的範例或模式,不能寫著不像Java,反而像Python。假如專案是一個公共庫,那麼註釋的要求就得提高些,因為別人要看的。但對於一些其他專案,這個要求可能不會那麼高。
  2. 好的程式碼規範必須得到團隊裡所有人的接受和認可。就像大家約好了,寫字要用看得懂的中文,不能非有人為了耍酷,非要用火星文,看得大家好累。
  3. 好的程式碼規範是可維護且合理的。a) 大家能輕鬆且明確知道一個東西有沒有違反規範;b) 不能為了執行這個規範把程式碼寫得很長很長,得用非常不人道的方法去實現。
  4. 好的程式碼規範必要小而精簡。首先,繁鎖而龐大的東西,大家大都記不住且不願意記。其次,過於繁重反而會讓大家花大量的時間在執行規範上。再次,太瑣碎的東西會讓人很煩,反心由然而起。再再次,扼殺個性或創新......總之,既然目的是要讓愉快的寫程式碼,那總不能讓人不高興吧。

套用一句廣告來說,適合自己的才是最好的

Android專案裡的程式碼規範

到Android了,覺得無關的群眾可以散了。

總體來說,Android的要求應該是要基於Java的。這裡推薦GoogleSun的程式碼規範,大家可以借鑑或修改。

不論是在Android Studio或者Eclipse裡,這些整合的IDE都對這些規範有很多人性化的提示,但它們在事後檢查或可定製或跨IDE方面有些不足,所以我們需要一些輔助工具。

接下來這裡會推薦幾個程式碼分析工具幫助大家檢查相關問題,主要環境是Android Studio和Gradle,但在Eclipse和Ant等其他環境下修改應該也能使用。

checkstyle幫助開發者實現常用JAVA程式碼規範的自動化檢查。它的功能比較豐富,相對配置起來比較複雜,你需要根據自己的需求配置你想檢查的東西,比如AnnotationsBlock ChecksClass DesignCodingDuplicate CodeHeadersImportsJavadoc CommentsMetricsMiscellaneousModifiersNaming ConventionsRegexpSize ViolationsWhitespace

首先,你要在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是一個分析bytecode並找出其中可疑部分的一個工具。它給專案位元組碼做一個全面掃描,通過一些通用規則去判斷可能潛在的一些問題,比如效能,多執行緒安全等等。有些時候它也會給出很詳細的說明,為什麼這種做法不大好,蠻有意思的。例如:

DLSYNCHRONIZATIONONSHAREDCONSTANT: Synchronization on interned String
The code synchronizes on interned String.

    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.

首先,在build.gradle里加入plugin

apply plugin: 'findbugs'  

其次定義任務,這個也非常簡單。你需要用classes指定臨時生成的classes目錄,source指定原始碼所在目錄。同時,你可以用xml.enabledhtml.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
        }
    }

PMD

PMD也是一個靜態程式碼分析工具,它主要用來分析一些常見問題。

PMDFindbugs功能上有很多重疊的地方,二者區別主要體現在分析物件上,Findbugs掃描的是位元組碼,所以找到問題的級別有可能不一樣。推薦大家可以各自選擇,也可以兩者都用

它有很多定義好的rule,例如在Android裡,目前有三項規則:

  1. CallSuperFirst,它會檢查在ActivityService裡的子類裡,是否在錯誤位軒呼叫父類onCreate等應該放在方法前的方法。
  2. CallSuperLast,和CallSuperFirst,但它會檢查一些應該在方法結束時才呼叫父類實現的情況。
  3. 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
        }
    }

總結

工具和方法很多,並且很多工具和方法有重複功能,大家都可以根據需要修改和調整。但需要切記:

  1. 制定規範和使用規範的目的是為了讓團隊能一起愉快的寫程式碼
  2. 不能因為過多和繁鎖的工具和規範讓大家不能愉快的寫程式碼