2.3Неудобные вопросы
Потренируешь ответы на провал, конфликт и сорванный срок через признание собственной роли, принятые меры и изменение процесса. Научишься говорить о неприятном спокойно, не перекладывая ответственность и не раскрывая лишние детали.
Зачем вообще спрашивают про плохое
У интервьюера гипотеза простая: то, как человек рассказывает о своих ошибках сейчас, показывает, как он будет вести себя во время инцидента через полгода. Если в рассказе виноваты аналитик, тестировщик и менеджер, то в его команде виноватыми будут те же люди. Если ошибка признана, но выводов нет, она повторится. Если ошибки «не было», то либо не было ответственности, либо нет рефлексии, и оба варианта плохи.
Отсюда рабочая формула честного ответа: признал → что сделал → что изменил в процессе. Третий пункт важнее всех, и его почти всегда пропускают. Он и превращает «я накосячил» в «я закрыл целый класс ошибок».
- «У меня не было провалов». Худший вариант из возможных. Значит одно из двух: либо ты не работал с продом, либо не считаешь свои ошибки ошибками.
- Виноватые с именами и должностями. Даже если правда на твоей стороне, интервьюер примеряет: так же он будет рассказывать про нас.
- Фальшивый провал. «Мой недостаток - я слишком въедливый, из-за этого один раз задержал релиз на день». Это самопохвала в маскировке, а не провал, и её слышно сразу.
- Провал космического масштаба. «Из-за меня компания потеряла клиента на десять миллионов»: если это правда, придётся объяснять, почему тебя допустили до такого в одиночку. Масштаб у хорошего провала заметный, но переживаемый: минуты-часы деградации, а не крах бизнеса.
- «Больше не повторится, буду внимательнее». Внимательность не масштабируется. Пока не изменился инструмент, повторится.
Конфликт и техническое несогласие
Слово «конфликт» в вопросе пугает, но спрашивают на самом деле про другое: умеешь ли ты довести несогласие до решения, не превратив его в личное. В хорошем ответе спор почти всегда переводят из плоскости мнений в плоскость данных и trade-offs. Кэш даёт скорость, платим за неё устареванием данных. Индекс ускоряет чтение, платим скоростью записи и местом на диске. Спор про trade-off всегда решаем, потому что цены можно сравнить; спор про «мне так больше нравится» не решить.
- «Я так думаю» / «мне кажется, так лучше»
- «Это же очевидно»
- «Так делают все нормальные команды»
- «У меня больше опыта»
- «Мы всегда так делали»
- Спор в чате на сорок сообщений вместо пятнадцатиминутного созвона
- «Давай сначала договоримся о критерии выбора»
- «Вот замер: с индексом 210 мс, с кэшем 40 мс, но плюс инвалидация»
- «У варианта А цена вот такая, у Б - вот такая. Что для нас дороже?»
- «Что должно случиться, чтобы ты изменил мнение?»
- «Давай зафиксируем решение и условие, при котором вернёмся к нему»
- «Не согласен, но принимаю - делаю как решили, в полную силу»
Формулировка американская и переводится примерно так: не согласен, но принимаю решение и делаю в полную силу. Принцип простой: до решения спорь сколько угодно, после решения работай на него как на своё. На собесе это звучит так: «я остался при своём мнении, но решение приняли другое, и я сделал его качественно - саботировать решение команды и потом говорить "я же предупреждал" мне кажется худшим, что можно сделать». Обязательное дополнение, по которому узнают зрелого инженера: зафиксировать условие пересмотра, скажем «договорились вернуться к этому, если p99 вырастет выше 500 мс». Тогда спор не тлеет: у него есть точка выхода.
Срок горит: механика правильного поведения
Вопрос здесь не «что делать», а когда сказать. Плохая новость за неделю до срока остаётся рабочей ситуацией с вариантами. Та же новость в день дедлайна превращается в сорванный дедлайн, и вариантов нет уже ни у кого.
- Пересчитать честно. Не «наверное, успею», а сколько реально осталось работы и какая новая дата, если ничего не менять. Число, а не ощущение.
- Сказать сразу, письменно и адресно. Тому, кто отвечает за срок, а не в общий чат. Формат: «риск такой-то, причина такая-то, новая оценка такая-то».
- Принести варианты, а не проблему. Минимум три: урезать скоуп (что именно можно выкинуть или отложить и что от этого потеряется), сдвинуть дату, подключить второго человека (с оговоркой, что это ускоряет не всегда). Свою рекомендацию назвать явно.
- Договориться о точке контроля. «Проверим в четверг: если к этому моменту миграция не поедет, идём по варианту с урезанным скоупом». Это снимает тревогу у всех.
Красные флаги: что интервьюер слышит на самом деле
| Фраза в ответе | Что слышит интервьюер | Как надо |
|---|---|---|
| «У меня не было провалов / конфликтов» | Нет ответственности или нет рефлексии | Взять реальный случай среднего масштаба и рассказать по формуле |
| «Виноват был аналитик / тестировщик / менеджер» | Так он будет говорить и про нашу команду | «Постановка была размытая - и это была моя работа её уточнить, я этого не сделал» |
| «Мы всё исправили» (в истории про свою ошибку) | Прячется за командой, когда неприятно | «Ошибку допустил я, чинили вместе, отдельно расскажу, кто что делал» |
| «Больше не повторится, буду внимательнее» | Вывода нет, повторится | Назвать инструмент: линтер, тест, алерт, правило ревью, изменённый пайплайн |
| «В итоге я оказался прав» | Спорит, чтобы победить, а не чтобы решить | Назвать, в чём был прав оппонент и что ты у него взял |
| «Я просто сделал как сказали, хотя был против» | Пассивная агрессия, потом «я же предупреждал» | Disagree and commit плюс зафиксированное условие пересмотра |
| «Пришлось выйти в выходные, но мы успели» | Героизм вместо процессов; выгорит и уйдёт | «Я поднял риск за неделю, вместе урезали скоуп и выкатили в срок» |
| «Там всё было очень плохо, легаси, никто ничего не документировал» | Жалуется, а не меняет | «Было мало документации - я завёл описание домена, к которому теперь ходят новички» |
| Долгая пауза и «дайте подумать» на каждом таком вопросе | Не готовился, историй нет | Заготовленные четыре истории - пауза в пять секунд нормальна, в тридцать нет |
Вопросы
4Каркас ответа
- Назвать ошибку прямо, в первой фразе. Без разгона и без смягчений: «я выкатил миграцию, которая сломала работу списка сделок на несколько минут».
- Признать свой вклад точно. Что именно сделал не так и почему тогда это казалось нормальным.
- Как чинил. Коротко: что выбрал, откат или движение вперёд, и почему.
- Что изменилось после. Это ядро: правило, автоматическая проверка, изменённый порядок работы. Желательно два-три конкретных пункта.
- Вывод одной фразой: обобщение уровня «класс ошибок», а не «этот случай».
«Самая дорогая моя ошибка - миграция, несовместимая с выкаткой. Я переименовывал
колонку в таблице сделок: owner_id стал assignee_id, потому что
поле уже давно значило не то, что называлось. Сделал одной миграцией - ALTER TABLE ... RENAME COLUMN, -
поправил код и выкатил всё одним релизом.
Проблема в том, что раскатка в Kubernetes идёт постепенно: несколько минут в проде
живут одновременно старые и новые поды. Миграция применилась мгновенно, а старые поды
продолжали спрашивать owner_id - колонки уже не было. Примерно шесть минут
часть запросов к сделкам падала пятисотками. И вторая, более неприятная часть: откатить
релиз было нельзя - откат приложения вернул бы код, который тоже не работает с новой схемой.
То есть я сам себя лишил кнопки отката.
Чинил движением вперёд: добил раскатку новой версии до всех подов, чтобы старых не осталось. Это заняло минуты три, ошибки прекратились. Правильнее было бы иметь возможность откатиться, но её у меня в тот момент не было - и это была ровно моя ошибка, а не стечение обстоятельств.
После этого я поменял три вещи, и они живут в команде до сих пор. Первое - правило
расширяй-и-сжимай: любое изменение схемы растягивается минимум на три релиза. Сначала добавляем новую колонку и пишем в обе, потом переводим чтение на новую, и только потом, когда старого кода в проде уже нет, отдельным релизом удаляем старую. То есть каждая отдельная миграция совместима и со старым, и с новым кодом.
Второе - миграции стали отдельным шагом пайплайна до раскатки приложения, и в ревью
миграций появился явный чек-лист: работает ли старый код с этой схемой, есть ли откат,
берёт ли операция тяжёлые блокировки. Третье - на опасные конструкции повесили проверку
в CI: DROP COLUMN, RENAME, CREATE INDEX
без CONCURRENTLY, ALTER без lock_timeout
требуют явного подтверждения в описании PR.
Вывод для себя я сформулировал так: раскатка - это не мгновенное событие, а промежуток, в течение которого в проде живут две версии кода одновременно. Пока я этого не прочувствовал, я думал про миграцию как про «поменять состояние базы», а надо думать как про «сохранить совместимость на время перехода». Это касается не только схемы БД - то же самое с форматами событий в Kafka и с контрактами API между сервисами.»
Чего говорить нельзя
- «Провалов не было». Мгновенный минус: либо не было прода, либо нет рефлексии.
- «Ревью пропустило». Правда, но не твоя часть правды. Ревью годится как системная причина («диф был большой, миграцию не разглядели, поэтому мы завели отдельный чек-лист»), но не как виноватый.
- Псевдопровал. «Я слишком перфекционист», «задержал релиз ради качества».
- Провал, который никак не закончился. Если после истории ничего не изменилось, лучше взять другую историю.
- Эмоции вместо фактов. «Было очень стыдно, я неделю переживал»: одной фразы хватит, дальше нужны действия.
Чем добить
Обобщи ошибку до класса. Не «я больше не переименовываю колонки», а «я перестал считать деплой атомарным событием - и это касается схемы БД, схем событий и контрактов API». По такому обобщению видно, что выводы человек делает по причине, а не по частному случаю. Второй сильный ход: сказать, что ты сам написал постмортем и сам вынес это на общий разбор, а не ждал, пока разберут за тебя.
Каркас ответа
- Предмет несогласия одной фразой: техническое, не личное.
- Позиции сторон и их резоны. Обязательно назови сильную сторону чужого варианта: это доказывает, что ты его понял.
- Как перевёл в измеримое: критерий, замер, эксперимент. Ядро ответа.
- Чем кончилось и что взял из чужой позиции.
- Отдельно про случай, когда решение приняли не твоё, и как ты себя повёл.
«Живой пример: у нас тормозил список сделок - p99 около двух секунд, менеджеры жаловались. Коллега предложил закэшировать выдачу в Redis: быстро, эффект сразу. Я был против и предлагал сначала разобраться в самом запросе.
Первое, что я сделал, - проговорил, в чём он прав. Кэш действительно даёт эффект за полдня, а разбор запроса может занять неделю и ничего не дать. Это честный аргумент, и я не стал делать вид, что его нет.
Дальше предложил не спорить, а посчитать, и сформулировал критерии: какая будет
латентность, во сколько нам обойдётся инвалидация и насколько мы рискуем показать
менеджеру устаревшие данные. Последнее в CRM важно: сделка меняется постоянно, и увидеть
старый статус - это реальная бизнес-проблема, а не косметика. Взял час, снял
EXPLAIN ANALYZE: там был seq scan по таблице сделок с фильтром по владельцу
и статусу плюс классический N+1 при подтягивании последнего контакта. Собрал составной
индекс, убрал N+1 одним запросом - получилось 210 миллисекунд без всякого кэша.
С этим числом спор закончился за пять минут: кэш дал бы 40 миллисекунд, но принёс бы инвалидацию по десятку событий и риск устаревших данных - а разница между 210 и 40 для пользователя, который открывает список, неощутима. Мы зафиксировали и обратное условие: если после роста нагрузки p99 снова уйдёт за 500 миллисекунд, возвращаемся к кэшу, и тогда уже осознанно, с продуманной инвалидацией.
Что я взял из его позиции: он был прав в том, что чинить надо быстро. Поэтому я не ушёл в разбор на неделю, а жёстко ограничил себе время: ровно один день. Не нашёл бы за день причину - сделали бы кэш, как он и предлагал.
Бывало и наоборот. Я предлагал вынести отчёты в отдельный сервис, тимлид решил оставить в монолите и читать с реплики. Я остался при своём мнении, но сделал вариант с репликой качественно и не возвращался к этому спору каждую неделю. Мы договорились о точке пересмотра - если отчёты начнут влиять на основную нагрузку. Через полгода это случилось, мы вернулись к разговору уже с графиками, и сервис выделили. Мне кажется, это правильный способ: спорить до решения, работать после него, и заранее договориться, что заставит нас пересмотреть выбор.»
Как выглядит хороший исход спора
- Есть решение, а не перемирие. Исход «каждый остался при своём» плохой: вопрос всплывёт снова.
- Есть критерий, по которому выбрали, и он записан: в комментарии к PR, в задаче или в ADR. Через полгода такая запись - единственное, что отвечает на вопрос «а почему у нас так сделано».
- Есть условие пересмотра. Фраза «вернёмся, если p99 выйдет за 500 мс» превращает решение из вечного в обратимое.
- Отношения не пострадали. Признак: с этим человеком ты дальше нормально работаешь и рассказываешь про него спокойно.
Чего говорить нельзя
- Личный конфликт. «Не сошлись характерами», «он токсичный». Даже если так, на собесе это читается как «он приносит конфликты с собой».
- «Я оказался прав». Как единственный итог не годится. Если ты правда был прав, скажи это через данные: «замер показал, что вариант с индексом дешевле».
- «Позвал тимлида, он решил». Как первый шаг это сигнал, что договариваться не умеешь.
- «Я просто уступил, чтобы не спорить». Это не гибкость, а отсутствие позиции.
- Спор длиной в месяц. Затянутый спор тоже плохой исход, даже если ты победил.
Чем добить
Назови вопрос, которым ты пользуешься в тупике: «что должно произойти, чтобы ты изменил мнение?». Он делает две вещи сразу: вытаскивает настоящий критерий собеседника и нередко показывает, что критерия нет вообще. И добавь про формат: длинные споры ты выносишь из чата в пятнадцатиминутный созвон, а решение возвращаешь в письменном виде, чтобы через месяц никто не спорил заново.
Каркас ответа
- Пересчитываю честно и получаю новую дату: число, а не ощущение.
- Сообщаю в тот же день, письменно, адресно: риск, причина, новая оценка.
- Приношу три варианта с ценой каждого и говорю, какой рекомендую.
- Договариваюсь о точке контроля, чтобы решение можно было принять не в последний день.
- Дальше работаю по выбранному варианту и держу статус видимым.
«Первое - я стараюсь понять это как можно раньше, потому что вся разница между рабочей ситуацией и сорванным сроком в том, за сколько дней ты об этом сказал. Практически это значит, что я держу задачу нарезанной на куски по полдня-день и смотрю, попадаю ли я в темп. Как только два-три куска подряд заняли вдвое больше, чем я думал, - это сигнал, дальше само не выправится.
Второе - пересчитываю и называю новое число. Не "кажется, задерживаюсь", а "осталось примерно четыре дня работы вместо запланированных двух, потому что вот здесь вылезло вот это".
Третье - в тот же день пишу продакту и тимлиду, и не с проблемой, а с вариантами. Обычно их три. Урезать скоуп: вот эту часть можно не делать в первой версии, тогда укладываемся в срок, потеряем вот такой сценарий. Сдвинуть дату: нужно ещё столько-то дней, объём такой-то. Добавить человека: помогает, только если есть кусок, который правда отделяется, - если нет, второй человек скорее замедлит. Я всегда говорю, какой вариант рекомендую сам и почему.
Живой пример: делал интеграцию с новым провайдером телефонии, а он выдал доступ к тестовому контуру на неделю позже обещанного. Стало понятно сразу, что в срок не влезаем. Я написал в тот же день и предложил выкатить в первой версии только входящие звонки, а исходящие и запись разговоров отложить на следующий спринт - потому что бизнесу были нужны в первую очередь входящие. Продакт согласился, дату по основной части не двигали.
И последнее - договариваюсь о точке контроля. Например: "проверим в четверг; если к четвергу тестовый контур не появится, идём по урезанному варианту". Тогда решение принимается спокойно и заранее, а не в вечер дедлайна. Чего я стараюсь не делать - это молча догонять по вечерам. Даже если получится, команда узнает о риске последней, и в следующий раз мне просто не поверят на слово.»
Чего говорить нельзя
- «Останусь подольше и всё успею». Разово бывает у всех, но как ответ на вопрос это сигнал: человек прячет риски и выгорит.
- «Скажу в день дедлайна». Даже в мягкой формулировке «предупрежу ближе к сроку».
- «Это не моя вина, аналитик поздно принёс требования». Причина бывает и внешней, но сообщить о риске в любом случае твоя работа.
- «Срежу тесты, потом допишу». Резать надо скоуп, а не качество: тесты и обработку ошибок «потом» не дописывают никогда, и опытный интервьюер это знает.
- Снизить качество, никому не сказав. Хуже всех вариантов: срок формально соблюдён, а расплата приходит через месяц и уже дороже.
Чем добить
Скажи, что предупреждение о риске не признание поражения, а инструмент: чем раньше ты его подаёшь, тем дешевле оно обходится компании. И добавь профилактику: на этапе оценки ты явно называешь рисковые пункты («вот здесь могу ошибиться в полтора раза - это работа с объёмом данных, которого я ещё не видел»). Тогда сработавший риск не сюрприз, а заранее обозначенная развилка, и разговор получается совсем другой.
Шесть флагов, которые закрывают вакансию
- Виноватые. В истории появляются должности: аналитик, тестировщик, менеджер. Интервьюер мгновенно достраивает, как ты будешь рассказывать про его команду.
- «Мы» в неприятных местах и «я» в приятных. Достижения «я сделал», ошибки «мы не учли». Заметно уже на второй истории.
- Нет системного вывода. «Буду внимательнее», «стал аккуратнее» значат то же, что «ничего не изменилось».
- Героизм. Ночи, выходные, «спас релиз». Читается так: процессов нет, а человек вот-вот выгорит.
- Жалобы без действий. «Легаси, документации нет, процессы кривые»: если за описанием проблемы не следует ни одной твоей попытки что-то изменить, это позиция пассажира.
- Спор ради победы. «В итоге я оказался прав» без единого пункта, где прав был оппонент. Такой человек дорого обходится команде, даже когда технически силён.
Два флага помельче, но заметных
- Идеальные истории. Всё прошло по плану, конфликтов не было, ошибок не было. Читается это не как «сильный кандидат», а как «не рассказывает правду» или «не было ответственности».
- Долгие паузы на каждом вопросе. Пять секунд подумать нормально и даже хорошо. Тридцать секунд на каждый вопрос подряд выдают, что историй нет и человек сочиняет на ходу.
«Если смотреть со стороны интервьюера, все плохие ответы на такие вопросы сводятся к четырём вещам. Первое - перекладывание: в истории появляются виноватые, и понятно, что в новой команде виноватые тоже найдутся. Второе - асимметрия местоимений: достижения "я", ошибки "мы". Третье - отсутствие вывода: человек честно рассказал про провал, но всё, что он из него вынес, - это "буду внимательнее"; значит, повторится. Четвёртое - героизм: если история заканчивается тем, что человек сидел ночь и всех спас, то на самом деле она про то, что в команде не было ни отката, ни алертов, ни разговора о риске.
Я поэтому свои истории специально проверяю на два вопроса: "есть ли тут кто-то виноватый, кроме меня" и "что изменилось в системе после этого". Если на первый ответ "да", а на второй "ничего" - историю надо переписывать или брать другую.»
Чем добить
Скажи, что ты отличаешь причину от виноватого. Причину назвать обязательно: «диф был на четыреста строк, поэтому миграцию не разглядели на ревью» звучит как системная причина, из неё следует изменение процесса. А «Петя не разглядел» указывает на виноватого, из него не следует ничего. Про культуру постмортема без обвинений короче не скажешь, и вслух эта пара слов звучит хорошо.
Что стоит запомнить
- Сильная история об ошибке содержит конкретную свою часть и причинную цепочку.
- Результат включает немедленное исправление и профилактику повторения.
- Разногласие полезно описывать через критерии решения и проверяемые данные.
Частые ошибки
- Обвинение коллег не объясняет собственные действия и ухудшает доверие.
- «Я стал внимательнее» не является изменением процесса, которое снижает риск повторения.
Самопроверка
Сначала реши задачу самостоятельно, затем открой ответ и сравни ход рассуждений.
Применение
1. Ответь о своём production-инциденте
Сценарий для ответа: ты добавил индекс без проверки на staging с production-подобным объёмом. Миграция заняла дольше окна, deploy задержался на 18 минут. Данные не потерялись; ты остановил rollout, дождался завершения миграции, затем выкатил версию. После этого добавил проверку длительности migration на копии данных и отдельный deploy budget. Сформулируй ответ на «расскажите об ошибке».
Ответ и разбор
«Я выпустил индекс без проверки времени построения на объёме, близком к production. Миграция вышла за плановое окно и задержала deploy на 18 минут. Я остановил rollout и продолжил после завершения миграции; данные не пострадали. После инцидента добавил прогон миграций на копии данных и отдельный временной бюджет для deploy. Теперь длительность проверяется до релиза». Ответ признаёт решение, сообщает проверенный ущерб и показывает изменение процесса.
Применение
2. Сними обвинение из ответа о конфликте
Черновик: «Релиз задержался, потому что тестировщик опять не проверил крайние случаи. Я настоял на своём, и в итоге всё сделали правильно». Перепиши ответ так, чтобы было видно несогласие по делу и способ разрешения. Факты: спор был о пустом customer_id; ты предложил проверить запросом к API, команда согласовала обязательную валидацию перед merge.
Ответ и разбор
«Мы разошлись во мнении, должен ли API принимать пустой customer_id. Я привёл запрос, который воспроизводил проблему, и предложил добавить валидацию до merge. Команда согласовала обязательную валидацию перед merge». Это описывает разногласие и проверяемый критерий, не приписывая одному участнику всю правоту.
Применение
3. Назови конкретный урок
После ручного deploy выкатили неверный тег образа. Твой ответ: «Теперь я буду внимательнее». Какой один процессный барьер предложить вместо обещания быть внимательнее? Условие: pipeline уже получает digest собранного образа.
Ответ и разбор
Передавать в deploy job digest, который вернул build job, вместо ручного ввода тега; проверить, что deployment использует именно этот digest. Так убирается расхождение между тегом и уже собранным образом. Подпись артефакта стоит добавлять только если она предусмотрена процессом.
Применение
4. Ответь о сорванном сроке без оправданий
Задача заняла пять дней вместо двух: ты не учёл лимит внешнего API и обнаружил его после начала реализации. Сервис не был выпущен, клиентскую дату перенесли на три дня. Ты добавил контрактный тест с лимитом и теперь сообщаешь о рисках при оценке. Составь краткий ответ, не обвиняя постановщика задачи.
Ответ и разбор
«Я оценил интеграцию в два дня и поздно проверил лимит внешнего API. Из-за этого релиз перенесли на три дня; до выпуска пользователи не затронуты. Я добавил контрактный тест с ограничением провайдера и теперь проверяю такие лимиты до оценки. Моя ошибка была в порядке исследования, а не в том, что требование было неясным». Последняя фраза нужна лишь если это действительно соответствует ситуации.