Эксперименты. Или как понять, удачная ли была фича? +2


А в чем, собственно проблема?

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

Как делать не надо

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

Уже лучше

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

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

Правильный подход

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

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

Технические подробности

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

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

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

if (FeatureToggle.isEnabled(clientId, experimentId)) {
  button.setColor(newColor);
}

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

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

Недостатки

Однако как и любое решение, это не обошлось без крупных проблем, я бы сказал их оказалось две:

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

  2. Мусор после экспериментов. После того как эксперимент закончился в большинстве случаев условие из кода никуда не девается, просто эксперимент конфигурируют таким образом, что 100%пользователей попадают в группу “включено”. Из-за этого сложность кода сильно растет со временем и приходится выделять отдельные спринты или релизы на вычистку старых, неиспользуемых условий.

Как жить дальше?

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




Комментарии (4):

  1. OlegZH
    /#24603606

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

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

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

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

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

    Эффективность разработки можно оценить ещё и по тому, что мы обнаруживаем в самом конце разработки:

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

    Всегда хочется спросить, что мы должны были знать и уметь в самом начале, чтобы сразу придти к конечному результату. Вот этот сухой остаток и есть то, что мы должны запомнить и обобщить. Можно ли было пройти прямо? Да, можно было. Но для этого надо было долго думать, а уже потом делать. (Семь раз отмерь...) Довольно трудно действовать, когда конечная архитектура неизвестна.

    Подход, основанный на экспериментировании, конечно, представляется любопытным. Но здесь не хватает последнего шага. А именно: понимания того, что система на этапе разработки это ещё не конечная система. Система на этапе разработки — это имитационная модель. Попробуйте просто поставить всем сотрудникам компании сетевой мессенджер с обязательством вести все дела через этот мессенджер. Обеспечте пользователей средствами описания сущностей, операций над сущностями и представлением о номенклатуре решаемых в данной организации прикладных задач. Вы довольно быстро получите рабочий макет системы и набор репрезентативных экспериментальных данных. И только потом, когда возникнет точное соответствие между деятельностью и её визуальным и алгоритмическим обеспечением (типичный градиентный спуск в многомерном параметрическом пространстве!), можно будет сделать релиз системы без лишних элементов, "фич" и других плохо документированных возможностей. (Не понимаю, почему так никто не делает? Хотя, кажется, что так должны действовать все.)

    • funca
      /#24603810

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

      Мне кажется Microsoft Teams развивается каким-то таким путем и это уже который год самый ужасный мессенджер.

    • Akon32
      /#24603838 / +2

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

      Результатом будут огромные неструктурированные кучи сообщений, при работе с которыми даже поиск не помогает. И это уже при 3-4 человеках в чате!

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

      То есть разработкой системы будут заниматься пользователи? Или пользователи станут программистами? Рядовой пользователь не очень умеет в "описания сущностей", "описания операций над сущностями". Для получения этих описаний нужны как знания прикладной области, так и знания ИТ.

      Система на этапе разработки — это имитационная модель.

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

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

  2. gdt
    /#24603926

    Хотел бы я иметь возможность рассказать про наработки в этой области. Все верно, примерно так и делается. Только вот, например, если хочешь показать новую фичу N% пользователей — можно просто поделить device id на 100 и взять остаток, если он меньше N — показать.