[Перевод] AndroidAudit. Ваше Android-приложение как место преступления

a7a965c2e9ec4ae8955f99291e2bb35a.jpg

От переводчика: оценка процесса и результата разработки — достаточно субъективная вещь, если не используется какая-либо мера весов. Можно долго спорить: табы или пробелы, git или mercurial, maven или gradle, но такие споры все равно скатываются к вкусовщине и каким-то частным случаям. Другое дело — соблюдение однородности проекта, вот это уже вполне себе измеримая величина.

Плохая методология лучше её отсутствия.

Помимо общих вещей, найдутся и специфические, присуще только мобильной разработке, только под Android. Pedro Vicente Gómez Sánchez из Karumi в своей работе разобрал по косточкам основные технические области и задал меткие вопросы для правильной, объективной оценки разработки для платформы Android. Если появится задача: оценить чужой проект, то рекомендую воспользоваться его методологией. Я воспользовался этой методологией, как чек листом. На выходе получился вполне понятный не профессионалу документ, где напротив каждой категории — конкретная величина соответствия правильности от 0 до 1.

Технический аудит iOS и Android приложений стал неотъемлемой частью нашей повседневной работы в Karumi. Хоть это и выглядит просто, имеется немало деталей реализации такой проверки, которые стоит рассмотреть. В этом документе мы рассмотрим то, что мы считаем наиболее важным при проведении аудита и разделим это по техническим областям.

Система контроля версий

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

  • Есть ли у вас правильно настроенный *ignore файл, чтобы файлы метаданных IDE и другие посторонние элементы не попадали в хранилище?
  • Сторонние библиотеки сконфигурированы в качестве внешних зависимостей или лежат в хранилище?
  • Достаточно ли краткие и выразительные комментарии к коммитам (commits) вы используете?
  • Является ли размер ваших коммитов обоснованным?
  • Все ли файлы в коммите связаны с одной и той же проблемой или функциональностью?
  • Используете ли вы какие-либо схемы ветвления типа «feature branch» или «git-flow»?
  • Достаточно ли информативны названия веток?
  • Используете ли вы систему pull request/code review до слияния кода в master?
    • Есть ли у вас какой-либо регламент относительно того, на что нужно обращать внимание при рассмотрении PR (pull request)?
    • Сколько комментариев в среднем приходится на каждый PR?
    • Сколько людей рассматривает каждый PR?
    • Сколько »+1» к PR вам нужно для слияния?
    • Кто несет ответственность за закрытие ветки?

  • Вы используете release branches для каждого релиза?
  • Как долго открыт процесс подготовки (staging process)?
  • Сколько исправлений вы вносите в release candidate, прежде чем выпустить его?
  • Имеется ли возможность переключиться на точный код какой-либо из опубликованных версий вашего приложения?
  • Сколько исправлений (hotfix) вы выпустили в прошлом году?
  • Вы объединяете (squash) коммиты до слияния (merging) его в master/develop ветку?
  • Готовы ли master/develop ветки к выпуску в любое время?

Инструменты сборки

Определяющим фактором является возможность запустить процесс сборки на машине разработчика и на любой другой внешней системе, например на системе непрерывной сборки (continuous integration).

  • Сколько библиотек используются в проекте?
  • Разделен ли проект на модули?
  • Используют ли модули Maven или Gradle для разрешения зависимостей, или используются локальные .jar-файлы?
  • На опасное ли расстояние приближен проект к лимиту количества методов в .dex файлах? Или уже за гранью?
  • Вы используете библиотеки, которые не нужны в проекте?
  • Используется ли multidex?
  • Все ли внешние зависимости обновлены до современных версий?
  • Все ли лицензии сторонних библиотек соблюдены?
  • Используются ли устаревшие или не поддерживаемые сторонние библиотеки?
  • Обусловлен ли минимальный SDK требованиями технического задания (product description)?
  • Актуален ли целевой SDK (target SDK)?
  • Используется ли ProGuard или любой другой инструмент обфускации (obfuscation — запутывание)? Он включен и правильно настроен?
  • Учетные данные хранилища ключей (keystore credentials) и учетные данные Google Play хранятся в надежном месте?
  • Хранилище ключей приложения (application keystore) и учетные данные хранятся в надежном месте?
  • Должным ли образом настроены build types?
  • Правильно ли используются flavors?
  • Правильно ли настроен релизный тип сборки?
  • Включена ли опция резервного копирования?
  • Включен ли Lint? Он успешно проходит проверку?
  • Имеется ли инструмент статического анализа? Он настроен и успешно проходит проверку?
  • Есть ли Checkstyle? Он настроен и успешно проходит проверку?
  • Правильно ли настроен id приложения и version name/code?
  • Вы используете какую-либо структуру или стратегию версионирования id?
  • Используется ли инструмент непрерывной сборки (continous integration), правильно ли он настроен?
  • Автоматизирован ли процесс выпуска новых версий?

Использование Android ресурсов

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

  • Существуют ли какие-либо недостающие ресурсы для densities, flavors и build types?
  • Требуется ли поддержка приложением экранов с различной плотностью пикселей (density) по техническому заданию?
  • Используются ли в приложении drawable/mipmap, шрифты или векторные ресурсы?
  • Существуют ли какие-либо недостающие переводы?
  • Автоматизирован ли процесс перевода?
  • Какой язык выбран по умолчанию для перевода?
  • Использует ли приложение сторонние шрифты?
  • Использует ли приложение значения конфигурации внутри файла строковых ресурсов?
  • Соблюдается ли соглашение для присвоения однородных имен ресурсам?
  • Есть ли параметры конфигурации, связанные с аппаратными средствами устройства, правильно ли они настроены?
  • Поддерживаются ли планшеты?

Использование Android Layout

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

  • Возникают ли проблемы с производительностью из-за количество слоев в макетах (layouts) приложения?
  • Используете ли вы темы и стили?
  • Используются ли повторно макеты (layouts) с использованием «include» тега?
  • Вы используете правильный тип группировок в макетах?
  • Учтены ли различные размеры экранов в макетах?
  • Используется ли какое-либо соглашение об именовании, чтобы присваиваемые имена макетам и виджетам оставались однородными?
  • Списки реализованы с использованием ListView или RecyclerView?
  • Правильно ли используется Android Support Library?

Права доступа

Запрос возможных действий приложения (permissions) увеличивает доверие пользователей к нему, а также расширяет его возможности за счет «прозрачной» интеграции с другими сервисами.

  • Все ли запрашиваемые разрешения (permissions) действительно необходимы?
  • Разрешение используется намеренно?
  • Есть ли отсутствующие разрешения?
  • Если целевой SDK больше, чем 23, то «опасные разрешения» запрашиваются с помощью системы разрешений совместимости (compatibility permissions system)?
  • Разрешение запрашиваются тогда, когда они будут использоваться?
  • Есть ли обратная связь с пользователем, объясняющая, почему какое-либо разрешение необходимо?

Проблемы с безопасностью

Как разработчики, мы должны сознательно относиться к безопасности наших приложений. Мы не хотим, чтобы данные наших пользователей «утекли» или их сессии были украдены.

  • Настроен ли HTTP клиент на использование HTTPS?
  • Настроен ли HTTP клиент на использование встроенного сертификата (certificate pinning) и сообщений аутентификации с HMAC?
  • Сохраняет ли приложение конфиденциальную информацию пользователя? Где?
  • Сохраняет ли приложение информацию вне внутренней системы хранения данных?
  • Логируется (logging traces) ли приложение при сборке релиза?
  • Обфусцирован (obfuscated) ли код приложения?
  • Предоставляет ли ваше приложение поставщика контента (Android content provider), приемника (receiver) или сервис другим приложениям?
  • Отключена ли опция «debuggable» в релизной сборке?

Push уведомления (Push Notifications)

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

  • Используется ли сторонняя библиотека для реализации системы Push-уведомлений?
  • Используется ли система GCM для передачи информации приложению, или просто, чтобы показывать сообщения пользователю?
  • Как ведет себя приложение при получении Push-уведомления?
  • Как ведет себя приложение, когда связанная с Push-уведомлением информация не та, что ожидалась?
  • Показываются ли уведомления с использованием API совместимости (compatibility API)?

Производительность

Производительность имеет большое значение. Никто не захочет использовать на своих дорогих устройствах медленное приложение. Производительность — это деньги.

  • Есть ли в приложении какие-либо утечки памяти?
  • Настроен ли в develop сборке какой-либо анализатор памяти, как, например, «LeakCanary»?
  • Android Strict Mode подключен и настроен в develop сборке?
  • Как в приложении используются потоки? Вы используете async tasks, intent services или любые другие сторонние библиотеки?
  • Вызывает ли количество фоновых потоков проблемы с производительностью?
  • Используете ли вы какие-либо политики планировщика (scheduler policy) или просто создаются потоки по требованию?
  • Поддерживаете ли вы Android Doze Mode?
  • Прослушиваются ли события, связанные с состоянием сети или любого другого повторяющегося события от операционной системы?
  • Основной поток используется только для выполнения задач, связанных с кодом пользовательского интерфейса?
  • Имеются ли в приложении какие-либо политики кеширования?
  • Настроен ли клиент HTTP на использование тайм-аута?
  • Настроен ли клиент HTTP на использование GZIP?
  • Работает ли пользовательский интерфейс приложения со скоростью 60 кадров в секунду?
  • Нет ли таких custom view, для которых выделяется слишком большой объем памяти, или которые выполняют «дорогостоящие» задачи в потоке пользовательского интерфейса (UI thread)?
  • Вы тестируете ваше приложение на lower-end (бюджетных, непроизводительных) устройствах?
  • Не «тормозит» ли прокрутка recycler view?
  • Для загрузки изображений используется какая-либо сторонняя библиотека или у вас есть своё собственное решение?
  • Изображения масштабируются под размеры экрана или сразу загружаются под определенный экран устройства?
  • Разумно ли использование памяти?
  • Правильно ли используется модификатор «Static» в Java?
  • Все ли задачи, связанные с обработкой изображений, могут обрабатывать несколько изображений за раз?
  • Работает ли система статистики в фоновом потоке и сконфигурирована ли она с правильным приоритетом?
  • Оптимизируется ли код в релизной сборке?

Структура Java Packages

Хорошая структура пакетов сделает наш код более масштабируемым.

  • Используются ли пакеты для разделения кода по функционалу (features) или концепциям (например, Login vs User)?
  • Используются ли модификаторы видимости Java, чтобы скрыть детали реализации внутри пакетов?
  • Все ли пакеты выходят из корневого пакета?
  • Повторяет ли директория с тестами структуру исходной папки?
  • Организованы ли различные функции (features) с помощью одной и той же структуры пакетов?
  • В правильных ли пакетах лежат классы?
  • Соблюдаются ли соглашения об однородном названии пакетов?
  • Связано ли название корневого пакета с именем компании?

Code Style

Согласованная с точки зрения стиля кодовая база помогает нашим инженерам читать код проще. Инженер читает ГОРАЗДО больше кода, чем пишет, так что это важное понятие.

  • Является ли codestyle однородным?
  • Используете ли вы венгерскую нотацию?
  • Есть ли какой-либо инструмент Checkstyle? Он настроен и работает?
  • Соответствует ли код Java codestyle?
  • Вы используете табуляцию или пробелы?
  • Правильно ли названы классы?
  • Используете ли вы «I» в качестве префикса интерфейсов или «Impl» как суффиксы реализации?
  • Используете ли вы правильные имена переменных?
  • Используете ли вы правильные имена для полей (fields)?
  • Используете ли вы правильные имена для методов?
  • Используются ли атрибуты и модификаторы видимости методов должным образом?
  • Код написан на английском языке?
  • Используете ли вы Javadoc?
  • Вы пишете комментарии к коду?
  • Используете ли вы константы или перечисления (enums), чтобы избежать дублирования литералов?

Offline реализация

Обеспечение хорошей работы в режиме offline является отличительным фактором наших приложений.

  • Может ли приложение использоваться, когда нет подключения к сети Интернет?
  • Каково поведение приложения при медленном сетевом соединении?
  • Какое поведение приложения при потере запроса из-за сбоя в сети?
  • Синхронизируются ли изменения данных приложения с бекэндом после того как соединение было восстановлено?
  • Настроен ли тайм-аут на сетевое соединение?
  • Настроена ли политика кеширования HTTP?
  • Сеанс пользователя восстанавливается автоматически?

Архитектура

Архитектура приложений, с точки зрения кода, является одной из частей аудита, которая дает нам более глубокое представление о приложении. В ходе обзора архитектуры приложения мы будем сосредоточены на понятиях, связанных с S.O. L.I.D и Clean Code принципами.

Реализация слоя представления (Presentation Layer Implementation)

  • Используется ли какой-либо паттерн, связанный с реализацией GUI (графического интерфейса пользователя)? Model View Presenter или Model View ViewModel два из наиболее часто используемых шаблонов для разработки приложений. Правильно ли они реализованы?
  • Связана ли реализация слоя представления (presentation layer) с реализацией вида (view implementation)?
  • Связана ли реализация вида (view implementation) c реализацией модели (model implementation)?
  • Включает ли слой представления бизнес-логику?
  • Правильно ли реализация вида использует Android SDK tools?
  • Используете ли вы сторонние библиотеки для упрощения реализации вида?
  • Разделена ли реализация разных функций по отдельным activities или fragments?
  • Однородно ли поведение пользовательского интерфейса?
  • Используете ли вы custom views для повторного использования кода пользовательского интерфейса?

Реализация предметной области (Domain Implementation)

  • Есть ли отдельный слой предметной области (domain layer) или вся бизнес-логика реализована в слое представления (presentation layer)?
  • Выражены ли правила предметной области и различные требования к приложению в основных объектах бизнес-логики?
  • Реализован ли слой предметной области с применением принципов ООП?
  • Связан ли слой предметной области с Android SDK или любой сторонней библиотекой?
  • Связан ли слой предметной области со слоем представления?
  • Является ли модель предметной области (domain model) «анемичной»?
  • Используете ли вы «толстые» модели предметной области?
  • Основан ли код на слабо связанных и, в то же время, хорошо взаимодействующих друг с другом компонентах?
  • Реализована ли обработка ошибок с использованием исключений или какого-либо другого механизма обработки ошибок?
  • Сопоставляются ли данные (mapped) между различными слоями?
  • Влияет ли архитектура внешних компонентов (например, схемы базы данных или парсинга JSON) на архитектуру модели предметной области?
  • Разработчики злоупотребляют наследованием?
  • Дублируется ли код?
  • Есть ли dependency injection библиотеки или сконфигурированный service locator?
  • Не слишком ли высока сложность классов и методов?

Реализация API

  • Привязана ли реализация API к Android SDK?
  • Происходит ли «утечка» через API каких-либо деталей реализации из-за клиента HTTP или используемой библиотекой для реализации сетевого слоя?
  • API клиент посылает правильные заголовки?
  • Каково поведение API клиента для различных ответов HTTP?
  • API клиента реализует механизм аутентификации?
  • Правильно ли реализован процесс возобновления сеанса?
  • Есть ли поддержка обфускации JSON?
  • Разделена ли реализация API для различных клиентов?

Реализация Хранения

  • Где хранится информация?
  • Используются ли транзакции при чтении и записи информации в хранилище?
  • Надежно ли хранение конфиденциальной информации пользователя?
  • Использует ли слой хранения какие-либо сторонние библиотеки?
  • «Утекают» ли детали реализации через слой хранения?
  • Правильно ли спроектированы tables/schemas?
  • Запросы, отправленные в хранилище, оптимизированы?
  • Используются ли Android SDK APIs для хранения данных в правильном месте? Сохраняются ли данные в базу данных, а настройки (preferences) и небольшие по объему данные в Shared Preferences и файлы на диске?

Тестируемость

  • Есть ли у приложения тесты?
  • Является ли приложение тестируемым?
  • В приложении используются различные виды (unit/integration/end-to-end) тестов?
  • Правильно ли названы тесты?
  • Достаточно ли тесты охватывают проект?
  • Есть ли чрезмерное документирование (overspecification) в тестах?
  • Время выполнения разумно?
  • Не слишком ли низко покрытие кода?
  • Существуют ли какие-либо игнорируемые тесты?
  • Есть ли нестабильные тесты (flaky tests)?
  • Используете ли вы современные фреймворки для тестирования?
  • Существуют ли какие-либо тесты без утверждений (tests without asserts)?
  • Тесты и продакшен код написаны одними и теми же разработчиками?
  • У вас есть команда QA?
  • У вас есть команда QA, автоматизирующая часть тестов?
  • Есть ли у вас какие-либо системы непрерывной интеграции (continuous integration system)?
  • Используете ли вы builders, factories или mothers, чтобы уменьшить затраты на создание некоторых объектов, которые необходимы для тестов?
  • Тесты утверждений (assertions) правильно написаны?
  • Проводите ли вы более одного логического утверждения на тест?
  • У вас есть различные наборы тестов, связанные с одним и тем же проектом?
  • Вы используете различные подходы тестирования для различных частей приложения?
  • Используете ли вы какой-либо monkeyrunner?
  • Следуете ли вы какой-либо TDD или BDD методологии?
  • Используете ли вы Java, чтобы написать тестовые варианты (test cases)?

На основании этого списка, связанного с различными техническими областями, мы можем оценить качество приложения. Есть и другие моменты, которые мы также рассматриваем, но этот список содержит наиболее важные из них. Вы можете дать корректные ответы на все эти вопросы о вашем приложении?

Автор: Pedro Vicente Gómez Sánchez.

Благодарности в помощи подготовке перевода

Не могу не упомянуть тех, без кого данный перевод был бы ужасным промтом, которым стыдно поделиться с общественностью.
Спасибо за помощь в переводе и вдумчивую вычитку Кочкиной Яне, Заостровскому Роману (@firsto), Полежаеву Максиму (@itsme_42).
Отдельное спасибо за обе КДПВ, которых не было в оригинальной статье, Кочкиной Яне.


Альтернативная КДПВ
В память, о некогда очень популярной библиотеке от JakeWharton.
1d89adf1b0f54ebfb48c7b8a30723b58.jpg

Кстати, если ActionBarSherlock живет в вашем проекте и по ныне, то рекомендую подумать об освежении проекта.

© Habrahabr.ru