Моя подруга Прия отвечает за расписание в отделении на 34 койки и два года разбирала запросы на обмен сменами через групповой чат, который никто не читает по порядку. Ей хотелось приложение, которое медсёстры могли бы открыть на телефоне во время перерыва, разместить смену, которую нужно прикрыть, и чтобы кто-то забрал её раньше, чем старшей медсестре придётся вручную перекраивать график. Я собирал его три недели по вечерам. Это журнал дня, когда он реально заработал — публикация, собственный домен, реальные медсёстры, реальные смены, — потому что разрыв между «работает в тестах» и «работает в 7 утра, когда на этаже не хватает двух человек» оказался отдельным уроком.
6:58 утра — публикация
Я настроил цель развёртывания на собственный домен Прии ещё накануне вечером, так что этот момент оказался антикульминацией: нажимаю «опубликовать», смотрю, как проверочный отчёт сборки проходит проверки:
- Маршруты открываются корректно
- Эндпоинт для отклика на смену возвращает реальный ответ, а не заглушку
- Хук SMS-уведомлений реально настроен, а не работает в тестовом режиме
Всё зелёное. Я отправил Прие ссылку в 6:58 утра, потому что знал, что она как раз идёт на смену, и хотел, чтобы она увидела приложение живым до начала дня, а не после.
7:15 утра — первый реальный пользователь делает то, что я не тестировал
Прия разместила открытую смену на вечер уже через двадцать минут, что оказалось быстрее, чем я ожидал, и означало, что я не успел допить кофе, как появилась первая реальная точка данных. Затем медсестра по имени Дениз забрала смену, через четыре минуты отменила и забрала снова. Не знаю почему — может, она сверилась со своим календарём в процессе и вспомнила про приём у стоматолога. Приложение справилось нормально. Чего я не тестировал, так это трёх человек, пытающихся забрать одну и ту же смену в одном десятисекундном окне, потому что за три недели тестирования в одиночку такой сценарий мне ни разу не пришёл в голову. Сейчас он мне тоже в голову не пришёл. Он пришёл в голову реальности примерно пять часов спустя.
9:40 утра — тихо, и я нервничаю из-за этой тишины
Два с половиной часа ничего не происходило. Ни откликов, ни новых смен, ни ошибок в логах. Я всё равно проверил дашборд четыре раза — привычка, от которой мне, наверное, стоит избавиться: приложение, которым не пользуются, не сломано, оно просто пока не используется, а это разные проблемы с разными решениями. Заставил себя закрыть вкладку и заняться настоящей работой.
11:52 утра — баг
Эндпоинт принял все три запроса, потому что я написал логику «отметить как забронированное» как простую проверку «обновить, если открыто» без блокировки, а при обычном однопользовательском тестировании для такого состояния гонки просто нет места. При трёх одновременных нажатиях с трёх разных телефонов места предостаточно. Все три медсестры получили SMS-подтверждение о том, что они прикрыли смену. Дениз была одной из них — уже второй раз за день, и на этот раз она была недовольна.
Хочу быть честным насчёт того, как я это обнаружил — не через мониторинг. Прия написала мне это сообщение, с эмодзи смеха, хотя, думаю, не в буквальном смысле, потому что для её дня это была вполне реальная проблема:
приложение говорит, что смену забрали 3 человека лол
12:10 дня — в чат со сборкой
Я описал баг простыми словами: несколько человек могут забрать одну смену, если нажмут почти одновременно, а закрепиться должна только одна заявка. Сам исправлять сразу не пытался — отчасти потому что был на телефоне на парковке, отчасти потому что точно описать сбой обычно быстрее, чем точно его диагностировать. Агент отследил проблему до отсутствующей блокировки строки в таблице заявок и предложил перейти на атомарное условное обновление — заявка проходит, только если статус смены всё ещё «открыта», и решение о том, кто побеждает, принимает сама операция, а не схема «проверка-затем-запись», при которой три запроса могут одновременно увидеть «открыто». Вот и вся суть бага в одном предложении — из тех вещей, что очевидны, стоит их произнести, и невидимы, пока что-то не заставит их проявиться.
12:34 дня — исправление выходит, и я заставляю Прию подождать
Патч был небольшим. Тем не менее я не стал сразу выкладывать его на живой домен во время активной смены — сначала прогнал его на предпросмотровой версии и попросил коллегу Прии, старшую медсестру, не работавшую в этой смене, попробовать то же самое — три одновременных нажатия из трёх вкладок браузера. Всё выдержало. Одна заявка прошла, две другие получили сообщение «эту смену только что забрал кто-то другой» вместо ложного подтверждения. Я выложил исправление в 12:34, примерно через сорок две минуты после бага, что в моменте казалось медленно, а задним числом — быстро.
С 14:00 до 18:00 — скучная, хорошая часть
- ещё 11 смен размещено
- 9 забрали без проблем
- 2 истекли незабронированными и перешли в график, которым Прия по-прежнему управляет вручную — и это нормально, инструменту не нужно решать всё в первый же день, ему нужно решить именно то, что было сломано
- 0 новых двойных бронирований
Я следил за цифрами, а не воображал исходы — совсем другое и куда более спокойное занятие.
Что бы я сделал иначе
Две вещи.
- Я бы описал сценарий одновременных заявок ещё в исходном промпте сборки, а не обнаруживал его вживую — «несколько пользователей, одно и то же действие, один и тот же момент» — это одно предложение, а не сложное требование, я просто не подумал его включить, потому что моё собственное тестирование по своей природе последовательно; я всегда нажимаю по одной кнопке за раз.
- На второй неделе я слишком много вложил в формулировки SMS-уведомления — три отдельные переработки текста подтверждения, на который никто не жаловался, — и слишком мало в тот самый вид проблем с конкурентным доступом, с которым отделение, полное медсестёр на перерыве, уставившихся в телефоны в один и тот же момент, было обречено столкнуться в первый же день.
В следующий запуск я буду меньше времени тратить на полировку текста, который никто не станет критиковать, и больше — на вопрос «что будет, если пять человек сделают это одновременно», потому что для всего, у чего больше одного реального пользователя, рано или поздно кто-то так и сделает.



