Люди заслуживают большего за свои деньги. Больше видимости, больше контроля, больше свободы. С 2015 года Revolut ставит перед собой задачу обеспечить именно это. Наше мобильное суперприложение с арсеналом замечательных продуктов, которые охватывают расходы, сбережения, путешествия, переводы, кредиты, криптовалюту, инвестиции, обмен и многое другое, помогло более чем 25 миллионам клиентов отправлять, тратить, сохранять и инвестировать с умом.

Давайте заглянем за кулисы разработки Android в Revolut и узнаем, как мы доставляем наши культовые приложения миллионам клиентов по всему миру.

Команда мечты

Наша команда Android — одна из лучших в отрасли, и мы гордимся этим. Это одна из наших движущих сил: над нашими ключевыми продуктами, такими как Revolut для личных клиентов, Revolut Lite, Revolut Business и Revolut ‹ 18 для подростков, работают более сотни отличных инженеров Android.

В Revolut мы считаем, что ключом к победе является создание разноплановых, компактных команд блестящих целеустремленных людей, преодолевающих барьеры. Вот почему у нас около 70 сильных команд, которые распределяют свою работу по двум основным направлениям: платформа и продукт.

Поток платформы состоит из команд Design System и Mobile Platform, а поток продукта включает в себя различные группы продуктов, такие как команда адаптации, команда платежей, команда торговли, команда Crypto, команда Credit и другие. Каждая команда состоит из владельцев продукта, дизайнеров, инженеров iOS, Android, Backend и Frontend, которые работают вместе для достижения исключительных результатов.

Чтобы лучше понять наши команды и то, как они способствуют нашему успеху, давайте подробнее рассмотрим их роли и обязанности.

Команда мобильной платформы 👨‍🔧

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

Команда обновляет конфигурацию проектов, в частности повышает производительность сборок Gradle, поддерживает архитектуру, управляет зависимостями и поддерживает устойчивость архитектуры, модернизирует конвейер CI/CD, упрощает процесс выпуска мобильных версий, создает внутренние инструменты и платформы (инструмент отслеживания автоматизированной аналитики, автоматизированная среда тестирования пользовательского интерфейса, Платформа объявления DI и т. д.), повысить производительность приложения и повысить безопасность.

Команда дизайн-систем 👨‍🎨

Команда Design System является сердцем нашей культуры дизайна. Он отвечает за создание и поддержку центрального источника правды для разработчиков, нашего UIKit (библиотеки повторно используемых компонентов и руководств).

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

Продуктовые группы 👩‍💻

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

Такая команда сосредоточена на создании конкретного продукта, сборе требований, внедрении новых функций, сборе отзывов клиентов и внесении улучшений. Каждый из наших продуктов, включая Credit, Crypto, Stays, Rewards и другие, представляет собой единое приложение для всех денег.

Процесс развития

Процесс разработки требует участия всех членов команды для достижения своей цели. Планирование, наглядность и структура в процессе разработки являются неотъемлемыми компонентами, которые позволяют команде снять стресс и своевременно внедрить качественную функциональность, удовлетворяющую потребности бизнеса.

Процесс начинается с определения требований и критериев приемлемости, которые проверяются и оспариваются командой. Как только требования станут ясными, можно приступить к этапу определения объема. Этап определения масштаба охватывает анализ требований, определение потенциальных решений и построение планов развития.

После этапа определения объема работы все члены команды должны быть согласованы, чтобы можно было приступить к самой разработке. Тем не менее, в процессе разработки могут появиться новые идеи или проблемы, а это означает, что может потребоваться повторное рассмотрение уже определенного решения.

Мы придерживаемся философии Agile, и у каждой команды есть выбор, какую систему управления проектами Agile использовать, обычно это Scrum и Kanban или их комбинацию.

Архитектура уровня проекта

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

Не все наши модули являются функциональными. Существуют основные модули для общих нужд, таких как сеть, базы данных или компоненты Android, модули UIKit для элементов дизайна, модули моделей для базовой структуры данных и тестовые модули. Мы повторно используем общие компоненты и основные функции между функциональными модулями в одном проекте и разделяем их между нашими проектами. Это также применимо к функциям: у нас есть несколько функциональных модулей, которые мы используем в разных продуктах.

В случае модулей функций мы придерживаемся подхода API/реализации, поэтому каждая функция представлена ​​в виде легкого модуля API и тяжелого модуля реализации.

В соответствии с этим подходом реализация функции должна зависеть только от модулей API. Таким образом, тяжелые модули реализации не зависят друг от друга и могут быть построены параллельно, чтобы ускорить время сборки. Этот подход также делает реализацию функции менее хрупкой, поскольку она зависит только от стабильных модулей API.

Архитектура уровня приложений

Все наши продукты реализованы в соответствии с принципами чистой архитектуры. Revolut Business и Revolut ‹ 18 основаны на нашем собственном Компот фреймворке. Kompot реализует шаблон проектирования MVVM, обеспечивает однонаправленный поток данных, упрощает навигацию между различными частями приложения и поддерживает многомодульность из коробки.

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

UI/UX

То, как мы работаем с пользовательским интерфейсом, заслуживает особого внимания, и мы в основном строим наши экраны поверх RecyclerView.

Наш UIKit определяет набор компонентов дизайна, которые можно использовать для создания пользовательского интерфейса. Большинство этих компонентов представлены в нашем коде как RecyclerViewDelegates, и мы строим каждый экран как список этих готовых компонентов (делегатов). Вы можете найти более подробную информацию о том, как мы перерабатываем наши экраны.

Мы также уделяем особое внимание UX. Согласно нашим рекомендациям, экраны должны поддерживать состояния загрузки/ошибки/пусто. Кроме того, переход между состояниями должен быть плавным, без визуальных шумов. Мы также склонны рендерить весь уже загруженный контент и использовать мерцающие скелеты только для тех частей, которые находятся в пути, вместо того, чтобы блокировать весь экран старомодными индикаторами выполнения.

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

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

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

Резюме технического стека

Мы пишем на Kotlin и склонны использовать сопрограммы и потоки Kotlin, но RxJava 2, вероятно, всегда будет частью нашего сердца и кодовой базы.

Мы также используем:

  • Фреймворки: RxJava 2, Coroutines (Flow), OkHttp, Retrofit, Dagger 2, тесты скриншотов Facebook, тесты пользовательского интерфейса Kaspresso, Android SDK
  • База данных: SQLite (Комната OM)
  • Инфраструктуры: Bitbucket, Jira, TeamCity.
  • Коммунальные услуги: Чарльз, почтальон

Контроль качества и тестирование

В Revolut у нас нет QA-инженеров, но это не значит, что мы не проверяем правильность нашего приложения или не выявляем возможные проблемы, прежде чем опубликовать его. У нас есть несколько типов тестов, которые помогают нам постоянно проверять функциональное поведение. Модульные тесты, интеграционные тесты, тесты скриншотов и автоматические тесты пользовательского интерфейса позволяют нам получить достаточно полное покрытие.

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

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

И последнее, но не менее важное: мы охватываем все основные изменения и обновления кода с помощью переключателей функций, управляемых нашей внутренней системой управления выпусками Vader. Это позволяет нам постепенно и безопасно развертывать функции и отключать их в случае возникновения ошибки.

Код-ревью и Git-флоу

Разработчики создают новую ветку для любых функциональных изменений, а не фиксируют их непосредственно в своей локальной основной ветке разработки. После обновления, фиксации и отправки изменений в соответствующую ветку разработчики открывают запрос на слияние, чтобы обсудить и просмотреть изменения, прежде чем они перейдут в ветку разработки.

Когда открывается запрос на слияние или появляются какие-либо изменения в удаленной отслеживаемой ветке, мы выполняем конвейеры CI/CD, включая сборку проекта, запуск Unit и набор наиболее уязвимых тестов пользовательского интерфейса, выполнение проверок Danger.

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

Pull Request готов к мержу только в том случае, если проект успешно собран, Unit и UI тесты пройдены, нет ошибок со стороны Danger, а Pull Request имеет как минимум два одобрения. Весь наш код, модули, классы и тесты закреплены за конкретными владельцами кода (командами), что позволяет нам легко находить владельцев кода во время разработки и, что более важно, назначать рецензентов, чей код был изменен на Pull Request.

Управление выпуском 🚝

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

Когда происходит заморозка, мы готовим бандл Google Play, запускаем Unit и все тесты пользовательского интерфейса. Если все нормально, публикуем первую бета-версию. (Мы проходим эти этапы и загружаем бета-версии каждый день, кроме воскресенья.) На этом этапе мы собираем отзывы клиентов о первой бета-версии, проверяем аналитику и отчеты о сбоях.

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

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

Аналитика

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

Чтобы защитить конфиденциальность наших клиентов, мы не используем сторонние инструменты аналитики. Вместо этого мы создали собственное решение для анализа пользовательского интерфейса, которое включает в себя как интерфейсную структуру, так и сервер. Фреймворк внешнего интерфейса отслеживает взаимодействие пользователя с приложением «из коробки», не требуя от разработчиков написания какого-либо специального кода. Сервер фиксирует пакетные события появления экранов и нажатия кнопок, что позволяет нам анализировать путь пользователя и его поведение, чтобы улучшить взаимодействие с нашими клиентами.

Присоединяйтесь к нам

Если вам нравятся наши процессы, то, как мы работаем, и возможности, которые вы можете получить от работы с нами, почему бы вам не посетить нашу страницу вакансий и не изучить вакансии в нашей команде Android?

Спасибо команде Revolut Android, особенно Антону Назаренко, Никите Баришок, Ахметову Кириллу и Артуру Харченко, руководителю Инженер Иван Важнов и наш технический директор Влад Яценко.