Разметить всё: как мы настроили систему логирования в приложении каршеринга
Привет, Хабр! Меня зовут Аня Погадаева, я тимлид клиентской и продуктовой аналитики в каршеринге Ситидрайв. В статье я расскажу о разметке событий в приложении. Иными словами, о построении системы логирования.
Глобальная цель этого лонгрида — показать все аспекты жизненного цикла события: от идеи и технической реализации до попадания в отчёт и получения инсайтов. Приступим :)
Любое действие пользователя в приложении можно расценивать как событие; разметка событий — это процесс, при котором мы «учим» приложение собирать полезную информацию о действиях пользователя. Полученные данные мы используем, чтобы улучшать клиентский опыт и совершенствовать продукт.
Например, в хорошо известной всем воронке каждый шаг и есть событие.
Потребность отслеживать некоторые действия пользователей в Ситидрайве появилась ещё в первые дни запуска проекта. Это сейчас у нас 700 уникальных событий, которые мы можем отследить. А в самом начале мы отслеживали всего 10 ключевых событий во флоу бронирования — открытие приложения, открытие карточки авто, нажатие на кнопку «Забронировать» и т. д. Но приложение каршеринга не состоит только лишь из флоу бронирования. А ещё оно постоянно развивается. Десяти событий для аналитики точно недостаточно. Нам нужно было выстроить эффективный процесс разметки и существующих, и новых фичей.
Систему отслеживания событий мы строили инхаус с нуля, набивая шишки и ошибаясь. Это заняло куда больше времени, чем использование готового стороннего решения; зато мы приобрели гибкость и возможность не подстраивать свои процессы под чужие шаблоны (а это вполне стандартные компромиссы в таких ситуациях).
Немного подготовительной теории
Событие (aka лог, ивент) — это действие пользователя или этап работы приложения.
Под действием пользователя подразумевается взаимодействие с видимыми элементами интерфейса приложения. Например, «Нажатие на кнопку «Забронировать».
Под этапом работы системы — ответы приложения на действия пользователя (или самой системы). Например, получение подтверждения с бека об успешном создании заказа после того, как пользователь нажал на кнопку «Забронировать».
Действие/этап фиксируется некоторой системой; вместо «фиксируется» обычно говорят, что событие «уходит» или «отправляется». Само по себе событие — это уже прекрасно, но давайте добавим немного контекста: событию нужно наименование и параметры события.
Наименование — это короткий никнейм для длинного описания. Вместо длинного описания на русском «Нажатие на кнопку «Забронировать» в систему логирования будет передано наименование book_button_tapped
.
Параметры события — это дополнительная информация, которая будет полезна для предстоящей аналитики. У события book_button_tapped
в качестве параметров можно указать:
дату и время события;
идентификатор пользователя;
идентификатор устройства;
ОС устройства;
версия приложения;
идентификатор автомобиля, выбранного для бронирования пользователем;
расстояние от пользователя до автомобиля;
уровень топлива автомобиля;
экран приложения, на котором произошло событие;
и др.
При этом некоторые параметры являются обязательными, а некоторые — необязательными (кастомными).
Обязательные параметры должны уходить вместе с любым событием. Примеры таких параметров: идентификатор пользователя/устройства, версия приложения, дата и время события. Если этих параметров не будет, то невозможно будет понять кто, когда, на каком устройстве и с какими настройками совершил событие. Набор обязательных параметров определяется на начальном этапе разработки системы логирования и, как правило, в дальнейшем меняется очень редко.
Кастомные параметры — это информация, которая относится к конкретному событию. Например, когда пользователь нажимает на кнопку «Забронировать», нам важно получить информацию об идентификаторе автомобиля. Но когда пользователь нажимает на иконку «Фильтры», информация об идентификаторе автомобиля не просто лишняя, её даже не существует. Набор кастомных параметров не статичен и при появлении новых событий может дополняться. Отмечу, что в сторонних системах, как правило, существуют ограничения по количеству или наименованию таких параметров, но при собственной разработке таких проблем не возникает.
Пример того, как событие хранится в аналитической базе.
С подготовительной теорией закончили: определились с тем, что такое события. А чтобы они начали существовать, нужно их создать. Иными словами — разметить.
Процесс разметки
Если грубо, то он состоит из двух частей: подготовка ТЗ и техническая реализация.
Подготовка ТЗ
На этом этапе аналитик:
находит все важные действия, которые могут произойти со стороны пользователя или системы;
определяет, какими кастомными параметрами будут обладать эти события;
составляет ТЗ и обсуждает возможность его реализации с разработчиками.
Создание нового события — процесс творческий. Первое, что важно сделать внутри команды, — задать систему наименований. Над разметкой событий может работать один человек, а может и целая команда. Нужно, чтобы все друг друга понимали и работали по одной схеме. Систему наименований можно придумать любую. В нашем случае — это элемент + глагол-действие, которое с элементом происходит. Всю остальную информацию мы передаём в параметрах.
Второе: важно запомнить (или вспомнить), что аналитика призвана отвечать на вопросы и не стоит логировать всё подряд. Во-первых, это трудозатратно в описании и разработке;, а во-вторых, место для хранения логов не бесконечно. Поэтому перед составлением структуры ивентов нужно понять, на какие вопросы ивенты должны отвечать и какие показатели мы должны уметь отслеживать.
Вопросы могут быть такими:
Как часто пользователь ищет авто по номеру и после этого бронирует машину?
Какие фильтры выбирают чаще всего перед тем, как сделать заказ?
Какое расстояние от пользователя до автомобиля является оптимальным для того, чтобы произошла конверсии из просмотра авто в бронирование?
И третье: важно помнить, что не стоит без надобности увеличивать количество кастомных параметров (опять же: место = деньги). На примере будет понятнее: есть 2 события «Нажатие на иконку авто на карте» и «Выбор конкретной модели авто в фильтрах». И в том, и в другом событии мы можем передать информацию о модели авто и записать это в один и тот же параметр: car_model
. Мы могли бы создать отдельный параметр под каждое из событий: для иконки — car_model
, а для выбора в фильтрах — filter_car_model
, но так делать не надо.
Если очень-очень упростить, то главное, что аналитик передаёт разработчику в рамках этапа подготовки ТЗ — это JSON. JSON — это структура вложенных объектов. На изображении ниже пример такой структуры. В объекте meta — обязательные параметры, в объекте payload — кастомные.
Помимо JSON«а в ТЗ содержатся: информация о том, в какой момент должно возникать событие, ограничения, ссылка на макет, описание кастомных параметров, автор и дата создания. Казалось бы, можно было обойтись просто JSON«ом и сэкономить время на описании — ведь в JSON«е всё просто и понятно. Но нет.
Когда-то давно, когда у нас не было стандартов ТЗ на разметку, возникла ситуация с логированием открытия карты. Вроде бы очень простое событие: пользователь попал на экран с картой города, проблем быть не должно. Но в результате на одной платформе логировалось только первое открытие карты при запуске приложения, а на другой — любое открытие карты в период взаимодействия с приложением. В итоге мы получали несопоставимые между собой данные, которые было сложно использовать для аналитики.
Поэтому помимо кода аналитик передаёт разработчику много текста. К примеру, так выглядит ТЗ для нового события booking_cancel_screen_appeared
:
Техническая реализация
Разработчики делают свою магию обвешивают элементы приложения событиями на базе JSON«а из ТЗ. Profit? Ну, почти. Давайте посмотрим на весь путь события, чтобы осознать всю картинку целиком.
Путь события
Сначала была новая идея фичи от продакт-менеджера. Затем появились макеты этой идеи от дизайнера. Затем разработчик согласился с тем, что идея реализуема и приступил к работе над фичей. Тем временем продакт-менеджер пришёл к аналитику с задачей: по согласованным макетам разметить события. Аналитик параллельно с разработчиком приступил к разметке; не забыл подключить к работе своего коллегу дата-инженера: предупредил о том, что появятся новые события, и о новых параметрах, если они предполагаются. Дата-инженер изучил структуру событий, оценил объём данных и подготовили все условия для того, чтобы распарсить новые параметры из JSON«а в нужные поля нужной таблицы. В назначенный час аналитик встретился с разработчиком и они утвердили разметку событий. И, конечно, перед релизом весь функционал и разметка прошли через строгую, но справедливую проверку QA-инженером. И вот наступил релиз новой версии приложения — новый функционал радует пользователей, а новые события куда-то и как-то уходят. Вопрос: куда и как?
Представим, что пользователь находится в приложении и совершает какие-то действия: настраивает фильтры, выбирает автомобиль, меняет способ оплаты. Все эти действия-события и их кастомные параметры логируются и хранятся на стороне клиента.
Затем по определённому триггеру, эти события оборачиваются в JSON и дополняются техническими параметрами, которые не нужно собирать каждый раз при каждом событии (версия приложения, идентификатор девайса и т. д.). В качестве триггера может выступать сворачивание приложения, холодное открытие приложения и т. д.
После этого JSON отправляется в аналитическое хранилище через шину данных: в нашем случае в качестве шины данных выступает самописный логгер и брокер сообщений Kafka.
И вот после всего этого на данных, которые хранятся в БД, можно строить кастомные отчёты и ловить инсайты.
Здесь важно заметить, что в качестве шины данных может выступать сторонняя система. Например, события можно собирать в MyTracker и строить стандартные отчёты внутри него. При необходимости построения более сложных кастомных отчётов, можно настроить интеграцию аналитического хранилища с MT.
Примеры использования событий
Данные здесь выдуманы, а информация чуть более сжата, чтобы всё поместилось на один экран.
На скриншоте пример отчёта по воронке от инсталла до первой поездки, который мы смогли построить благодаря отслеживанию событий. Воронку можно смотреть в динамике, в различных срезах; можно выбрать, какие именно ивенты показывать в воронке. К примеру, пробовал ли клиент вводить промокод, — этот шаг не является обязательным и по умолчанию скрыт при открытии отчёта.
Ещё один пример применения разметки: оценка интереса в детских креслах и транспондерах. Благодаря правильной разметке событий, мы смогли оценить, насколько часто пользователи обращаются к фильтрам и какие из них выбирают перед заказом. На основе аналитики этих данных закупили достаточное количество кресел и транспондеров, чтобы покрыть спрос клиентов на них без привлечения чрезмерных ресурсов.
Сейчас правильную разметку событий можно считать фундаментом аналитики Ситидрайва. И мы собираемся в дальнейшем совершенствовать методологию разметки. Главное понять и принять, что процесс разметки не останавливается никогда, если приложение развивается.
Если у вас есть вопросы, пишите в комментарии, отвечу. Спасибо за внимание!