Если в какой-то момент вы захотите сразу перейти к работающему коду, он доступен здесь (и в разделе реализации).

Opendoor уже два года работает с Cloudflare Workers в производственной среде. Cloudflare Workers — это бессерверная среда выполнения, которая позволяет Javascript перехватывать, выполнять и изменять входящие запросы на уровне CDN (отличный обзор см. в Докладе Эшли Уильямс на JSConf EU). Рабочие процессы достаточно легкие, чтобы запускаться перед каждым запросом, и предоставляют мощные строительные блоки для выполнения общих операций, таких как проксирование, настройка заголовков и тому подобное. В Opendoor работники изначально были развернуты для обработки одного варианта использования, прокси-запросов от opendoor.com/w/* к нашему внутреннему экземпляру Wordpress. Наш рабочий процесс позволяет объединять необходимые пакеты npm, имеет полное тестовое покрытие и активно итерируется разработчиками в Opendoor каждый день. (Бонус! Он написан на машинописном языке и на машинописном языке Opendoor ❤). Со временем их полезность, простота использования и постоянно расширяющиеся возможности привели к взрывному росту вариантов использования; теперь они запускаются перед каждым запросом к веб-ресурсу Opendoor.

Cloudflare Workers поддерживают нашу инфраструктуру целевой страницы и позволяют нам:

  1. Проведите A/B-тестирование старой и новой инфраструктуры.
  2. Проведите A/B-тестирование двух разных дизайнов целевых страниц.
  3. Проведите несколько A/B-тестов на различных вариантах нашего нового дизайна.
  4. Упростите работу разработчиков в новой инфраструктуре

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

Задний план

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

  1. Перепишите наши целевые страницы с новой инфраструктурой/фреймворком (оптимизированным для повышения скорости страницы, в данном случае nextjs) с существующим дизайном и внедрите его (гарантируя, что конверсия будет плоской или положительной).
  2. A/B-тестирование нового дизайна и старого с новой инфраструктурой
  3. Проведите несколько экспериментов над выигрышным вариантом, чтобы повысить конверсию.

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

Архитектура

При поступлении запроса есть несколько высокоуровневых шагов:

  1. Идентифицируйте пользователя (или создайте личность, если это новый пользователь)
  2. Выберите экспериментальную группу, к которой назначен пользователь (или к которой он был ранее), и удовлетворите его запрос на этот контент.
  3. Зарегистрируйте пользователя и вариант для использования в анализе конверсий.

Во всех экспериментах есть две общие черты: экспериментальная платформа (Optimizely) и отдельный идентификатор пользователя (хранящийся в собственном файле cookie в домене opendoor.com). Три области A/B-тестирования: инфраструктура, дизайн и вариация. Каждую из них нужно развернуть, измерить, и победителем объявляется либо A, либо B. Мы не можем смешивать и сопоставлять эти три категории, или существует слишком много переменных, чтобы их можно было изолировать при анализе. Чтобы достичь этих целей, мы должны решить, где находится общая инфраструктура.

Наша первая экспериментальная область — сравнение старой и новой инфраструктуры. Это два отдельно развернутых сервиса, первый обслуживается из нашего развернутого монолита рельсов heroku, второй — это служба размещенного узла kubernetes, на которой выполняется рендеринг nextjs на стороне сервера — они различаются в зависимости от хоста (например, heroku.opendoor.com против k8s.opendoor.com). Затем наш проектный тест выполняется на выбранной обслуживающей инфраструктуре. Каждый вариант дизайна будет находиться на одном хосте, но не будет иметь общего кода. Наконец, мы протестируем варианты победившего дизайна (заголовки, призывы к действию и т. п.). В основном это будет один и тот же код с условными вариациями. У нас есть два варианта, учитывая эти требования.

Вариант 1. Экспериментируйте с логикой в ​​коде приложения

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

Вариант 2. Поэкспериментируйте с логикой, прежде чем переходить к коду приложения

Если логика эксперимента запускается перед кодом приложения, мы можем кэшировать запросы к нашему серверу и определять, какую инфраструктуру следует затронуть, прежде чем они попадут в код приложения. Это вводит требование, чтобы наш URL-адрес запроса был единственной зависимостью данных для серверной части. Это требование также упрощает работу с разработчиками, поскольку при разработке нет необходимости имитировать или подделывать экспериментальные группы. Бэкэнд nextjs даже не знает, кто такой пользователь, он отображает исключительно на основе URL-адреса запроса.

Решение: Вариант 2

Поскольку Cloudflare Workers может запускаться перед каждым запросом, получать различные серверные части, читать и устанавливать пользовательские файлы cookie, а также загружать и запускать пакет SDK Optimizely Javascript, мы использовали их для реализации варианта 2. Когда приходит запрос, мы проверяем экспериментальные группы пользователя, а затем форматируем восходящий запрос с работником. Рабочий меняет хост для теста инфраструктуры, путь для теста дизайна и параметры запроса для теста вариантов. Поскольку URL-адрес запроса является единственной зависимостью данных, все это также кэшируется на границе.

Выполнение

При каждом запросе лендинга наш воркер делает следующее:

  1. Сопоставьте запрос с путем к целевой странице (GET + $landing_page_path)
  2. Разберите файл cookie «anonymous_id» (сгенерируйте случайный uuid, если он отсутствует)
  3. Проверьте, в какой экспериментальной группе находится пользователь (это стабильное назначение на основе идентификатора пользователя).
  4. Получить содержимое для URL-адреса, связанного с этой группой (и вернуть ответ пользователю, обычно кэшированный)
  5. Зарегистрируйте задание эксперимента

Полный рабочий пример концепций, описанных в этом сообщении в блоге (включая образец инфраструктуры, дизайн и тесты вариантов), доступен в виде шаблона Cloudflare Workers с использованием следующих команд. Это включает в себя всю конфигурацию, необходимую для интеграции Optimizely с воркером (включая рабочую конфигурацию веб-пакета, связанные библиотеки и управление файлами cookie):

Упрощенный пример рабочего кода для этого выглядит следующим образом:

Если у вас есть какие-либо вопросы или отзывы, не стесняйтесь открывать проблему в связанном репозитории или обращаться в Twitter (@defjosiah).

Выводы

В конце концов, нам удалось успешно провести все запланированные A/B-тесты на этой новой инфраструктуре целевой страницы. Логика Cloudflare Worker была надежной (частично благодаря нашей стратегии тестирования), и мы не сталкивались с какими-либо производственными проблемами. Разработчики любят работать с этим сервисом, а добавлять новые функции и эксперименты легко (в основном из-за требований к URL-адресу запроса). В центре внимания этого поста нефактические результаты конверсии; но нам удалось успешно повысить конверсию с помощью новой инфраструктуры (благодаря повышению скорости страницы), выпустить новый дизайн целевой страницы и, наконец, провести ряд успешных экспериментов с вариациями. По сравнению с реализацией одноразового прокси-сервера (nginx или аналогичного) с этими функциями, Cloudflare Workers — это проще простого.

Быть в курсе

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