[Перевод] AndroidAudit. Ваше Android-приложение как место преступления
От переводчика: оценка процесса и результата разработки — достаточно субъективная вещь, если не используется какая-либо мера весов. Можно долго спорить: табы или пробелы, 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 вам нужно для слияния?
- Кто несет ответственность за закрытие ветки?
- Есть ли у вас какой-либо регламент относительно того, на что нужно обращать внимание при рассмотрении PR (pull request)?
- Вы используете 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).
Отдельное спасибо за обе КДПВ, которых не было в оригинальной статье, Кочкиной Яне.
Кстати, если ActionBarSherlock живет в вашем проекте и по ныне, то рекомендую подумать об освежении проекта.