Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Январь этого года был для меня не только чередой праздников, но и поводом отметить год, как мы полностью переехали на новый платежный шлюз. Для нас, как для сервиса подписки на духи, это одна из ключевых систем и если с ней есть проблемы, то это касается всех в компании. Сам переезд можно сравнить с хорошей книгой: есть экспозиция - проблемы с прошлым сервисом, завязка как мы делали выбор между своей разработкой и готовым сервисом, развитие действия - когда мы начали работать над архитектурой и делать первые коммиты, кульминация - момент первого запуска и первые проблемы с ним и развязка, когда мы закончили миграцию всех клиентов. Звучит интересно? Тогда добро пожаловать под кат.
Сначала, пару слов про наш бизнес. Scentbird - это сервис подписки на духи и одеколоны в Штатах. Раз в месяц клиент автоматически платит нам $16 и мы шлем 8 мл духов по его/ее выбору. В целом, все очень просто, но дьявол кроется в деталях. Какие есть особенности у подписочных сервисов, связанные с оплатой:
Разнообразие планов - масса нюансов по переходу с плана на план, отмена плана при предоплате и так далее
Управление подпиской - пауза, пропуск месяца, отмена
Восстановление клиента, когда из за ошибки (нет денег на карте, проблемы у банка, и тд) не прошел платеж
Финансовая отчетность и все с ней связанное
Как правило, подписочные сервисы, используют сторонние решения, хорошие известные на рынке: Stripe, Recurly, Chargebee, Vindicia и так далее. Все эти сервисы умеют все вышеперечисленное плюс каждый пытается предложить что-то свое, как правило это фокус на восстановление подписок или полезные интеграции. Есть еще один вариант - построить свое с нуля. Таких примеров тоже хватает, в частности HelloFresh (один из крупнейших mealkit сервисов) пошел именно таким путем.
Часть первая. Направо пойдешь - коня потеряешь… (Народное творчество). С чего все началось.
В начале 2020 года мы использовали сервис Vindicia, на который мы в свое время перешли по причине того, что они очень хорошо восстанавливали клиентов, у которых не прошел платеж (этот процесс называют либо recovery, либо dunning). Но со временем меня как СТО перестали устраивать цена, скорость работы (иногда между инициацией платежа и фактическим платежом проходили сутки) и техническая поддержка (нам пришлось выстроить логгирование каждого шага, потому что на той стороне особо логов не было и приходилось доказывать все). При 400 тысячах активных клиентах и нескольких сотнях тысяч прошлых клиентов это весьма серьезно. Поэтому мы решили мигрировать и первым шагом, надо было определить куда - стороннее решение или свое.
Первое, с чего я решил начать - составить список функционала, который нам требуется. Вот что получилось:
One time charges (capture/refund/void) - разовые платежи
Subscription Plan Management - управление планами
Subscription management (change next billing day, change plan, etc) - управление подпиской
Recurrent charges - повторные платежи
Recycling logic - логика восстановления
Fraud prevention - защита от фрода
Discount management - управление скидками
Taxation - расчет налогов
Customer health management (i.e. double charge prevention) - мониторинг ошибочного статуса клиента
Technical monitoring (performance) & logging - технический мониторинг
Security
Alternative payment methods support (PayPal, ApplePay, Google Wallet)
Analytics & Dashboards
Mobile SDK
Chargeback management - работа с чарджбэками (когда клиент обращается банк и тот отменяет транзакцию)
Затем побеседовав с представителями интересующих нас сервисов получилось собрать вот такую табличку:
Сравнив эти же сервисы по цене, стало понятно, что Recurly выглядит наиболее интересно. А как насчет своей разработки?
Согласно анализу, нам бы потребовалось:
Участие 4 разработчиков в как минимум на 5-6 месяцев активной разработки
Доработки инфраструктуры
Постоянная команда на поддержку и доработку сервиса
Регулярное прохождение аудита на предмет PCI DSS
Да, мы бы серьезно сэкономили в короткой перспективе и стоимость сервиса не росла бы с ростом количества транзакций, но иметь на балансе приложение, которое не лежит в области нашей ключевой экспертизы смотрелось не очень привлекательно, поэтому пошли по пути интеграции с внешним сервисом. Это, кстати, одна из самых больших головных болей любого технического директора - покупать или строить самим. Серебряной пули тут нет и в конце решает рост бизнеса или его потеря.
Полный анализ можно посмотреть по ссылке.
Часть вторая. Планы — ничто, планирование — все. (Приписывается Хельмуту фон Мольтке). Делаем план проекта.
Основная сложность при переезде на другой платежный шлюз - это миграция данных пользователей. Малейшая ошибка в логике и вам пишут сотни (тысячи) раздраженных пользователей уже шлют вам лучи ненависти и все ваши бизнес метрики идут на дно. Поэтому переход надо делать поэтапно, при этом важно помнить и про различные платежные методы людей, и про различные статусы и так далее.
Чтобы учесть все это и многое лучше запастись планом. Пойдет ли все по плану? 100% нет, но планирование тем не менее полезно. Основные элементы документа:
Таймлайн - включает фазы проекта и когда они начнут/закончатся (спойлер, проект занял на 2 месяца больше, чем мы думали)
Метрики успеха - что мы меряем по итогам проекта, чтобы понять, был ли смысл в миграции
RACI Matrix - показывает кто и за что отвечает в проекте (чтобы потом не говорили, что чье-то мнение не учли) Пример ниже
Функциональные требования - это все должно потом 1 к 1 быть отражено в таск трекере
План по миграции данных
Риски и план по работе с ними
Про план миграции расскажу отдельно.
Во-первых, важно понять, как переносить платежные данные. Мы работаем с 4 платежными методами:
ApplePay
PayPal
AmazonPay
CreditCard
Самое простое было с AmazonPay и PayPal - мы знали так называемые agreement id (уникальный id, который выдается в момент авторизации платежа), что позволило нам просто создать подписку в Recurly, задать нужные даты следующего платежа и собственно все. Опять же, это стало возможно только потому, что у Recurly был нужные метод в API, что опять же говорит о важности правильного выбора партнера.
Примерно такая же история обстоит с ApplePay. При авторизации платежа шлюз получает JSON, который можно потом использовать для проведения повторных транзакций и трансфера данных. К сожалению, тут нас подвел наш старый шлюз - у них этих данные не было.
Но самая интересная история обстоит с передачей данных о карточках. Во-первых, оно делается без участия с нашей стороны, это дело шлюзов. Во-вторых, оно занимает достаточно длительный промежуток времени. В-третьих, как правило шлюз дает бесплатно сделать один импорт, а каждый последующий будет стоит дополнительных денег. Поэтому тут очень важно правильно управлять тем, как вы переключаете шлюз в боевых условиях.
Это вторая важная часть по работе с данными. Следует очень осторожно включать новый шлюз на проде, потому что если вы, например, не выкатили весь функционал сразу, то часть ваших пользователей не смогут заплатить за ту или иную услугу, что негативно скажется на бизнесе. И тут у вас есть две опции - либо сначала перевести весь функционал на новые рельсы и потом уже переводить клиентов, либо по правилу 80-20 перевести часть и затем смириться с потерями, зато рано начать получать обратную связь.
Мы пошли по второму пути, потому что закрыв сценарии подписки, смены плана, разовой транзакции, отписки и паузы мы смогли закрыть большинство клиентов и могли начать пускать их в новый шлюз.
Возвращаясь к миграции клиентов. Благодаря тому, что мы могли сами переносить клиентов на PayPal/AmazonPay, то за 3 подхода (1000/20000/все остальные) мы перенесли всех и смогли проверить все сценарии до того, как перенесли клиентов на карточках.
Часть третья. Главное- ввязаться в драку, а там посмотрим! (Наполен Бонапарт). Создаем архитектуру и настраиваем интеграции.
Как вы понимаете, самое интересное началось, когда мы начали разработку. В начале пару слов про имплементацию. Ниже будет пара схем, которые упрощенно объясняют, что было сделано. Начнем с бизнес логики:
Выделю основные моменты. Во-первых, мы сами теперь поддерживаем механизм скидок. Почему? Потому что каждый шлюз имеет свои ограничения, а вот команда маркетинга их не имеет. Так и появляются скидки на несколько месяцев с уменьшающейся суммой, третий месяц бесплатно и так далее. Кроме того, у нас много акций, завязанных на физическую составляющую (например, подарок в первый месяц) и важно это учитывать в инвойсах.
Во-вторых, как раз сами инвойсы. Это важный артефакт для команды финансов, потому что именно инвойс является документом, который надо предоставлять при аудите, инвойс содержит четкое описание всего, за что оплатил клиент и позволяет правильно рассчитывать финансовые метрики. Так же, у техподдержки всегда должна быть возможность сделать рефанд за любую строчку из инвойса. Так что аккуратность наше все.
В-третьих, механизм аддонов. Аддон это платное дополнение к подписке. Например, мы таким образом делаем дополнительные платежи за доставку в Канаду или дополнительная подписка, которая доступна только в таком случае, если есть основная подписка. Плюс это дает возможность какие-то хитрые изменения самой подписки, например, провести тест повышения цены основной подписки.
На схеме выше показано, как изменилась общая архитектура. Правильно, почти никак и это было целью. Мы по-прежнему обрабатываем входящую информацию через связку API Gateway (чтобы оставить сервис внутри VPC) + AWS Lambda + Rabbit. Мы по-прежнему сохраняем данные этих ивентов на S3 в целях логирования. И так далее. Подобная система показала свою надежность, поэтому мы решили не менять.
Из забавных моментов. У нас есть ряд интеграций в нашем аккаунте, среди них защита от фрода Kount и сервис расчета налогов Avalara. Ни у тех, ни у других нет тестового окружения:
У Kount его нет вообще, там прод обслуживает все интеграции. Это важно, потому что мы им платим за количество проверенных транзакций, так что на тесте у нас эта интеграция выключена
У Avalara тестовое окружение платное, стоит около $15k в год и доступно только на ограниченное время, поэтому на тесте стоит сервис от самих Recurly. В чем проблема? Налог в e-commerce считается до уровня каждого line item и зависит от tax code. Естественно, Recurly ничего это не поддерживает, потому сумма налога может отличаться на проде и тесте.
Часть четвертая. Только дураки повторяют свои ошибки, умные — совершают новые. (Народная мудрость). Что в итоге пошло не так и как мы с этим справлялись.
А теперь самое интересное - какие ошибки мы (я) совершили в рамках этого проекта.
Ошибка первая - сколько бы умных программистов не собралось вместе, все равно нужен кто-то кто будет играть роль менеджера и собирать вместе. Мы начали этот проект силами 2х principal engineers и 2 senior engineers. Ребята все делали правильно, но были проблемы с фокусом и прозрачностью. Ну и все мы знаем, что программисты любят решать инженерные задачи, а не бизнесовые.
Ошибка вторая - недостаточный анализ зависимых систем. В рамках перехода на новый шлюз мы также решили обновить внутреннюю CRM систему для тех поддержки. Проблема в том, что без человека, который отвечает за проект и продвигает нужные задачи, это сделано не было, данный функционал съехал по времени и задержал миграцию клиентов.
Ошибка третья - недостаточное вовлечение представителей других менеджеров в обсуждение плана миграции. Вот это наверное самая большая моя ошибка, потому что как только речь зашла про миграцию клиентов, то со стороны финансов и технический поддержки резко встал вопрос “А как мы поймем, что все хорошо” и просьба добавить дополнительные отчеты и мониторинг. Все это так же сдвинуло сроки.
Ошибка четвертая - оптимизация задач под разработчика. Для того, чтобы закончить быстрее каждый разработчик отвечал за свою область и практически не залезал в код соседа, кроме ситуаций с code review. В итоге проблема с bus factor и с тем, что у разработчиков из других команды были местами вопросы по реализации.
Проблема пятая. Во время миграции данных карточных клиентов выяснилось, что старый шлюз не делал никакой нормализации данных на своей стороне и во время импорта данных клиентов в некоторых случаях были ошибки. Таких клиентов пришлось переносить уже руками.
Итоги
Что же в итоге? В итоге с опозданием на 2 месяца мы закончили проект. Сейчас год спустя можно со 100% уверенностью сказать, что мы достигли своих целей:
В три раза уменьшили оплату за шлюз
Решили проблему с экстра платежами из-за багов на стороне шлюза
В два раза увеличили скорость обработки данных о рекуррентных платежах, что позволило на день раньше начать отправлять посылки
Пишите в комментариях, что еще из технических решений и проблем подписочных сервисов вам было бы интересно узнать.