Приветики, меня зовут Петр и я алкоголик работаю продуктовым аналитиком вот уже лет 12 наверное. Мои основные профили это продуктовые рисерчи и эксперименты, причём тестирования в последние годы получается сильно больше.

В компании, где я работаю, мы решили таки внедрить потоковое АБ‑тестирование, и так как я был чуть ли не единственным аналитиком в команде с большим опытом работы с экспами, я и вызвался это всё разгребать и настраивать, тем более что к тому времени я уже пилил пет‑проектом микросервис чисто для себя, как раз для задач калькулирования экспериментов, а тут мне выпала буквально тестовая площадка для обкатки в бою.

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

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

Картинка интерфейса для привлечения внимания
Картинка интерфейса для привлечения внимания

Предыстория, про движок

Так получилось, что работать с АБ‑тестами я начал буквально с нулевой секунды, как попал в профессию. Тогда, в далеких 10-х не было практики содержания отделов экспериментов, да и даже просто аналитических отделов. Лучшее, на что могла рассчитывать компания — маркетолог, и, может быть, один штатный аналитик на все задачи.

И вот, значит, я прихожу в компанию на позицию UX‑аналитика, после решения тестового, где надо было (!) прокомментировать CJM, который они там себе набросали. Да, никаких алгосов, кейсов и тд, даже про SQL не спрашивали. Я туда пришёл не с улицы, до этого мы с корешем качали свою веб‑студию, в которой я выполнял задачи проектировщика сайтов. Поэтому разобрать CJM для меня было довольно просто.

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

Время шло, я впитывал всю инфу по тестам, что мог нагуглить, и спустя несколько лет и разных компаний, я вроде как разобрался в теме. Со временем у меня накопилось куча разных скриптов на разные методы/метрики и корнер‑кейсы. Тогда‑то у меня и возникла мысль это всё дело связать в единый батя‑скрипт, который бы сам подбирал какую часть в каких условиях прогонять, чтобы я не 20 скриптов прогонял, а 1 скрипт прогонял 20 своих модулей.

Легко сказать, но сделать уже не так просто. У меня ушло лет 5 на это, в основном потому что я забрасывал идею, упоровшись в какую‑то тогда «нерешаемую» проблему на stackoverflow, потом прозревал, возвращался к проекту и бросал, уткнувшись в новую.

Но в итоге оно сложилось и у меня получился довольно объёмный движок, который умел сам анализировать характеристики распределения, выбирать метод препроцессинга, оценивать «формат» эксперимента и выбирать нужный алгоритм из своей базы — семейства алгосов + фоллбеки на нестандарт + ситуативные надстройки под траф или множественные сравнения.

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

Так мы собрали стабильную версию движка, которая, однако, была очень уж сложной в обращении и требовала сначала перечитать кучу документации how‑to, которой (документации) и в проекте‑то не было.

Первый юзер, которому я пошерил код движка для сбора фидбека через 15 минут
Первый юзер, которому я пошерил код движка для сбора фидбека через 15 минут

И вот где‑то на этом этапе наша компания решила поставить АБ‑тесты на поток...

Организация процессов

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

Думал я.

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

Но first things first. Первым делом было решено вообще поднять систему сплитования экспов. Благо на рынке полно коммерческих решений разной степени сложности. Выделенный разработчик вообще хотел написать своё решение, что мы отмели сразу, хотя стоило бы прислушаться. Но в целом этот шаг у нас не вызвал проблем, мы взяли несложную готовую сплитовалку, переписали немного SDK под себя и погнали тестить на АА. Ожидаемо, всё завелось без проблем — трафф сплитовался ровно по заданному плану, рандомизация работала чётко и выдавала красивые результаты на АА и всё шло гладко. Этот вопрос закрылся планово.

А потом начались процессы.

Как и полагается в новоиспеченном бизнес‑юните, я начал проектировать форкфлоу работы направления и писать документацию для MVP. До этого я работал в разных командах и какая‑никакая насмотренность на разные подходы у меня была. Я прикинул что мне нравилось и не нравилось у разных ребят и вывел для себя ряд требований к процессам:

  1. Сбор заявок на проведение экспов должен быть вынесен в отдельный поток. Тут всё просто — создаём отдельный канал в корп. мессенджере, прикручиваем туда бота для заполнения заявки и сохраняем payload формы.

  2. Нужна площадка для хранения гипотез. Тут всё по классике, отдельная доска в Jira, карточки в которой появлялись из того бота выше. Автоматизация!

  3. Нужен понятный инструмент для планирования потока экспов. Вот тут стало чуть сложнее, потому что планироваться в Jira конечно можно, но не очень удобно глазами метчить даты старта и даты завершения. Поэтому мы подняли док в гугл щитс с кастомной диаграммой Гантта. Стало сильно удобнее, однако поддержка доки осуществлялась руками, из‑за чего впоследствии весь понедельник стабильно уходил на микроменеджмент тестов — что нового появилось в идеях, правки форм почти в 100% случаев и сверка дат и планирование в график.

Но это уже, в целом, была готовая обвязка по менеджменту гипотез и экспов. Поначалу оно даже хорошо работало, когда экспов было 3. Первое время так и жили. Главной проблемой на этом этапе было то, что никто не читал документацию по процессам (ну естественно!) и мне приходилось буквально каждого заинтересованного обучать как создать запрос, где мониторить, когда и где ждать результаты. Осложнялось это ещё и тем, что каждый инструмент был независимым и жил отдельно от остальных.

Постепенно команда впитывала культуру экспериментов, подключались новые заказчики из других отделов — «а чё вы там такое делаете интересновое? Нам тоже надо» и объём бэклога рос, а с ним и объёмы ручного менеджмента создаваемых артефактов.

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

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

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

В совокупности такая система работала, но была слишком требовательна в обслуживании. Вопрос объединения был на открыт.

Всё херня, Миша, давай по‑новой

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

Для бэка выбрал Django, база на Postgre, а фронт по классике через Tailwindcss. Довольно быстро собрал основу, но уткнулся в скорость обработки файла. Локально всё работало прекрасно, но после деплоя на сервер и тестах на датасете в миллион строк система захлебнулась, потому что я складывал содержимое большого датасета в Redis для передачи фоновой задаче) я тогда не понимал а что, собственно, не так, пока мы не пошли пить пиво с моим корешем, который по совместительству бэкендер. Он поковырял логи и предложил другую архитектуры для этих фоновых процессов, назвав мою чем‑то вроде убожества, и присоединившись к «команде».

В общем, не вдаваясь в нюансы, в которых я слабо шарю, весь бэк был потом переписан адекватным разрабом и оно наконец‑то нормально (и быстро) завелось.

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

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

Текущий вид интерфейса движка
Текущий вид интерфейса движка

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

Первое что мы туда добавили — это возможность сохранять результаты расчётов. Но просто сохранять таблицы было не весело, поэтому мы завели туда систему карточек, в которой накидывалось описание гипотезы, чтобы связать результаты расчётов с конкретным экспом. Причём карточки гипотез можно было заводить отдельно от результатов, тем самым создавая условный бэклог экспов. Впоследствии это заменит доску в Jira + бота, и заказчики станут сами заводить свои карточки.

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

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

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

Простая диаграмма Гантта для планирования запусков
Простая диаграмма Гантта для планирования запусков

Уже на этом этапе я притащил наработки в команду и мы начали обкатывать этот проект в боевых условиях.

Было много проблем и неудобств по мелочи, которые сложно было предусмотреть на стадии идей, но в боевом использовании они всплывали. Я выписывал их в блокнотик и впоследствии придумывал как их решить.

Со временем эта админка обрастала всё новыми и новыми фичами. Например, в качестве тулзы я написал на R калькулятор sample size, который учитывал бы не только альфу, мощность, метрику конверсии и mde, но и умел работать с непрерывными метриками, многовариативными тестами и непропорциональными весами вариантов.

Sample size calculator.png
Так он выглядит сейчас
Так он выглядит сейчас

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

Пример карточки активного теста с прогнозом на дашборде
Пример карточки активного теста с прогнозом на дашборде

И из последних апдтейтов прикрутили туда фичу для СЕО/CDO уровней — все тесты, которые вы проводите, собираются в единую стату для оценки всей программы экспериментов. Но тут лучше один раз глянуть, чем объяснять.

‑-

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

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

В работе мы уже отказались от доски + бота и экселя и полностью перенесли планирование сюда.

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

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

Потестить, покрутить, посмотреть можно по ссылке: https://ab‑labz.com/

В интерфейсе после реги доступен русский, на основной сайт особо смысла нет его ставить.