company_banner

Quality pipelines в мобильной разработке, часть 1: Android

Автор оригинала: Vladimir Ivanov
  • Перевод


фото с Unsplash по запросу "pipeline"


Общий подход


Привет! Я начинаю серию постов о пайплайнах в разработке и не только, которые помогают удостовериться в качестве разрабатываемых мобильных приложений. Главная идея в том, чтобы осветить все подходы к мобильной разработке, актуальные сейчас: нативную разработку для Android и iOS, React Native, Xamarin и Flutter. Я начну с Android, но сначала хотел бы дать общее представление, о чём это всё.


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


Ради чего это всё?


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



Много часов труда можно было бы сэкономить, если бы у вас были механизмы, предотвращающие появление багов в самом начале. Я не говорю, что есть серебряная пуля, избавляющая от всех багов — это невозможно. Но что возможно, так это воздвигнуть барьеры (также известные как quality gates), повышающие вероятность отловить баги в вашем коде как можно раньше.



На компьютере разработчика


Вы как разразботчик всегда работаете на своей машине с IDE и инструментами командной строки. Давайте посмотрим, что существует для Android-разработчиков.


Android Studio


Это сейчас вариант по умолчанию для Android-разработчика, и поскольку он основан на платформе IntelliJ, там есть множество инспекций для Java, Kotlin и XML. Советую договориться в команде о конкретных правилах, которые вы хотите использовать, сконфигурировать их на одном компьютере и закинуть файл settings.jar с этими правилами в вашу систему контроля версий или какой-либо инструмент коллаборативной работы (вроде Confluence).



Настройки инспекций в Android Studio


В AS также есть быстрые исправления, которые можно применить к своему коду по нажатию Alt+Enter.



Пример быстрого исправления от Android Studio


Android Lint


Это инструмент статического анализа конкретно для Android-разработки, «из коробки» снабжённый сотнями правил, любые из которых вы можете использовать. Lint может и запускаться из Gradle-задачи (task), и давать подсказки прямо в Android Studio, и генерировать отчёт. У него множество проверок, разделённых по категориям — безопасность, интернационализация, юзабилити, производительность...


Но особенно мощным его делает возможность добавлять свои собственные правила. Например, у Room есть свой набор правил, у библиотеки логирования Timber — свой. Можно создать правила для вашей команды или проекта и быть уверенным, что никто не совершает определённые типичные ошибки. (Кстати, скоро на конференции Mobius будет доклад об этом, объясняющий и теоретическую сторону, и практическую).



Пример отчёта от Android Lint


Ещё статический анализ


Конечно, есть много инструментов статического анализа, предназначенных не конкретно для Android, а в целом для Java и Kotlin: PMD, FindBugs (заброшен, используйте SpotBugs), Checkstyle, Ktlink, Detekt и другие. Выберите себе по душе, интегрируйте его в свой пайплайн и обеспечьте его реальное использование (как именно? читайте дальше).



Пример отчёта от FindBugs


Но недостаточно наличия инструмента, предоставляющего данные о том, что надо поправить. Вам также пригодится следующая информация:


  1. Как изменяется со временем покрытие кода тестами?
  2. Сколько времени мне потребуется для исправления всех найденных проблем?
  3. Сколько в проекте дублирующегося кода?
  4. Как мне распространить свои правила на несколько команд?

И многие другие. Мы в EPAM Systems уделяем внимание качеству, поэтому выбрали SonarQube как инструмент для ответов на эти вопросы. О других преимуществах SonarQube можно узнать здесь.


Юнит-тестирование


Надеюсь, не требуется вновь убеждать вас, что вашему коду, чёрт возьми, требуются юнит-тесты по различным причинам. Не имеет значения, следуете ли вы TDD, придерживаетесь принципа пирамиды тестирования или новой идеи гриба тестирования. Не так важно, какой уровень покрытия вы ставите целью, в любом случае ваши юнит-тесты — необходимая составляющая. А значит, вам надо их писать и запускать! К счастью, за 11 лет эволюции мы получили довольно удобный механизм запуска тестов из Gradle и Android Gradle-плагина.


В андроид гредл-проекте по умолчанию есть задача testDebugUnitTest (у вас она, естественно, может отличаться в зависимости от флейворов), и именно она запускает тесты. Убедитесь, что её используют и что покрытие кода со временем растёт. Плюс Java юнит-тестов в том, что они работают на JVM рабочей станции, а не на Dalvik/ART, что даёт преимущество в скорости.


В случае с андроидными юнит-тестами есть одна фундаментальная проблема: зависимость от Android SDK. Это одна из причин, по которым появились все эти подходы к UI-слою вроде MVP, MVVM, MVI и прочие MV*. Конкретная проблема в зависимости класса от Android в том, что юнит-тесты просто падают из-за использования стабов этого самого Android, которые просто бросают исключение. Конечно, существует пара вариантов: либо пропустить тесты для этого класса, либо извлечь часть логики в другие классы, либо создавать интерфейсы для Android-зависимых классов для тестирования какой-то высокоуровневой логики, либо использовать Robolectric (что далеко от идеала). Другой вариант — использовать инструментированные тесты, которые могут подходить для проверки поведения Activity, но современный тренд в том, что Activity не должна содержать тестов.


К вопросу о покрытии: вы хотите знать, какое оно у вас в данный момент и как меняется со временем, так что вам пригодился бы инструмент и для этого. Насколько мне известно, jacoco — индустриальный стандарт для Java, и у него есть поддержка Kotlin.


Инструментированные тесты


Эти тесты запускаются на эмуляторе Android, что позволяет им использовать Android Framework. К сожалению, они медленные и нестабильные (из-за некоторых проблем с эмулятором), так что большинство известных лично мне разработчиков старается их избегать. Но их поддержка есть в Gradle и Android Studio, так что для вас они, может, и подойдут.


Аудит безопасности


Помимо простых ошибок, опечаток, проблем при копипейсте и тому подобного, есть ещё и большая категория проблем, на которую вам стоит обращать внимание: безопасность. Конечно, Android Lint уже предоставляет некоторые соответствующие подсказки, но лучше озаботиться специализированными инструментами конкретно для этой задачи. Эти инструменты могут работать как в статическом, так и в динамическом режимах; в зависимости от ваших требований к безопасности вы можете хотеть использовать как один из этих режимов, так и оба. Возможно, вы захотите начать, например, с Mobile Security Framework, а позже рассмотреть платные варианты.


К счастью, есть список инструментов статического анализа, составленный непосредственно OWASP. Например, можете выбрать Find Security Bugs или использовать OWASP SonarCube Project.


Удостовериться в выполнении проверок


Как я уже сказал, чем короче цикл фидбека, тем меньше времени и денег вы тратите на исправление багов. Так что хочется быть уверенным, что код соответствует продакшн-качеству ещё до того, как он попадёт в репозиторий или даже будет закоммичен локально. Конечно, можно просто попросить своих разработчиков выполнять проверки, но есть вариант куда лучше: Git hooks.


Я предлагаю добавить pre-commit hook для всех проверок, которые мы обсудили выше: Lint, статического анализа кода и юнит-тестов. Пример процесса настройки можно найти здесь.


CI/CD-пайплайн


Очень сложно представить Android-проект без CI/CD-пайплайна. Ваша цель — повторить все вышеописанные проверки ещё и на этапе сборки. На то есть несколько причин:


  1. Git hooks можно легко обойти с помощью параметра '--no-verify'
  2. Код может успешно проходить все проверки локально, но вносить проблемы уже после merge
  3. Вам нужны отчёты о тестах и покрытии


Пример отчёта на bitrise.io


К счастью, вам достаточно или упомянуть эти проверки безопасности непосредственно в билд-скрипте Gradle, или вызывать соответствующие задачи в вашем CI/CD-пайплайне. Если у вас есть сложности с выстраиванием пайплайна, недавно на конференции DevOops я выступил с докладом о мобильном DevOps в 2019-м.


Пожалуйста, делайте также следующее:


  1. Прогоняйте все проверки для пулл-реквестов. Не позволяйте мерджить ни один реквест, нарушающий любое из правил. Это очень важно: если правило не выполняется, то оно, по сути, не существует.
  2. Прогоняйте все проверки при сборке и деплое. Вы не хотите понижать свою планку качества.
  3. Если билд сломался — это первоочередная задача. Команда должна исправить проблему немедленно, потому что она нарушает вашу практику continuous delivery и не даёт команде писать качественный код.

И удачи в улучшении своего кода!


Если вам понравилась эта статья, подписывайтесь на меня в Твиттере, чтобы не пропустить следующие. А если вы в декабре будете в Москве или можете приехать, приходите на нашу конференцию Mobius и узнайте много другого о разработке для Android (и iOS)!


P.S. Спасибо vixentael за подходы к вопросам безопасности, Алексею Никитину за ревью и комментарии, Александру Баканову за пруфридинг.

JUG Ru Group
239,40
Конференции для программистов и сочувствующих. 18+
Поделиться публикацией

Комментарии 0

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

Самое читаемое