Ретроспектива: ecommerce
03 Jun 2020Год назад я ушел из healthcare стартапа, который являлся ecommerce для лекарств в штатах. Сразу после ухода я написал черновик с советами самому себе о том, что стоит делать сразу, а на что обратить внимание.
Черновик забылся на год, но, найдя записи в блокноте, выложил в паблик как ретроспективу основанную на опыте и боли. Каждый пункт - субъективный опыт и не претендуют на единственно верное решение. Если у вас есть похожие советы связанные с ecommerce - пишите комментарии, хочется собрать целый список. В будущем, можно будет сделать подобные списки и для других видов проектов.
Ордер и цены
Cart
- частный случайorder
. Вместо двух сущностей можно взятьorder
со статусомcreated
.- Купоны появятся. Делать купон отдельной сущностью - усложняет логику и добавит условий в чекаут и рефанд логику. Сегодня, если нужно будет делать добавить купоны в систему - сделаю купон отдельным айтемом с отрицательной ценой (скидкой).
- В
order_items
линковался наitem
иprice
из базы. Также, аналитики постоянно меняли цены на товары. Такая ситуация привела к мутациям ордера и было тяжело сказать, что и сколько стоило для ордера годичной давности. А пользователь получал не предсказуемый UX, так как возникала гипотетическая ситуация, что в момент чекаута цена на товар меняется и пользователь заплатит больше или меньше чем ожидает. Сегодня я бы помести в каждыйorder_item
JSONB поле для цены которое выглядело следующим образомJSONB: { added_at: '', price: ... }
. В таком случае нет непредвиденных мутаций, появляется версионирование данных. К тому же, это больше информации для аналитиков. - Датасайнтисты захотят менять цены, используя сложные паттерны расчета цены и кучу условий. Это приводит к постоянным изменениям цен в базе данных. Поэтому сформировалось правило, все что относится к ценам стоит как можно раньше изолировать в отдельный домен, сервис, rails engine, что угодно. Разделять стоит не только на уровне логики, но и на уровне данных. Вариант с JSONB полем - частный случай такого разделения.
Обсервабилити
- Мониторинг и логирование добавляют контроля и скажут что происходит или подскажут где проблема. Покрывать логами и мониторингом каждую строчку дорого, поэтому top1 кандидаты: все что связанно с деньгами, checkout&refund flow, изменения в данных, интеграции с партнерами, которые приносят деньги. Подход коррелирует с правилом “знайте, что происходит в частях системы, которые приносят деньги”.
- Работу с деньгами стоит начинать с логов. Если нет ELK или хранилища для логов в котором можно найти информацию без боли - используйте базу данны. Решение для старта - отдельная аудит таблица куда будет попадать информация от платежного шлюза. Такая информация будет полезна как в дебаге, так и аналитикам для создания моделей.
Архитектура
- Если в системе присутствуют мобильные устройства и другие виды клиентов (например b2b интеграции), значит стоит подумать о версионировании и заложить работу с версиями с самого начала. Кроме версионирования контроллера есть версионирование бизнес логики и версионирование данных.
- Если клиентов больше двух рекомендую почитать о BFF паттерне.
- Если событий нет в коде - вероятность появления крайне высока. Sidekiq не предназначен для event driven architecture, хотя помогает отодвинуть переход на новую архитектуру и работает для бэкграунд процессинга или в самом начале работы проекта. Поэтому стоит заложить в имплементацию последующее использование событий вне сайдкика.
- Код без событий для бизнеса и аналитиков - деньги на ветер. Стоит с самого старта проекта заложить, что события относящиеся к работе бизнеса нужно отправлять. Не обязательно использовать сложные решения или платить за SaaS продукты. Например, в собственных проектах шлю события в телеграм, а некоторые пишу в базу.
- Kafka как брокер событий с самого старта - провал. Это дорого и очень дорого. Если хоститесь в клауде - sqs или google pub/sub могут стать хорошим началом. Если нет - выбирайте из селфхостед аналогов. Также, стоит сразу подумать о прямой и обратной совместимости данных в событиях, а также о schema registry. Как хак подойдет отдельный репозиторий со схемами событий.
- Временное остаётся навсегда. Так технология добавленная на 2 спринта осталась в проекте на 2 года.
Данные и ETL
- В маркете возникает ситуация, когда регулярно надо загружать новые данные. Пример - цены на товары и сама информация по товарам. Вместо создания rake тасков для загрузки csv в базу, стоит посмотреть на ETL и заложить работу с ним в архитектуру. Из аналогов можно посмотреть на kiba (написан на руби) и Apache Airflow, написанный на питоне.
- Желательно подумать о том, как выгружать данные из приложения аналитикам заранее. Шарить дамп БД может оказаться быстрым вариантом, но в долгосрочной перспективе принесет проблемы совместимости между схемой данных в базе и схемой данных у аналитиков. Как альтернативное решение может подойти событийный подход. Но стоит заранее подумать о схеме данных, версионировании и обратной совместимости между версиями.
- Аналитики хотят видеть динамику по данным и делают из дампов за разные дни список изменений. Событийный обмен данными также поможет в этой проблеме.
- Если в домене присутствует специфический ID с определенной структурой - сделайте эту структуру на уровне базы и приводите к этой структуре в бизнес логике. Например, у нас был National Drug Code. Это строка которая может содержать
xxxx-xxxx-xx
(10 знаков),xxxxx-xxx-xx
(10 знаков),xxxxx-xxxx-x
(10 знаков) илиxxxxx-xxxx-xx
(11 знаков) значения. Спустя год разработки вскрылось, что система содержит три формата этого кода и часть системы поддерживает только десятизначный формат, а на одиннадцатизначном падает с ошибкой. Договорились о стандарте5-4-2
(11 знаков), сделали триггер на базу данных, чтобы лефтпадить значение до 11 чисел в строке (недостающие значения забивать нулями) и констрейн в базу данных на не больше 11 символов. В бизнес логике значение через лефтпад приводим к строке 11 символов (с нулями). В таком случае продюсер присылает данные в своем формате, а мы не боимся что в бд будет не валидное значение.
Нашли опечатку или ошибку? Буду рад если пошлете PR в гитхаб.