Интервью по системному дизайну - Проектирование платежных систем; Дополнительные вопросы и возможные проблемы

Интервью по системному дизайну - Проектирование платежных систем; Дополнительные вопросы и возможные проблемы

10 ноября 2022 г.

Исходный

У нас будет благотворительная акция, которая продлится 3 дня (скажем, с пятницы по воскресенье). Мы хотим собрать 100 миллионов долларов, и будет 10 благотворительных организаций, поэтому каждый пользователь нашей системы может решить, куда он / она хочет пожертвовать деньги. Можно предположить, что клиентская часть готова, а также у нас есть соглашение с какой-то сторонней платежной системой, поэтому нет необходимости обрабатывать денежные переводы с одного счета на другой. Также нам нужно собрать все деньги на один банковский счет и после завершения мероприятия нам нужно как-то распределить собранные деньги между всеми 10 благотворительными фондами. И последнее, о чем следует упомянуть, это то, что нам нужно обработать любую ошибку, с которой мы можем столкнуться при обработке платежа.

Функциональные требования

  • Обработка транзакций с использованием сторонних сервисов (поставщиков платежных услуг, таких как Stripe, Braintree и т. д.)
  • Отслеживайте, какие пожертвования относятся к определенной благотворительной организации (чтобы иметь возможность распределить все пожертвованные деньги между благотворительными организациями).

Нефункциональные требования

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

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

:::подсказка Обычно план собеседования по проектированию системы выглядит так:

  1. Функциональные требования
  2. Нефункциональные требования
  3. API
  4. Структуры данных
  5. Дизайн высокого уровня
  6. Подробнее о дизайне
  7. Подведение итогов

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

:::

Дизайн высокого уровня

  1. Пользователь отправляет форму в пользовательском интерфейсе (форма содержит информацию о кредитной карте, идентификатор благотворительной организации и сумму денег, которую пользователь хочет пожертвовать этой благотворительной организации.
  2. Веб-сервер вызывает PSP для проведения платежа.
  3. PSP ответила подтверждением того, что платеж прошел успешно
  4. Веб-сервер сохраняет данные в БД

Проблемы с этим дизайном:

  • пользователь дважды нажал кнопку отправки, что произойдет в этом случае? Система выполняет 2 разных платежа?
  • при работе с конфиденциальными данными, как обращаться с информацией о кредитной карте?
  • как сделать систему надежной и отказоустойчивой?

Нажмите кнопку «Отправить» несколько раз

Мы можем решить эту проблему несколькими способами:

  • у нас могут быть некоторые ограничения JavaScript, но это не поможет, если пользователь отключит JavaScript в браузере. Это также не так надежно, поскольку пользователи могут попытаться изменить ваш код javascript (вместо того, чтобы вы запутали свой код, чтобы сделать это действие практически невозможным)
  • обеспечить идемпотентный API с двухэтапной обработкой.

Давайте рассмотрим второй подход. Во-первых, мы предоставляем страницу с раскрывающимся списком 10 благотворительных организаций, суммой, которую пользователь хочет пожертвовать, и кнопкой «Далее»:

First step, Checkout page

После этого мы сгенерируем UUID из PSP и сохраним его в своей БД, после сохранения данных перенаправляем пользователя на страницу оплаты:

Second step. Payment page

Весь процесс будет выглядеть следующим образом:

2-step processing flow

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

Размещение страниц кредитных карт, предоставляемых PSP

Хранение информации о кредитных картах — непростая задача, поскольку нам необходимо соблюдать сложные правила, такие как Стандарт безопасности данных индустрии платежных карт (PCI DSS) в США. Большинство компаний избегают хранения информации о кредитных картах и ​​вместо этого размещают платежные страницы, предоставляемые PSP. Вот пример оплаты Stripe:

Second step. Picture

https://stripe.com/payments/checkout?embedable=true

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

Сверка

Вот весь процесс:

На шаге 4 наша запись в таблице транзакций будет выглядеть так:

| идентификатор (пк) | благотворительный идентификатор (fk) | сумма | статус | обновлен | |----|----|----|----|----| | UUID123 | 1 | 500 (строка) | в процессе | отметка времени |

У нас будет поле статуса, которое указывает текущий статус транзакции.

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

:::

На шаге 8 PSP вызывает наш веб-перехватчик и подтверждает, что транзакция успешно завершена. После этого мы можем изменить статус на Завершено.

| идентификатор (пк) | благотворительный идентификатор (fk) | сумма | статус | обновлен | |----|----|----|----|----| | UUID123 | 1 | 500 (строка) | завершено | отметка времени |

Если между шагами 1–4 что-то пошло не так, мы просто не сохраняем данные в БД, и наша БД остается согласованной.

Если между шагами 4–8 что-то пошло не так, мы можем предоставить процесс согласования, который будет периодически считывать таблицу транзакций и проверять все транзакции со статусом в процессе и отметкой времени старше, чем X, и отправлять такие записи в выделенную очередь, чтобы финансовый отдел мог обрабатывать ее вручную. Или, если PSP предоставляет API для проверки транзакций по идентификатору, мы можем автоматизировать его.

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


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE