Активная аналитика для вашего проекта
Возьмем за условие задачи e-commerce проект (интернет-магазин или другой b2c интернет-сервис). Наделим этот магазин классной командой: внятным руководством, скорыми на честные решения маркетологами, гибкой разработкой (готовой быстро реагировать на изменяющиеся требования). Дадим ему некоторый уровень количественной успешности (пусть будет от 1000 заказов в сутки). Предположим что проект этот — пока еще стартап (или недавно им был). И он когда-нибудь обязательно захватит мир. Но пока что не сподобился внедрить систему разряда ERP/CRM для работы с большими объемами заказов/клиентов.Что обычно происходит в активной стадии развития такого бизнеса? Маркетинг всеми силами изыскивает способы:
расширить аудиторию и каналы привлечения клиентов; увеличить качество услуг; реализовать программы лояльности для удержания хороших клиентов; развивать партнерские сети. И вычитывает и выдумывает другие мирозахватнические бизнес-модели.
А в разработку получаем очередь гениальных и не очень (но обязательно срочных) задач. Затрагивающих все процессы от приземления клиента на сервис, до многократного его обслуживания. Программная часть бизнеса быстро варится с вермишелью из логики регистрации новых клиентов, оформления ими заказов, расчета стоимостей/тарифов, способами оплаты заказов/услуг, формирования персональных рассылок, индивидуальных и групповых скидочных предложений, проведения акций и так далее.
Маркетинг, который на старте бизнеса довольствовался отчетами типа «средняя сумма заказа за месяц» теперь хочет «среднюю сумму заказа без специальных предложений в сравнении за две недели января и такие же две недели сентября для группы клиентов сделавших более чем 1 заказ за последние полгода и зарегистрированных более 2-х лет назад, и еще отдельно пожалуйста клиенты такого-то и другого пола, а еще лучше чтобы они ни разу не обращались в колл-центр, а еще разделите все это отдельно по каждому каналу привлечения клиентов и по лунным фазам тоже»…
От торопливости и безысходности, база активно зарастает мусорными вспомогательными таблицами и полями, которые не нужны никому (кроме маркетологов). Счастливый маркетинг развивает успешные и отбрасывает в сторону неуспешные бизнес-модели. Поля и целые таблицы остаются навсегда. Сделанные на скорую руку отчеты при росте клиентской и коммерческой базы вскоре перестают укладываться в разумные пределы нагрузки на систему, требуют вынесения в фоновые задачи (если не на отдельный сервер) и хотят репликации базы. Или еще веселее: маркетолог «выучил sql» и сидит в вашем сервере напрямую, периодически бегая к админу с просьбой кильнуть этот «не знаю почему долго выполняющийся запрос».
А структура базы выглядит примерно так (не самый плохой вариант):
Почему это «плохо»? Потому что связка users-orders-payments должна решать задачу получения клиентом услуги и ее оплаты. Как только мы даем этим сущностям любые посторонние задачи, мы увеличиваем опасную связность через весь workflow.
Жизненный примерДля начала представим себе упрощенный прямой цикл продажи в e-commerce (с точки зрения самой важной его части — клиента):
Для того, чтобы этот процесс выполнялся качественно, быстро и с минимальным количеством логических ошибок (у клиента при заказе все должно быть «тип-топ», иначе сорвется с маркетингового «крючка»), в нем не должно быть ничего лишнего (и вероятность наполнить багами — минимальна).
Но вот приходит маркетинг и говорит:
После регистрации нужно отправить клиенту письмо. А если клиент зашел с акции, то в нем заменить «привет» на «здравствуйте». А может быть он с заказа на пробный период сервиса — тогда совсем другой шаблон. Если клиент долго не приходил, то отправить ему письмо-напоминание. Если клиент пришел, но быстро ушел, то отправить-письмо-спросить-почему. Если пришел и потоптался N минут, ничего не положив в корзину, предложить скидку. А еще прокинуть track-id от партнеров, чтобы потом поделиться процентом по заказу. И это только один кусочек из всей цепочки. Дальше будет только «хуже». Вы согласны, что сам клиент в этих задачах никак не участвует и его потребность эти тайные интриги не удовлетворяют? И когда вы будете программировать все эти условия прямо в вашем классе (компоненте/контроллере), который обрабатывает заходы и регистрации клиентов, то код этого класса будет все толще, а зависимостей в нем — все больше. И этот класс уже не регистрирует клиентов! Точнее не только регистрирует: он отправляет письма и принимает при этом сложные решения (и еще на гитаре научится играть — гарантированно). Вы молодец, если выделили письма в отдельный компонент, но и этот компонент постоянно рискует начать обращаться к базе клиентов и истории их заказов, чтобы решить какое письмо отправить и в итоге научится играть на рояле (уверен, сам когда-то учил).
И теперь все работает как-то так (и это еще только начало):
Для продолжения рассчитываю на то, что проблема понятна и даже знакома.
Но вот внезапно внятное руководство не только услышало об этой проблеме, ни предоставило «зеленый свет» на ее решение. Аттракцион щедрости: целый разработчик, специалист по рассылкам, генерации отчетов с графиками и эксель-выгрузками. Или вы счастливый владелец оффера на разработку проекта с нуля. Какое бы теперь ТЗ составить, чтобы «забыть» о влиянии маркетинговой активности на основной (четкий и стабильный) бизнес-процесс?
Решение есть, нельзя не съесть Предлагаю один из вариантов решения, который удовлетворит разработчиков-сторонников принципов SOLID, шаблонов проектирования, TDD и DDD и других красивых терминов. Это решение родилось из уверенности, что всегда можно просто взять… и выставить маркетинговый функционал за дверь вашего важного клиентского процесса (и никогда не впускать обратно).
И сделать это конечно — событиями. Берем маркетинг, просим его отойти от нашей простой системы в уголок, и начинаем бросаться туда информацией:
Теперь все задачи из списка «Но вот приходит маркетинг и говорит» — могут быть решены отдельно. Ваша основная система девственно чиста от маркетинга, он может сам решать свои задачи, сам отправлять письма и решать когда это нужно сделать. Исходных данных у него значительно больше, чем в «чистой» базе проекта. Потому что при получении данных события, аналитический модуль может разложить их по детальным полочкам и даже выполнить все сопутствующие действия (отправить письмо, в нашем случае):
сохранить в отдельных полях и год-месяц-день для облегчения будущих отчетов/срезов; аккумулировать счетчики по истории (например, который по счету посмотрен продукт данным клиентом?); детально проследить за поведенческой цепочкой конкретного клиента; сделал ли он это в рамках одной сессии или цепочку действий нужно прервать; отправить всю нужную информацию во внешнюю аналитику; на основании истории поведения клиента и источника его появления, сформировать правильное письмо; формировать список популярных продуктов/услуг, «с этим товаром часто покупают»; и так далее, и тому подобное. Представьте себе, если все эти нюансы рассчитывать на лету (или позже в отчетных скриптах) и сохранять в основной базе?
В нашей же схеме условная задача «отправить письмо» становится отделённой и не угрожает главному процессу. Получается вполне себе CRM-модуль (и анализ, и принятие решений, и их исполнение), который может быть даже кривым до безобразия, со страшной (под свои задачи) денормализированной базой, кучей всяких разных вспомогательных полей в таблицах, тормозами, плохо написанного кода… Но это не важно, потому что оно далеко в «маркетинговом углу» (идеально — физически на другом сервере) и клиентского процесса никак не касается.
И ведь ничего особенного в этом решении нет. Получился привычный такой паттерн «наблюдателя» с бросанием событий и их слушанием. Но в нашем случае нельзя реализовать паттерн «на месте», когда события услышаны и исполнены тем же процессом, который принял запрос от клиента, т.к. если мы косячим в «слушателе», то 500-е ошибки будут возвращаться из него точно также как и без всяких паттернов.
Поэтому подход будет хорош только когда:
вы сделаете его асинхронным и быстрым; и на отдельном серверном ресурсе код + базы данных (отдельным проектом); еще вам понадобится база данных с резервными копиями (это кроме основной базы самого аналитического модуля); и поддержка этой структуры понадобится как целого проекта… Ха! — подумаете вы. Стоит ли овчинка выделки? Пробуем оценить плюсы и минусы реализации отдельного «аналитического проекта»:
Интересно получается. Все минусы «отдельного проекта» лишь в том, что потребуется усложнить серверно-софтовую инфраструктуру, и реализовать ядро проекта для аналитики, которое предоставит интерфейсы для чтения событий и сохранения их в свою базу данных (от недели, до месяца в особо запущенных случаях на реализацию этого ядра). О минусе синхронизации — чуть ниже.
Факт что решение «так сделать» — зависит от проекта и его бизнес-моделей. И факт что не зря проекты посерьезнее закупают очень дорогие (во внедрении и поддержке) системы управления клиентами/заказами/складами и так далее. И ни в коем случае не доверяют этой работы интернет-площадке. А мы таким образом отделяем еще и «первичный» маркетинг со всеми его бешеными (бывает — одноразовыми) идеями и сложными отчетами.
И вот в чем заключается этот самый отдельный проект:
Вместо реализации сложной аналитики и косвенных процессов в главном проекте, мы передаем эту ответственность проекту аналитическому, реализуя только лишь надежный транспорт для событий (красная легенда). Это нужно будет сделать один раз и иногда поддерживать. В поддержку будут включаться задачи по выбросу новых событий из главного проекта и чтению их на проекте аналитическом. Но согласитесь: в случае программирования этих действий внутри главного проекта работы будет не меньше, а рисков что-нибудь сломать в нем — значительно больше.
Пара десертных ложек высококачественного дёгтя Есть значимый минус у данного подхода. Главному проекту не надо ничего знать про существование проекта аналитического (иначе смысл?). Но с аналитическим ситуация обратная. Ему скорее всего потребуется знать все процессы главного (т.к. придуман решать все задачи, которые тот решать «не захотел»).
Поэтому в процессе разработки во-первых, будет сложно (а часто и невозможно) решать задачи одновременно на обоих. В главном проекте появятся новые события —, а в аналитическом начнут обрабатываться значительно позже. Во-вторых, в разборе данных из очереди на аналитическом сервере может возникнуть программная ошибка или недостаточная денормализация, а задачи уже прочитаны… «поезд ушел».
Для решения этой проблемы задумана «база данных событий», которая хранит их (события) все от начала времен, включая (что важно) фотографичный контекст (в котором эти события происходили). Это нужно и для спокойствия души и затем, чтобы в крайнем случае всегда можно было бы выполнить полную перезагрузку созданной матрицы:
На аналитическом проекте исправляются ошибки и вносятся необходимые правки (до деплоя) Далее запускается деплой-сценарий: Останавливаем чтение данных из очереди (пусть копятся). Полностью чистим аналитическую базу Выкладываем все нужные фиксы Запускаем специальный скрипт, который в отдельную очередь (постоянно читаемую) отправит все ранее происходившие события. Снова включается чтение данных из основной очереди. В итоге аналитический «воркер» забирает данные из очереди так, как будто бы ничего и не было. Есть еще один очевидный минус — это сложности внедрения. Если вы решили так сделать, а у вас все уже «очень давно и плохо», вариантов немного и во всех придется хорошо подумать:
Отказаться от аналитики за прошедшее время (события копятся только с момента запуска аналитического проекта). Внедрить предложенную схему параллельно с текущими аналитическими разработками (общая аналитика — продолжают жить в главном проекте, новые штуки — в новом). Загрузить данные в «базу событий» единоразовыми скриптами за все ранее прошедшее время (имитируем жизненный цикл отправки событий задним числом). Но и бонусов тоже штук шесть у нас есть На основе чтения потока событий из основной системы, можно реализовать:
и удобные процессные логи (для операторов технической/клиентской поддержки — notice/warning/error); асинхронная рассылка событий по персоналу проекта (уведомления, напоминания; необходимости позвонить клиенту, проверить заказ, и т.п.); асинхронная рассылка коммерческих уведомлений (sms, email-ов, пушей) клиентам; генерация потоков «вторичных» событий по условиям аналитики (99-й клиент в этом квартале с чеком больше 1000 — отправить «письмо счастья»); простая перегрузка данных в уже готовые существующие системы OLAP анализа (QlikView, MS Business Solutions) в любое время и любое количество раз — и никакой боли по генерации интерфейсов для маркетинга и бизнес-анализа; простая подвязка и агрегация внешних источников событий и данных в единую БД (яндекс-метрика и т.п.); простая выдача доступа внешним партнерам (тому же коллцентру, они не будут «сидеть» в ядре вашего проекта); и так далее.