Как проводить технические интервью по коду: разбор инцидента
Кандидат быстро написал рабочий код, получил высокий балл, а через месяц похожее решение стало причиной повторной обработки заказов. Разбираем, как строить интервью по коду так, чтобы проверять инженерное мышление, а не скорость печати.

Кандидат за 20 минут написал обработчик сообщений, прошёл интервью и через месяц оказался автором решения, которое при повторной доставке события дважды запускало бизнес-операцию. Ошибка была не в синтаксисе и не в знании Python: на интервью никто не спросил, что произойдёт между отправкой результата и отметкой сообщения как обработанного. Ниже — анонимизированный разбор такого кейса и схема интервью, которая проверяет поведение кода при сбоях, а не только его happy path.
Инцидент начался с правильного на вид кода
Задание выглядело привычно: обработать пачку сообщений, сохранить результат и отметить каждое сообщение завершённым. Кандидат быстро предложил последовательный цикл. Схематичный фрагмент на Python 3.12:
def process_batch(messages, save_result, mark_processed):
for message in messages:
save_result(message)
mark_processed(message["id"])
На обычном прогоне решение действительно работает. Сообщение сохраняется, затем получает статус processed. Интервьюер видит понятный порядок действий, короткую функцию и отсутствие лишних абстракций.
Проблема появляется в промежутке между двумя вызовами. Если save_result успешно завершился, а процесс остановился до mark_processed, брокер или очередь доставит сообщение повторно. Второй запуск снова вызовет операцию сохранения. Если она не идемпотентна1, пользователь получит дубль, двойное списание или повторную отправку уведомления.
Хорошее интервью по коду проверяет не только «работает ли функция», но и «что произойдёт, если она остановится на каждой строке».
Что именно сломалось в процессе интервью
Скорость подменила анализ границ
Интервьюер оценивал результат по трём наблюдаемым признакам: кандидат быстро начал писать, не делал синтаксических ошибок и прошёл заранее подготовленные примеры. Эти признаки удобны для быстрой оценки, но они не отвечают на вопросы о доставке сообщений, повторном запуске и частичных сбоях.
В анонимизированном кейсе не было отдельного этапа, где кандидат должен был:
- назвать внешние операции и их побочные эффекты;
- показать точку отказа между двумя действиями;
- объяснить, можно ли безопасно повторить каждый вызов;
- предложить наблюдаемость: логи, метрику повторов и идентификатор сообщения;
- описать, как проверить решение тестом на падение процесса.
В результате интервью проверило выполнение сценария, но не гарантию при сбое. Это разные свойства. Первое видно за несколько минут. Второе требует вопросов о состоянии системы и явной проверки граничных случаев.
Почему ревью после выхода не спасло ситуацию
На ревью внимание ушло на именование, размер функции и обработку исключений. Самый опасный вопрос звучит иначе: «Что произойдёт, если запись уже сохранена, но подтверждение обработки не записалось?» Если на него нет ответа в коде или архитектуре, обычный try/except проблему не решает.
Исправление может выглядеть по-разному: сделать операцию сохранения идемпотентной, использовать уникальный ключ события, перенести изменение состояния в одну транзакцию либо применить паттерн outbox. Выбор зависит от базы данных, брокера и цены повторной обработки. На интервью не нужно требовать конкретный паттерн, если он не был частью задания. Нужно проверить, заметил ли кандидат сам разрыв между действиями.
Как построить интервью вокруг реального риска
1. Сначала зафиксируйте контракт задачи
До начала интервью сообщите кандидату не только входной формат, но и ограничения. Например: сообщение может быть доставлено повторно, save_result меняет внешнее состояние, порядок сообщений не гарантируется, а процесс может завершиться в любой момент.
Так вы не проверяете способность угадать скрытые требования. Вы проверяете, как человек работает с явно заданным контрактом. Уточните также, что считается успехом: одна обработка события, отсутствие потери данных или возможность безопасного повтора.
2. Дайте рабочий happy path, но не останавливайтесь на нём
Попросите кандидата написать минимальное решение, а затем добавьте четыре сценария. Каждый вопрос должен привязываться к конкретной строке, а не к абстрактному «что будет при ошибке».
- Ошибка до сохранения. Что увидит вызывающий код и можно ли повторить сообщение. Проверка: кандидат явно называет состояние записи после сбоя.
- Ошибка после сохранения. Что произойдёт при повторной доставке. Проверка: появляется разговор об идемпотентности или уникальном ключе.
- Два одинаковых сообщения одновременно. Какая операция защищает от гонки. Проверка: кандидат различает последовательный повтор и конкурентную обработку.
- Перезапуск после частичного выполнения. Как оператор поймёт, что произошло. Проверка: названы корреляционный идентификатор, журнал и метрика повторов.
Не подсказывайте термин «идемпотентность» сразу. Сначала оцените рассуждение своими словами, затем спросите, знает ли кандидат общепринятое название свойства.
3. Попросите изменить решение, а не пересказать теорию
После обнаружения риска предложите кандидату выбрать один из вариантов: добавить защиту от повторной операции, изменить порядок действий или описать гарантию на уровне хранилища. Важна не длина патча, а связь между исправлением и моделью отказа.
Например, хороший ответ должен отделять два утверждения: «сообщение не будет обработано дважды» и «повторная обработка безопасна». Первое требует строгой координации и часто дорого. Второе достигается идемпотентной операцией, но не отменяет необходимость наблюдаемости и очистки зависших состояний.
Как оценивать ответы без субъективного «понравился кандидат»
| Что проверяем | Сильный сигнал | Слабый сигнал |
|---|---|---|
| Понимание отказов | Кандидат проходит по точкам между внешними вызовами | Говорит только о перехвате исключений |
| Данные и повторы | Различает потерю, дубль и конкурентную обработку | Предлагает просто повторить весь цикл |
| Изменение решения | Связывает патч с конкретной гарантией | Добавляет блокировку без объяснения цены |
| Наблюдаемость | Называет метрики, логи и идентификаторы | Ограничивается сообщением об ошибке |
| Коммуникация | Фиксирует неизвестные требования и задаёт уточняющие вопросы | Молча выбирает допущения и защищает их как факт |
Оценивать лучше не одной итоговой цифрой, а по нескольким независимым критериям. Если команда использует баллы, заранее опишите, сколько требуется для прохождения и какие ошибки критичны. Критичной может быть не незнакомая библиотека, а неспособность заметить повторную побочную операцию после подсказанного сценария сбоя.
Какие форматы интервью подходят для этой задачи
Формат влияет на то, что именно вы увидите. Live coding показывает рассуждение в моменте, но ограничивает объём контекста. Домашнее задание даёт больше времени, зато сложнее понять, кто принимал решения и как кандидат реагировал на уточнения.
| Формат | Что хорошо проверяет | Главная цена |
|---|---|---|
| Парное решение с интервьюером | Вопросы, ход рассуждений, реакцию на сбой | Сильно зависит от качества интервьюера |
| Отладка готового фрагмента | Поиск конкретной причины и оценку риска | Можно проверить только заранее выбранные классы ошибок |
| Небольшое домашнее задание | Тесты, документацию, структуру изменений | Не всегда видно авторство и затраты времени |
| Архитектурный разбор после кода | Последствия решения при росте нагрузки и сбоях | Требует больше времени и не заменяет практическую задачу |
Для кейса с повторной доставкой лучше всего работает связка «короткий кодовый фрагмент плюс отладочный сценарий». Кандидат сначала пишет минимальное решение, затем получает условие о сбое и должен изменить код или явно доказать, почему изменение нужно не в нём, а в хранилище.
Что измерять после похожего инцидента
Если ошибка уже попала в продакшен, не начинайте с подсчёта «плохих интервью». Сначала восстановите цепочку событий: идентификатор сообщения, время первой обработки, момент повторной доставки, результат каждой попытки и состояние записи в базе. Без этих данных команда может спорить о причине, опираясь на неполные логи.
Для проверки исправления полезно измерять:
- долю повторно доставленных сообщений;
- число повторных бизнес-операций по одному идентификатору события;
- время между успешным побочным действием и подтверждением обработки;
- количество сообщений, застрявших в промежуточном состоянии;
- долю ошибок, по которым можно восстановить полный путь запроса.
Не подставляйте универсальные пороги: допустимое число повторов зависит от цены операции. Для отправки письма и списания денег одинаковая метрика может иметь совершенно разный смысл.
Где такой подход ломается
Сценарий с повторной доставкой не проверяет все инженерные навыки. Кандидат может хорошо понимать отказы, но не знать конкретный фреймворк. И наоборот: знание API очереди не доказывает, что человек умеет формулировать гарантии обработки.
Не превращайте интервью в экзамен на угадывание инфраструктуры. Если используете RabbitMQ, Kafka или конкретную СУБД, сообщите версию и важные гарантии доставки заранее. Если версия Python отличается от рабочей, разрешите свериться с документацией: в проде инженер тоже не обязан помнить весь API наизусть.
Отдельно проверяйте стоимость исправления. Уникальный индекс может защищать от дублей, но создать конфликт для легитимного повторного события. Долгая транзакция может уменьшить окно сбоя, но увеличить блокировки. Блокировка в приложении не заменяет ограничение в базе, если обработчиков несколько. Эти компромиссы важнее красивого названия паттерна.
Что сделать дальше
Возьмите одну реальную операцию вашей системы с побочным эффектом и составьте для неё карту отказов: что происходит до вызова, во время него и сразу после. Затем превратите две наиболее дорогие точки сбоя в вопросы интервью и добавьте к заданию тестовый сценарий с повторным запуском.
После следующего интервью сохраните не только итоговый балл, но и наблюдения по критериям: какие допущения сделал кандидат, какие сбои заметил, как изменил решение и что предложил измерять. Через несколько собеседований сравните эту форму с результатами испытательного срока. Так вы проверите не впечатление от разговора, а прогностичность самого интервью.
1 Идемпотентность — свойство операции, при котором повторное выполнение с теми же данными не создаёт новый нежелательный побочный эффект.
Инженер-технолог: Перевод технических мануалов с CN/EN на русский ГОСТовский язык.
Спросить за 20 ₽Источники: Google re:Work: Structured interviewing, Python 3.12 documentation
Частые вопросы
Нужно ли требовать от кандидата идеальное решение сразу?
Что делать, если кандидат не знает термина «идемпотентность»?
Можно ли использовать другой язык или другую версию Python?
Что делать, если после интервью код выглядит правильно, но в проде снова появляются дубли?
Нужно ли давать кандидату готовый код с ошибкой вместо задачи с нуля?
Какие подводные камни возникают после найма?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.