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

Ответ

Критический баг с двойным списанием средств в платежном шлюзе.

Контекст: Веб-приложение для онлайн-покупок. Пользователь нажимает кнопку "Оплатить".

Шги воспроизведения:

  1. Добавить товар в корзину.
  2. Быстро (двойным кликом или нажатием Enter дважды с интервалом < 300 мс) инициировать оплату.

Ожидаемый результат: Одна транзакция, один созданный заказ.

Фактический результат:

  • Со счета пользователя списывались средства дважды.
  • В системе создавался только один заказ.
  • Второе списание не было привязано ни к какому заказу, что приводило к финансовым потерям клиента.

Анализ и причина: На фронтенде не было реализовано дебаунсирование (debounce) или блокировка кнопки после первого нажатия на время обработки запроса. Бэкенд принимал два почти одновременных HTTP-запроса, оба проходили проверки и инициировали списание.

Исправление: По моему баг-репорту команда:

  1. Добавила дебаунс на кнопку оплаты на фронтенде.
  2. Реализовала на бэкенде механизм идемпотентности (проверка уникального ключа транзакции) для предотвращения повторной обработки одинаковых запросов.

Итог: Баг был исправлен до попадания в продакшен, что предотвратило потенциальные финансовые потери и потерю доверия пользователей.

Ответ 18+ 🔞

О, смотри-ка, какой интересный пиздец мы тут имеем. Прямо классика жанра, ебать мои старые костыли.

Ситуация такая: есть у нас приложение для покупок, всё вроде красиво. Человек набрал корзинку, довольный такой, тыкает кнопочку «Оплатить». А потом, от волнения что ли, или просто клава залипла, бац — и ещё разок по ней стучит. Ну, бывает, все мы люди, все мы человеки, иногда пальцы чешутся.

И вот тут начинается цирк с конями, а точнее — с деньгами. Наш фронтенд, лохматый такой, не успевает даже моргнуть. Он смотрит на первое нажатие, говорит «окей» и шлёт запрос на бэк. А тут уже второй запрос прилетает, почти одновременно. А фронтенд-то нехитрый, у него никакой защиты нет — ну и шлёт второй, чего уж там. «На, получай, обрабатывай».

А бэкенд наш — работяга простой. Получает первый запрос, проверяет всё: деньги на счету есть? Есть. Товар в наличии? Есть. Ну окей, ёпта, списываем бабки и создаём заказ. Только он это сделал, а тут уже второй, такой же самый запрос, подъезжает. Бэк смотрит на него: «А? Опять? Ну деньги-то ещё есть? Опа, есть! Товар? Ну вроде как да!». И — хрясь! — списывает ещё разок. А заказ-то уже создан, второй ему нахуй не нужен. Вот и получается, что у пользователя со счета улетели деньги дважды, а в системе висит одинокий заказик, как памятник нашей криворукости.

Ожидали: Одна транзакция, один заказ. Всё честно. Получили: Деньги списались дважды, заказ один. Вторую пачку денег просто съела чёрная дыра, и пользователь остаётся с вопросом «нахуя?» и пустым кошельком.

Короче, пиздец, а не баг. Финансовые потери, доверия ебать ноль у клиентов.

А корень зла, как всегда, в мелочах. На фронте не было дебаунса — этой простой хуйни, которая говорит: «Чувак, я уже отправил запрос, успокойся, не дёргай кнопку, пока первый не обработается». И на бэке не было идемпотентности — умной проверки, чтобы одинаковые запросы, прилетевшие подряд, не обрабатывались как два разных.

Что сделали? Ну, я, как главный по крикам «у нас пиздец!», написал баг-репорт. Команда, хоть и материлась, но сделала:

  1. На фронтенд прикрутили дебаунс на кнопку оплаты. Теперь её тыкать можно, но второй раз — только через паузу.
  2. На бэкенд добавили проверку уникального ключа транзакции. Если запрос с таким же ключом уже обрабатывался — ему вежливо говорят «иди нахуй, мы это уже видели».

Итог? Баг прихлопнули ещё до того, как он вылез в продакшен. Предотвратили кучу скандалов, возвратов денег и потерю репутации. А я ещё раз убедился, что самые дорогие ошибки — это часто самые тупые. Чих-пых тебя в сраку, невнимательность.