Статьи

Обеспечение высокого качества кода Android с помощью инструментов статического анализа

В сегодняшнем уроке мы узнаем о том, как обеспечить высококачественный код Android в наших проектах, используя некоторые инструменты статического анализа кода для Java. Мы рассмотрим Checkstyle, FindBugs, PMD и Android Studio Lint — все они бесплатные и с открытым исходным кодом!

Это инструменты, которые анализируют и анализируют ваш исходный код, фактически не выполняя его. Цель состоит в том, чтобы найти потенциальные уязвимости, такие как ошибки и недостатки безопасности. Популярный бесплатный статический анализатор кода, такой как FindBugs, проверяет ваш код на соответствие правилам, которым ваш код должен придерживаться — если код не следует этим правилам, это признак того, что что-то может быть не так. Думайте об инструментах статического анализа кода как о дополнительном компиляторе, который запускается перед окончательной компиляцией на системный язык

Многие компании-разработчики требуют, чтобы проекты проходили тесты статического анализа кода, в дополнение к проверке кода и модульному тестированию в процессе сборки. Даже сопровождающие проектов с открытым исходным кодом часто включают один или несколько шагов статического анализа кода в процесс сборки. Поэтому изучение статического анализа является важным шагом в написании качественного кода. Имейте в виду, что статический анализ кода, также известный как тестирование «белого ящика», не должен рассматриваться как замена модульного тестирования вашего исходного кода.

В этом руководстве мы познакомимся с некоторыми популярными инструментами статического анализа, доступными для Android и Java. Но сначала давайте посмотрим на некоторые преимущества использования статического анализа.

  • Помогает обнаружить потенциальные ошибки, которые могли пропустить даже единичное или ручное тестирование.
  • Определяет специфичные для проекта правила. Например, статический анализ как часть цепочки сборки помогает новичкам быстрее освоить стандарты кода своей новой команды.
  • Помогает вам улучшить ваши знания нового языка.
  • Сканирует весь ваш проект, включая файлы, которые вы, возможно, никогда не читали.

Все инструменты анализа кода, о которых мы узнаем в этом руководстве, доступны в виде плагинов Gradle, поэтому мы можем создавать отдельные задачи Gradle для каждого из них. Давайте использовать один файл Gradle, который будет включать их все. Но перед этим давайте создадим папку, которая будет содержать все наши файлы для статического анализа кода.

Откройте Android Studio и в модуле приложения (в представлении « Проект» ) создайте новую папку и назовите ее code_quality_tools . Эта папка будет содержать файлы XML для инструментов анализа кода, а также файл Gradle, quality.gradle , который будет выполнять наши задачи статического анализа.

Скриншот структуры проекта студии Android

Наконец, зайдите в свой build.gradle в папке модуля приложения и включите эту строку в конец файла:

1
apply from: ‘/code_quality_tools/quality.gradle’

Здесь наше качество. gradle Сценарий Gradle применяется со ссылкой на его локальное местоположение файла.

Учитывая правила, которые вы указываете в файле XML для обеспечения соблюдения стандарта кодирования для вашего проекта, Checkstyle применяет эти правила путем анализа исходного кода и сравнения их с известными стандартами или соглашениями кодирования.

Checkstyle — это инструмент с открытым исходным кодом, который активно поддерживается сообществом. Это означает, что вы можете создавать свои собственные пользовательские проверки или изменять существующие в соответствии с вашими потребностями. Например, Checkstyle может выполнить проверку имен констант (финальных, статических или обоих) в ваших классах. Если ваши имена констант не соответствуют правилу прописных букв, разделенных подчеркиванием, проблема будет отмечена в окончательном отчете.

1
2
3
4
5
// incorrect
private final static String myConstant = «myConstant»;
 
// correct
private final static String MY_CONSTANT = «myConstant»;

Я покажу вам, как интегрировать Checkstyle в наш проект Android Studio, и продемонстрирую практический пример.

Во-первых, нам нужно создать наши правила кодирования. Внутри чекстайл . xml , мы создаем некоторые правила конфигурации Checkstyle, которые будут выполняться с нашим кодом.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version=»1.0″?><!DOCTYPE module PUBLIC
        «-//Puppy Crawl//DTD Check Configuration 1.2//EN»
        «http://www.puppycrawl.com/dtds/configuration_1_2.dtd»>
<module name=»Checker»>
    <module name=»FileTabCharacter»/>
    <module name=»TreeWalker»>
 
        <!— Checks for Naming Conventions —>
        <!— See http://checkstyle.sourceforge.net/config_naming.html —>
        <module name=»MethodName»/>
        <module name=»ConstantName»/>
 
        <!— Checks for Imports —>
        <!— See http://checkstyle.sourceforge.net/config_imports.html—>
        <module name=»AvoidStarImport»/>
        <module name=»UnusedImports»/>
 
        <!— Checks for Size —>
        <!— See http://checkstyle.sourceforge.net/config_sizes —>
        <module name=»ParameterNumber»>
            <property name=»max» value=»6″/>
        </module>
         
        <!— other rules ignored for brevity —>
</module>

В приведенном выше коде мы включаем правила или проверки, которые мы хотим, чтобы Checkstyle проверял в нашем исходном коде. Одним из правил является AvoidStarImport, который, как следует из названия, проверяет, содержит ли ваш исходный код оператор импорта, такой как java.util.* . (Вместо этого вы должны явно указать пакет для импорта, например, java.util.Observable .)

У некоторых правил есть свойства, которые мы можем установить точно так же, как и для ParameterNumber — это ограничивает количество параметров метода или конструктора. По умолчанию свойство max равно 7, но вместо этого мы изменили его на 6. Взгляните на некоторые другие проверки на сайте Checkstyle .

Чтобы запустить эту проверку, нам нужно создать задачу Gradle . Итак, зайдите в файл quality.gradle и создайте задачу с именем checkstyle:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
apply plugin: ‘checkstyle’
 
task checkstyle(type: Checkstyle) {
    description ‘Check code standard’
    group ‘verification’
 
    configFile file(‘./code_quality_tools/checkstyle.xml’)
    source ‘src’
    include ‘**/*.java’
    exclude ‘**/gen/**’
 
    classpath = files()
    ignoreFailures = false
}

Обратите внимание, что в приведенном выше коде мы сначала применили плагин Checkstyle Gradle . Мы дали ему описание и добавили его в уже определенную группу Gradle, которая называется проверкой.

Ключевыми свойствами задачи Checkstyle Gradle, которая нас интересует, являются:

  • configFile : файл конфигурации Checkstyle для использования.
  • IgnoreFailures : разрешить или нет продолжение сборки, если есть предупреждения.
  • include : набор шаблонов включения.
  • исключить : набор шаблонов исключения. В этом случае мы не сканируем сгенерированные классы.

Наконец, вы можете запустить скрипт Gradle, открыв окно инструмента Gradle в Android Studio, открыв группу проверки , а затем щелкнув по контрольному стилю, чтобы запустить задачу.

Панель инструментов Gradle открыта для запуска задачи checkstyle

Другой способ — использовать командную строку:

1
gradle checkstyle

После завершения задачи будет сгенерирован отчет, который доступен в модуле приложения> build> reports> checkstyle . Вы можете открыть checkstyle.html для просмотра отчета.

Расположение папки отчета Android Studio Checkstyle

Плагин Checkstyle свободно доступен для Android Studio или IntelliJ IDEA. Он предлагает сканирование ваших файлов Java в режиме реального времени.

PMD — это еще один инструмент анализа открытого кода, который анализирует ваш исходный код. Он находит общие недостатки, такие как неиспользуемые переменные, пустые блоки catch, создание ненужных объектов и так далее. PMD имеет множество наборов правил, которые вы можете выбрать. Пример правила, которое является частью набора правил проектирования :

  • SimplifyBooleanExpressions : избегайте ненужных сравнений в логических выражениях, которые усложняют простой код. Пример:
1
2
3
4
5
6
7
public class Bar {
 // can be simplified to
 // bar = isFoo();
 private boolean bar = (isFoo() == true);
 
 public isFoo() { return false;}
}

PMD настраивается с помощью файла pmd .xml . Внутри мы включим некоторые правила конфигурации, такие как правила для Android , Naming и Design .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?xml version=»1.0″?>
<ruleset xmlns:xsi=»http://www.w3.org/2001/XMLSchema-instance» name=»Android Application Rules»
         xmlns=»http://pmd.sf.net/ruleset/1.0.0″
         xsi:noNamespaceSchemaLocation=»http://pmd.sf.net/ruleset_xml_schema.xsd»
         xsi:schemaLocation=»http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd»>
 
    <description>Custom ruleset for Android application</description>
 
    <exclude-pattern>.*/R.java</exclude-pattern>
    <exclude-pattern>.*/gen/.*</exclude-pattern>
 
    <!— Android —>
    <!— http://pmd.sourceforge.net/pmd-4.3.0/rules/android.html —>
    <rule ref=»rulesets/java/android.xml»/>
     
    <!— Design —>
    <!— http://pmd.sourceforge.net/pmd-4.3.0/rules/design.html —>
    <rule ref=»rulesets/java/design.xml»>
        <exclude name=»UncommentedEmptyMethod»/>
    </rule>
 
    <!— Naming —>
    <!— http://pmd.sourceforge.net/pmd-4.3.0/rules/naming.html —>
    <rule ref=»rulesets/java/naming.xml/ShortClassName»>
        <properties>
            <property name=»minimum» value=»3″/>
        </properties>
    </rule>
    <!— other rules ignored for brevity —>
</ruleset>

Как и в случае с Checkstyle, нам также необходимо создать задачу PMD Gradle, чтобы проверка выполнялась внутри файла quality.gradle .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
apply plugin: ‘pmd’
 
task pmd(type: Pmd) {
    description ‘Run PMD’
    group ‘verification’
    ruleSetFiles = files(«./code_quality_tools/pmd.xml»)
    source ‘src’
    include ‘**/*.java’
    exclude ‘**/gen/**’
    reports {
        xml.enabled = false
        html.enabled = true
    }
 
    ignoreFailures = false
}

PMD также доступен в виде плагина Gradle .

Ключевые свойства созданной нами задачи:

  • ruleSetFiles : файлы настраиваемого набора правил, которые будут использоваться.
  • Источник : источник для этой задачи.
  • отчеты : отчеты, которые будут сгенерированы этой задачей.

Наконец, вы можете запустить скрипт Gradle, открыв окно инструмента Gradle, открыв папку группы проверки, а затем щелкнув по pmd, чтобы запустить задачу. Или вы можете запустить его через командную строку:

1
gradle pmd

Отчет также будет сгенерирован после выполнения задачи, которая доступна в модуле приложения> build> reports> pmd . Существует также плагин PMD для IntelliJ или Android Studio, который вы можете загрузить и интегрировать, если хотите.

FindBugs — это еще один бесплатный инструмент статического анализа, который анализирует ваш класс в поисках потенциальных проблем, сверяя ваши байт-коды с известным списком шаблонов ошибок . Некоторые из них:

  • Класс определяет hashCode (), но не equals () : класс реализует метод hashCode (), но не equals () — поэтому два экземпляра могут быть равными, но не иметь одинаковые хеш-коды. Это подпадает под категорию плохой практики.
  • Неправильное сравнение значения int с длинной константой : код сравнивает значение int с длинной константой, выходящей за пределы диапазона значений, которые могут быть представлены как значение int. Это сравнение бессмысленно и, возможно, даст неожиданный результат. Это подпадает под категорию правильности.
  • TestCase не имеет тестов : класс является JUnit TestCase но не реализовал никаких методов тестирования. Этот шаблон также находится под категорией корректности.

FindBugs — это проект с открытым исходным кодом, поэтому вы можете просматривать, вносить вклад или отслеживать ход выполнения исходного кода на GitHub .

В файле findbugs-exclude.xml мы хотим запретить FindBugs сканировать некоторые классы (с помощью регулярных выражений) в наших проектах, такие как автоматически генерируемые классы ресурсов и автоматически генерируемые классы манифеста. Также, если вы используете Dagger, мы хотим, чтобы FindBugs не проверял сгенерированные классы Dagger. Мы также можем сказать FindBugs игнорировать некоторые правила, если мы хотим.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
<FindBugsFilter>
    <!— Do not check auto-generated resources classes —>
    <Match>
        <Class name=»~.*R\$.*»/>
    </Match>
 
    <!— Do not check auto-generated manifest classes —>
    <Match>
        <Class name=»~.*Manifest\$.*»/>
    </Match>
 
    <!— Do not check auto-generated classes (Dagger puts $ into class names) —>
    <Match>
        <Class name=»~.*Dagger*.*»/>
    </Match>
     
    <!— http://findbugs.sourceforge.net/bugDescriptions.html#ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD—>
     <Match>
        <Bug pattern=»ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD» />
    </Match>
</FindBugsFilter>

И, наконец, мы включим задачу findbugs в quality.gradle :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
apply plugin: ‘findbugs’
 
task findbugs(type: FindBugs) {
    description ‘Run findbugs’
    group ‘verification’
    classes = files(«$project.buildDir/intermediates/classes»)
    source ‘src’
    classpath = files()
    effort ‘max’
    reportLevel = «high»
    excludeFilter file(‘./code_quality_tools/findbugs-exclude.xml’)
    reports {
        xml.enabled = false
        html.enabled = true
    }
    ignoreFailures = false
}

В первой строке выше мы применили FindBugs в качестве плагина Gradle, а затем создали задачу под названием findbugs . Ключевые свойства задачи findbugs нас действительно интересуют:

  • classes : классы для анализа.
  • effort : уровень анализа усилий. Указанное значение должно быть одним из min , default или max . Имейте в виду, что более высокие уровни повышают точность и находят больше ошибок за счет времени выполнения и потребления памяти.
  • reportLevel : приоритетный порог для сообщения об ошибках. Если установлено значение low, сообщается обо всех ошибках. Если установлено среднее (по умолчанию), сообщается об ошибках со средним и высоким приоритетом. Если установлено высокое, сообщается только об ошибках с высоким приоритетом.
  • excludeFilter : имя файла фильтра, определяющего ошибки, которые нужно исключить из excludeFilter , который мы уже создали.

Затем вы можете запустить скрипт Gradle, открыв окно инструмента Gradle, открыв папку группы проверки, а затем щелкнув по кнопке findbugs, чтобы запустить задачу. Или запустите его из командной строки:

1
gradle findbugs

Отчет также будет сгенерирован, когда задача завершится. Это будет доступно в модуле приложения> build> reports> findbugs . Плагин FindBugs — это еще один свободно доступный плагин для загрузки и интеграции с IntelliJ IDEA или Android Studio.

Lint — это еще один инструмент для анализа кода, но по умолчанию он поставляется с Android Studio. Он проверяет исходные файлы вашего проекта Android на наличие потенциальных ошибок и оптимизацию на корректность, безопасность, производительность, удобство использования, доступность и интернационализацию.

Чтобы настроить Lint, вы должны включить блок lintOptions {} в файл build.gradle уровня модуля :

1
2
3
4
5
lintOptions {
    abortOnError false
    quiet true
    lintConfig file(‘./code_quality_tools/lint.xml’)
}

Ключевые параметры Lint, которые нас интересуют:

  • abortOnError : должен ли lint устанавливать код завершения процесса в случае обнаружения ошибок.
  • quiet : стоит ли отключать анализ прогресса отчетности.
  • lintConfig : файл конфигурации по умолчанию для использования.

Ваш файл lint.xml может содержать проблемы, которые Lint должен игнорировать или изменять, например, приведенный ниже пример:

1
2
3
4
5
6
7
8
<?xml version=»1.0″ encoding=»UTF-8″?>
<lint>
    <!— Disable the given check in this project —>
    <issue id=»IconMissingDensityFolder» severity=»ignore» />
 
    <!— Change the severity of hardcoded strings to «error» —>
    <issue id=»HardcodedText» severity=»error» />
</lint>

Вы можете запустить Lint вручную из Android Studio, щелкнув меню « Анализ» , выбрав « Проверка кода» (область проверки — весь проект), а затем нажав кнопку « ОК» для продолжения.

Студия Android проверяет кодовое меню
Android Studio lint проверяет весь диалог кода проекта

Вы также можете запустить Lint, посетив окно инструмента Gradle, открыв группу проверки , а затем щелкнув по lint . Наконец, вы можете запустить его через командную строку.

В Windows:

1
gradlew lint

В Linux или Mac:

1
./gradlew lint

По завершении выполнения задачи будет также создан отчет, который доступен в модуле приложения> build> output> lint-results.html .

StrictMode — это инструмент для разработчиков, который помогает предотвратить случайный флэш-ввод или сетевой ввод-вывод разработчиков вашего проекта в главном потоке, поскольку это может привести к замедлению работы приложения или его неработоспособности. Это также помогает предотвратить отображение диалогов ANR (приложение не отвечает). С исправленными проблемами StrictMode ваше приложение станет более отзывчивым, а пользователь получит более плавный опыт. StrictMode использует два набора политик для обеспечения соблюдения своих правил:

  • Политики виртуальных машин : защищает от неправильных методов кодирования, таких как закрытие объектов SQLiteCursor или любых Closeable объектов Closeable .
  • Политики потоков : отслеживает такие операции, как флэш-ввод-вывод и сетевой ввод-вывод, выполняемые в основном потоке приложения, а не в фоновом потоке.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
if (BuildConfig.DEBUG) {
    StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
            .detectDiskReads()
            .detectDiskWrites()
            .detectNetwork() // or .detectAll() for all detectable problems
            .penaltyLog() // Log detected violations to the system log.
            .build());
    StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
            .detectLeakedSqlLiteObjects()
            .detectLeakedClosableObjects()
            .penaltyLog()
            .penaltyDeath() // Crashes the whole process on violation.
            .build());
}

Приведенный выше код может быть в методе onCreate() вашего Application, Activity или другого компонента приложения.

Вы можете узнать больше о StrictMode здесь на Envato Tuts +.

  • Android SDK
    Рекомендации для Android: StrictMode
    Шейн Кондер и Лорен Дарси

Пример проекта Android, реализующего все вышеперечисленное, включая наборы правил инструментов для типичного проекта Android, можно найти в репозитории GitHub .

В этом руководстве вы узнали о том, как обеспечить высококачественный код Android с помощью инструментов статического анализа кода: каковы они, преимущества их использования и как использовать Checkstyle, FindBugs, Lint, PMD и StrictMode в вашем приложении. Попробуйте эти инструменты — вы можете обнаружить в коде некоторые проблемы, которые вы никогда не ожидали.

А пока ознакомьтесь с другими нашими курсами и учебными пособиями по разработке приложений для Android!

  • Android SDK
    Приложения RxJava 2 для Android: RxBinding и RxLifecycle
    Джессика Торнсби
  • Android Studio
    Создание функциональных приложений для Android в Kotlin: начало работы
    Джессика Торнсби
  • Android SDK
    Android с нуля: использование API REST
    Ашраф Хатхибелагал
  • Android SDK
    Как создать приложение для Android-чата с помощью Firebase
    Ашраф Хатхибелагал