Извлеченные уроки разработки инструмента A / B-экспериментов в Walmart Labs

Метрическая задача

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

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

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

Метрики

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

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

Метрика против точки измерения против маяка

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

Определения

  • Beacon - это объект данных, отправляемых различными компонентами Walmart.com при различных загрузках страницы или действиях пользователя.
  • Точка измерения используется Expo для отслеживания и составления отчетов об эффективности эксперимента. Маяк - это один из типов данных, который оценивается точкой измерения.
  • Показатель обычно представляет собой числовое значение или процентное соотношение, которое отображается на диаграмме или диаграмме отчетов, что дает представление об эффективности эксперимента. Метрики основаны на точках измерения.

Для экспериментов A / B необходимы две основные метрики: назначенные и квалифицированные.

  • Назначенные - это пользователи, которые посещают приложение или сайт Walmart и участвуют в текущем эксперименте (контрольном или альтернативном).
  • Квалифицированные - это пользователи, включенные в текущий эксперимент И посетившие или просмотревшие страницу или элемент, содержащие другой вариант или лечение.

Теперь давайте посмотрим на поток этих терминов на разных этапах эксперимента.

На этапе 1 эксперимент настраивается и конфигурируется с точками измерения. Когда эксперимент будет готов к работе, мы его запускаем, что означает, что он готов к назначению реального трафика (например, клиентов, посещающих Walmart.com). На этапе 2 клиенты назначаются для эксперимента, и пользовательский опыт (например, данные о кликах) фиксируется с помощью маячков. На этапе 3 пользовательские данные анализируются и передаются обратно на Expo в виде показателей!

Действие и контекст

Точка измерения в контексте Walmart.com - это то, что отображается на атрибуты маяка. С маяком связано множество атрибутов, одним из которых является действие. Атрибут action относится к странице, которая активировала маяк. Это означает, что произошло событие, в данном случае событие загрузки страницы, которое вызвало вызов API службы маяка. Например, домашняя страница имеет действие «домашняя страница».

В некоторых случаях нам может потребоваться немного больше контекста об этом событии. Объект маяка также имеет атрибут, называемый context. Атрибут context на домашней странице просто Homepage. В других случаях атрибут context может быть более описательным для события, вызвавшего его, а не напрямую коррелировать с действием.

На начальном этапе разработки Expo эти два атрибута, в первую очередь атрибут Action, составляли основу того, как инструмент понимал точки измерения и метрики.

Как все было

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

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

Жестко закодированная проблема

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

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

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

Из этого кода видно, что когда появилось требование добавить новые точки измерения, нам пришлось внести изменения в код как в сервисе, так и в пользовательском интерфейсе, опубликовать новые сборки для каждой и выполнить развертывание. (Вы думаете, может быть, они эгоистично встроили в свой инструмент гарантии занятости?)

Гарантия занятости = мечта каждого разработчика?

Решение на основе конфигурации

Несколько лет назад я придумал дизайн для решения нашей жестко закодированной проблемы с интерфейсом пользовательского интерфейса (да, мы частично устранили эту проблему несколько лет назад, извините, безопасность работы). В то время из-за внешних систем, которые вызывают нашу службу, у нас не было возможности (или достаточно высокого приоритета) для изменения кода перечисления службы. Частью этого решения, которое я разработал, была модель определения метрики на основе конфигурации. Эта модель представляла собой единую многоцелевую структуру JSON, которая использовалась пользовательским интерфейсом следующими способами:

  • В форме настройки эксперимента для заполнения раскрывающегося списка метрик с множественным выбором, по которым будет составляться отчет (см. Определение в разделе назначено).
  • В форме настройки эксперимента для заполнения раскрывающегося списка метрик с несколькими вариантами выбора (см. Определение в разделе квалифицировано).
  • Для получения аналитических данных, сгенерированных этими метриками, из трех разных источников отчетов: базы данных временных рядов (kairos), индексированной базы данных NoSql с уменьшенной картой (Couchbase) и более старой внутренней системы потоковой обработки (mupd8).
  • Отображение на панели мониторинга показателей из разных источников отчетов в реальном времени
  • 24-часовой монитор с отображением метрических данных с возможностью отображения данных из разных источников отчетов
  • Отчет о результатах эксперимента с возможностью отображения данных из разных источников отчетов

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

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

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

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

По мере того, как дела идут, вещи развиваются

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

Как дела

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

Статический в динамический

Большинство экспериментов все еще настраиваются в Expo с точками измерения, настроенными на этих двух исходных атрибутах: действие (a) и контекст (ctx). Это все еще поддерживается и может быть записано как выражение запроса.

query_map[‘a’]==’pageview’ and query_map[‘ctx’] == ‘tvpage’

Однако реальная сила этого языка выражений запросов заключается в том, что он позволяет нам погрузиться в этот сложный объект-маяк и сопоставить более точные атрибуты. Ниже приведен частичный сигнал от Walmart.com со страницы с телевизорами. Одно замечание по этому поводу, я говорю «частичный маяк», потому что я удаляю около 90% данных маяка, чтобы продемонстрировать простой пример.

https://beaconserver/beacon?bla={"bla1":{"i":"123","j":"TV"}}&a=pageview&ctx=tvpage

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

query_map['ctx'] == 'tvpage' and query_map['a'] == 'pageview' and query_map['bla'].indexOf('bla1')>0 and query_map['bla1'].indexOf('i')>0 and (c:extract(query_map['i'],'bla1.i') == '123' or c:extract(query_map['j'],'bla1.j') == 'TV')

Вы можете видеть, что параметр URL-адреса «bla» имеет значение, которое является объектом. В этом объекте мы хотим сопоставить определенный набор идентификаторов, в приведенном выше примере «123» или «TV».

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

Отражения и вынос

Если бы мы приложили все эти усилия на ранних этапах строительства Expo, все еще есть шанс, что мы могли ошибиться. Пытаться предсказать будущее поведение, особенно поведение программного обеспечения, через пять лет, вероятно, - плохая идея (равно как и попытка предсказать будущее человеческое поведение). Кроме того, за последние пять лет вся эта предварительная проектная работа была бы чрезмерной для 99% случаев использования. Это не значит, что не было бы определенного уровня раннего внедрения интеллектуальных точек измерения.

Смотреть вперед

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

Создайте трехколесный велосипед, который может стать беспилотным автомобилем

Гибкий дизайн

Убедитесь, что ваш первоначальный дизайн достаточно гибок для эволюции, т.е. будьте осторожны, когда ваш дизайн включает перечисление. В то время у нас была веская причина для встраивания перечислений в нашу службу, в первую очередь для обеспечения ограничений на то, как API-интерфейсы используются внешними системами. Оглядываясь назад, мы могли бы выполнить эти ограничения способами, не требующими изменения кода для добавления нового действия. Помог бы такой дизайн, как дизайн, перейти к умным точкам измерения с гораздо меньшими трудностями? То же самое можно сказать и о раннем дизайне нашего пользовательского интерфейса и о том, что нужно учитывать дизайн на основе конфигурации, а не показатели жесткого кодирования.

Соображения

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

  1. По мере развития платформы, какие будут самые большие проблемы в текущем дизайне?
  2. Каковы затраты и компромиссы при разработке проекта, ориентированного на будущее?
  3. Каковы предполагаемые затраты и усилия на проведение серьезного изменения дизайна в будущем?

Заключение

Экспо прошла долгий путь за последние пять лет. Он сильно изменился, с каждым разом становясь все более зрелой в качестве платформы для Walmart. Это помогло запустить некоторые из крупнейших изменений Walmart.com, такие как последний редизайн веб-сайта, запущенный в мае 2018 года. Требования будут продолжать развиваться (мы надеемся, что метрики на данный момент эволюционируют). Не существует мастерской, ориентированной на будущее дизайна, которая ограничила бы эволюцию, особенно в программном обеспечении. Ваши лучшие инструменты - это заранее продумать и осознать свой дизайн и свести к минимуму те способы, которыми вы, возможно, жестко закодируете себя в коробке.