26. Поведенческие и архитектурные вопросы
«Любой дурак может написать код, понятный компьютеру. Хорошие программисты пишут код, понятный людям».
— Мартин Фаулер
- Расскажи о самом сложном проекте
- Как ты решал сложную техническую проблему
- Как принимал решения
- Как работал с командой
- Как разрешал конфликты в команде
- Был ли опыт наставничества
- Как оцениваешь задачи
- Что делаешь, если не согласен с решением архитектора
- Как убедить команду использовать новую технологию
- Приведи пример неудачного проекта и чему он научил
- Какой твой вклад в open-source
- Как ты учишься новому
- Как относишься к code review
- Как ты тестируешь свой код
- Что для тебя значит "хороший код"
- Как ты работаешь с требованиями от заказчика
- Как ты обеспечиваешь наблюдаемость observability сервиса
- Как ты выбираешь между созданием собственного решения и использованием стороннего
- Расскажи о случае, когда тебе пришлось пойти на компромисс в архитектуре
- Как ты определяешь и предотвращаешь технический долг
- Опиши свой подход к проектированию нового сервиса
- Как ты пишешь документацию для своего кода и API
- Как ты подходишь к планированию и декомпозиции больших задач
- Расскажи о ситуации, когда тебе пришлось быстро развернуть исправление в продакшене
- Как ты оцениваешь риск при внедрении новой технологии или архитектурного решения
- Как ты управляешь своим временем и приоритетами в условиях высокой неопределенности
- Расскажи о самом интересном баге, который ты нашел
- Как ты выстраиваешь отношения с продакт-менеджерами
- Как ты проводишь post-mortem после инцидента
- Какой твой подход к безопасности при разработке
- Был ли опыт работы с высоконагруженными системами > 10k rps
- Как ты обеспечиваешь, что твой код легко поддерживать
- Как ты подходишь к работе в распределенной команде
- Что для тебя важнее скорость разработки или качество
- Как бы ты спроектировал систему, если бы мог сделать это с нуля без ограничений
- Как ты выбираешь стек технологий для нового проекта
- Расскажи о случае, когда тебе пришлось отказаться от любимого инструмента в пользу командного стандарта
- Как ты оцениваешь производительность своего кода до того, как он попадет в продакшен
- Как ты работаешь с обратной связью, особенно критической
- Опиши идеальный для тебя процесс CI/CD
- Как ты работаешь с "легаси" кодом
- Что такое "архитектурное решение" ADR и зачем оно нужно
- Как ты обеспечиваешь консистентность кодовой базы в большой команде
- Как ты объясняешь сложные технические концепции нетехническим стейкхолдерам
- Расскажи о твоем опыте проектирования API и взаимодействия с другими командами
- Как ты подходишь к выбору между микросервисами и монолитом
- Какова твоя роль в инцидент-менеджменте
- Как ты справляешься с "выгоранием" burnout и помогаешь справляться другим
- Как ты организуешь процесс "knowledge sharing" в команде
flowchart TD
classDef entry fill:#1e3a5f,stroke:#38bdf8,stroke-width:2px,color:#f8fafc
classDef process fill:#1e293b,stroke:#38bdf8,stroke-width:1px,color:#f8fafc
classDef accent fill:#1e1b4b,stroke:#818cf8,stroke-width:1px,color:#f8fafc
classDef warning fill:#78350f,stroke:#fbbf24,stroke-width:1px,color:#f8fafc
classDef success fill:#064e3b,stroke:#34d399,stroke-width:1px,color:#f8fafc
STAR["STAR-метод структуры поведенческого ответа"]:::entry
STAR --> S["S — Situation (Ситуация, 15% времени)"]:::accent
S --> SD["Контекст: масштаб проекта, цели бизнеса, команда, стек технологий"]:::process
STAR --> T["T — Task (Задача / Вызов, 15% времени)"]:::warning
T --> TD["Какая именно проблема возникла и какова была ваша персональная зона ответственности?"]:::process
STAR --> A["A — Action (Действие, 50% времени)"]:::accent
A --> AD["Что конкретно предприняли ВЫ: архитектурные решения, дебаг, фасилитация, код"]:::process
STAR --> R["R — Result (Результат / Выводы, 20% времени)"]:::success
R --> RD["Измеримый бизнес-эффект в цифрах (-40% latency, 99.99% SLA) и системные уроки"]:::process
Расскажи о самом сложном проекте
Краткий ответ (30–60 секунд)
Самым сложным был проект миграции монолита интернет-банкинга на событийно-ориентированную микросервисную архитектуру с 99,99% доступности. Сложность заключалась в совмещении императива zero-downtime с полным пересмотром модели данных и в необходимости переобучить команду из 40 человек. Ключом успеха стали параллельная работа через Strangler Fig, двойное подписывание событий и поэтапное переключение трафика с автоматическим разбором инцидентов.
Развёрнутый ответ
Проект длился 18 месяцев. Монолит на Java обрабатывал ~3k tps, база — одна Oracle RAC. Бизнес требовал масштабироваться до 20k tps и ускорить вывод фич. Я предложил перейти на Go-микросервисы с Kafka и Event Sourcing, постепенно выпиливая куски монолита. Основные вызовы:
- Консистентность данных: вводил Saga-паттерн и идемпотентные обработчики, каждая операция получала
idempotency-key. - Наблюдаемость: внедрял OpenTelemetry с кастомными спанами, обязательные трейсы всех запросов.
- Люди: проводил внутренние Go-митапы, парные программирования, code review с обязательным approval от двух сеньоров.
- Технологический мост: написал прокси-сервис, который дублировал записи в старую и новую БД, синхронизировал через Debezium.
Результат: переход без единого инцидента уровня SEV1, p99 снизился с 2с до 200мс, вывод фич ускорился в 4 раза.
Под капотом (internals)
В основе подхода лежат:
- Теория ограничений (TOC): выявили bottleneck — общая БД монолита, работали над ним в первую очередь.
- Cynefin framework: мы находились в комплексном домене, поэтому использовали probe-sense-respond: выкатывали теневой трафик, анализировали, итеративно адаптировали.
- Психология сопротивления изменениям: применял модель ADKAR, снимал страхи через прозрачные метрики и ранние победы (quick wins).
- System thinking: рассматривал поток создания ценности от идеи до продакшена, боролся с локальными оптимумами (например, команда ускоряла CI но игнорировала флаки-тесты).
Типичные ошибки кандидатов
-
Отсутствие делового контекста
Рассказывают только технические детали, не связывая с бизнес-ценностью. Это неправильно, потому что интервьюер оценивает влияние на продукт. Нужно начинать с проблемы бизнеса, её стоимости и конкретных метрик успеха. -
Умолчание конфликтов
Представляют проект как гладкий процесс. Реальный рост происходит через напряжённые споры. Следует описать, например, конфликт с архитектором о выборе CQRS, как вы аргументировали тестами пропускной способности и пришли к компромиссу. -
Отсутствие роли
Говорят «мы сделали», размывая личный вклад. Надо чётко выделить, что именно вы инициировали, спроектировали, настояли. Используйте «я предложил», «я провёл RFC», «я убедил продакт-менеджера приоритизировать observability».
Возможные дополнительные вопросы интервьюера
Как вы выбирали между Strangler Fig и полным переписыванием?
Полное переписывание — это риск заморозки фич и потеря контекста. Strangler позволил параллельно поставлять бизнес-ценность и снижать риск регрессии, направляя 1% трафика на новый сервис с автоматическим сравнением ответов.
Что бы вы сделали иначе, начни проект заново?
Раньше ввёл бы контрактное тестирование сервисов с Pact и унифицировал формат ошибок API в первый месяц — это сэкономило бы кучу времени на интеграции.
Как вы измеряли прогресс миграции?
Еженедельно отслеживали долю трафика на новых сервисах, количество удалённых строк в монолите и NPS от смежных команд. Использовали DORA-метрики: частота деплоя и время восстановления.
Как ты решал сложную техническую проблему
Краткий ответ (30–60 секунд)
Сервис авторизации падал с nil pointer dereference в 0.1% запросов под нагрузкой, но только в продакшене. Логи не содержали стектрейс из-за включённого оптимизатора паники. Проблему нашёл, пересобрав бинарник с -gcflags="all=-N -l" и добавив автоматический coredump-анализ. Корневая причина — гонка данных в кастомном кеше сессий, которую пропускал race detector из-за неправильной сборки. Исправил, внедрив sync.Map и обязательную проверку на go test -race в CI.
Развёрнутый ответ
Система аутентификации для 50 млн пользователей. Симптомы: раз в ~30 минут паника, но мониторинг не показывал корреляции с нагрузкой. Стек:
- Поднял тестовый стенд с зеркалированием продакшен-трафика через goreplay.
- Исключил GC-паузы и аллокации, профилируя pprof.
- Заметил, что паника происходит только при конкурентном обновлении TTL-кеша, где map не был защищён.
- Race detector (
go test -race) в CI не работал, потому что флаг-raceне был глобальным и тесты вызывались через Makefile без него. Внёс правку в Makefile и добавил статический анализgo vet.
Решение: перевёл кеш на sync.Map с атомарными операциями над TTL, реализовал фоновую горутину для очистки, добавил метрику числа промахов и время обновления.
Под капотом (internals)
- Go runtime:
nil pointer dereferenceвызываетpanic, который по умолчанию выводит стектрейс, но в нашем бинарнике использовалсяrecoverс кастомным логированием, которое не записывало информацию о панике — классическая ловушка. - Race detector: построен на ThreadSanitizer, требует пересборки с
-race, увеличивает потребление памяти в 10 раз. Мы не проверяли флаг для production-сборок, что упустило гонку. - sync.Map: внутри два слоя — read-only dirty map для lock-free чтений и блокировка при миграции. Для частых обновлений TTL лучше использовать шардированный map с
sync.RWMutexна сегментах. - Анализ coredump: настроил
GOTRACEBACK=crash, чтобы записывать core и потом читать через delve.
Типичные ошибки кандидатов
-
Прыжок в решение без гипотезы
Начинают менять код, не воспроизведя проблему. Неправильно, потому что теряется время и можно внести новые баги. Сначала изолируй, воспроизведи, профилируй. -
Игнорирование race detector
Считают, чтоgo test -raceво время разработки достаточен, но не проверяют все пакеты и интеграционные тесты. Нужно принудительно запускать-raceв CI для всех сборок и тестов, включая e2e. -
Недооценка observability
Пытаются решить без метрик, трейсов и профилирования. Без данных это гадание. Всегда добавляй метрики вокруг проблемного компонента, а потом смотри pprof/live.
Возможные дополнительные вопросы интервьюера
Почему не использовал sync.RWMutex?
sync.Map дал lock-free путь для чтений, которые составляли 99% операций. Профилирование показало, что RWMutex создавал контеншн на запись. В финальной версии шардированный map действительно показал чуть лучшую производительность, но sync.Map выиграл во времени внедрения.
Как убедился, что больше не потеряешь паники?
Добавил middleware, который всегда вызывает recover и логирует стектрейс с runtime.Stack() независимо от внешних флагов. Также внедрил алерты на резкий рост паник по категориям ошибок.
Как бы ты предотвратил такую проблему архитектурно?
Избегать разделяемого состояния: либо immutable структуры, либо каналы с одним владельцем. В данном кейсе кеш сессий можно было делегировать Redis, который гарантирует атомарность.
Как принимал решения
Краткий ответ (30–60 секунд)
Принимаю решения через модель «дерево решений с весами»: выписываю критерии (приоритет бизнеса, time-to-market, maintenance cost, риск), взвешиваю варианты. Если ставки высоки, провожу RFC с таблицей trade-offs и обязательным пунктом «что может пойти не так». После внедрения фиксирую решение в ADR.
Развёрнутый ответ
Пример: выбор БД для OLAP-отчётности. Рассматривались ClickHouse, PostgreSQL с Citus и ScyllaDB. Критерии: скорость запроса (вес 0.4), простота эксплуатации (0.3), стоимость (0.2), знание командой (0.1). Сделал PoC с загрузкой 1 млрд строк и нагрузочным тестированием под реальными запросами. По каждому критерию — объективные цифры. Выяснил, что ClickHouse даёт 50x выигрыш по скорости, но команда не имела опыта, поэтому добавил риск. Решением стал ClickHouse с условием найма эксперта и проведения внутреннего воркшопа. Зафиксировали в ADR-002.
При повседневных решениях использую:
- Cynefin framework: если домен простой — best practice, комплексный — эксперимент, хаотичный — быстро стабилизировать и потом анализировать.
- Decision Matrix с обязательным учётом uncertainty.
- Предсмертный анализ (premortem): прошу команду представить, что через полгода решение провалилось; записываем причины, затем прорабатываем mitigation.
Под капотом (internals)
- Когнитивные искажения: confirmation bias — ищем подтверждение любимому решению. Противодействую: «адвокат дьявола», требую от каждого члена команды аргументы против его собственного предложения.
- Модель OODA (Observe-Orient-Decide-Act): в быстрых ситуациях (инцидент) решение циклично: наблюдение, ориентация, решение, действие — с фиксацией гипотезы.
- Теория перспектив Канемана: избегаю ловушки невозвратных затрат, регулярно спрашивая «если бы мы начинали сегодня, выбрали бы мы это же решение?»
- Принцип Decision Record: ADR с номером, заголовком, контекстом, решением, последствиями — обеспечивает эволюционный дизайн.
Типичные ошибки кандидатов
-
Решение из личных предпочтений
«Мне нравится Rust, поэтому перепишем на Rust». Технические решения без привязки к бизнес-требованиям и компетенциям команды ведут к провалу. Всегда стартуй с «какую проблему бизнеса решаем». -
Паралич анализа
Бесконечно собирают данные, не назначая дедлайн. Нужно делать timeboxed PoC и принимать reversible decision быстро. Irreversible decisions требуют глубины, но и они должны иметь рамки. -
Не документировать контекст
Принимают решение и все забывают почему. Через полгода новый разработчик переделает и повторит ошибку. ADR — это инвестиция в будущее.
Возможные дополнительные вопросы интервьюера
Как ты поступаешь, когда данных недостаточно?
Делаю «spike» — временную ветку с минимальным экспериментом, который дешево проверить гипотезу, и принимаю решение с оговоркой «пересмотр через 2 недели при новых данных».
Приведи пример решения, которое оказалось неверным, и что ты сделал?
Выбрали NoSQL документо-ориентированную БД для финансовых отчётов, посчитав, что схема будет гибкой. Потом много времени ушло на ад-хок консистентность и отчёты через map-reduce. Вернулись к PostgreSQL, но это было дорого. Извлёк урок: для OLAP двигаться от запросов к модели, а не наоборот.
Как работал с командой
Краткий ответ (30–60 секунд)
Мой подход — servant leadership: создаю среду, в которой инженеры могут максимально эффективно работать. Это включает чёткие границы ответственности, психологическую безопасность, проактивное снятие блокеров, прозрачные цели и постоянную обратную связь. Инструментально использую OKR, еженедельные 1-on-1 и ретроспективы с метриками DORA.
Развёрнутый ответ
В кросс-функциональной команде из 6 человек (3 Go-бэкенда, 2 фронта, QA, DevOps) мы столкнулись с проблемой зависимости от одного эксперта по системе. Решение:
- Knowledge sharing: парное программирование на критичных участках, обязательные CR с пояснениями, документирование в ADR и runbooks.
- Автономия: каждый член команды владел микросервисом от проектирования до дежурства. Это повысило вовлечённость и снизило bus factor.
- Метрики здоровья команды: time-to-merge, количество прод-инцидентов, время нахождения в on-call без алертов, опросы eNPS.
- Регулярная ротация: каждый месяц человек из бэкенда брал задачу по фронту и наоборот — для T-shaped skills и общего понимания.
Под капотом (internals)
- Модель Такмана: команда проходила forming, storming, norming, performing. Я осознанно управлял этими стадиями — например, в storming фазу легитимизировал конфликты как поиск истины.
- Психологическая безопасность (Google Project Aristotle): ввёл правило «нет глупых вопросов», благодарил за признание ошибок, рассматривал инциденты blameless.
- Теория потока Чиксентмихайи: убирал прерывания, защищал команду от срочных, но неприоритетных запросов, давал задачи уровня навыка + 10% вызова.
- Система Грейвза и спиральная динамика: учитывал, что члены команды находятся на разных уровнях потребностей (безопасность, принадлежность, самореализация) — подбирал мотивацию индивидуально.
Типичные ошибки кандидатов
-
Микроменеджмент
Кандидаты описывают, как они всё контролировали. В старших ролях нужно давать свободу и отвечать за результат. Опиши, как ты создал рамки (SLI/SLO), и затем доверял. -
Игнорирование токсичности
Рассказывают только о технических успехах, умалчивая о токсичном члене команды. Необходимо показать, что ты управляешь и людьми: как проводил сложные разговоры и помог или попрощался. -
Отсутствие метрик
Говорят «команда была классная», без измеримых показателей. Инженерная культура требует данных: скорость поставки, качество, удовлетворённость. Приведи конкретные цифры улучшения.
Возможные дополнительные вопросы интервьюера
Как ты мотивировал самого слабого разработчика?
Выяснил его зону ближайшего развития — написание тестов. Назначил его ответственным за coverage, дал ментора, показывал, как его работа влияет на снижение инцидентов. Через квартал он стал champion по тестированию.
Что делаешь, когда команда не согласна с твоим решением?
Я не принимаю единоличных решений, касающихся технических деталей. Использую фасилитацию принятия консенсуса: выписываем варианты, делаем таблицу trade-off, голосуем пальцами вверх/вниз. Если тупик, беру ответственность как лид, объясняю причины и ставлю срок пересмотра.
Как разрешал конфликты в команде
Краткий ответ (30–60 секунд)
В ситуации спора о выборе между оркестратором (Temporal) и ручными saga для workflow заказов, я применил подход «конфликт как исследование». Организовал встречу с повесткой: «Что мы оптимизируем — скорость разработки или контроль?». Провели PoC обоих решений, замерили сложность поддержки и время добавления нового шага. Сонаправил фокус с личных предпочтений на бизнес-метрики. Пришли к гибриду: простые flow — raw saga, сложные — Temporal, зафиксировали границы.
Развёрнутый ответ
Конфликт возник между сторонниками «pure Go» и внедрения готового решения. Эмоции накалялись. Действия:
- Отделил факты от интерпретаций: попросил каждого записать свои допущения.
- Активное слушание: перефразировал позиции, чтобы убедиться в понимании.
- Определил общие цели: надежность 99.95%, простота онбординга новичков.
- Создал безопасное пространство для несогласия: договорились, что проигравший вариант не означает «проигравшего человека».
- Запустили timeboxed spike на 3 дня, по результатам сравнили по матрице.
- Закрепили решение в ADR с пунктом «Revisiting criteria» через 3 месяца.
Под капотом (internals)
- Конфликтология Томаса-Килмана: определил, что конфликт перешёл из сотрудничества в конкуренцию. Использовал стиль «сотрудничество» — поиск выигрыша для всех.
- Ненасильственное общение (NVC) Розенберга: формулировал наблюдения, чувства, потребности, просьбы. Например: «Когда вижу, что PR задерживаются (наблюдение), я беспокоюсь за срок релиза (чувство), потому что нам нужна предсказуемость (потребность), можешь объяснить, какие блокеры?»
- Когнитивный диссонанс: приверженность своему инструменту усиливается публичными заявлениями. Я позволил каждому «сохранить лицо», предложив гибрид.
- Психология влияния Чалдини: использовал принцип авторитета (пригласили внешнего эксперта по Temporal), социальное доказательство (ссылался на опыт других команд).
Типичные ошибки кандидатов
-
Избегание конфликта
Говорят «мы не конфликтовали, всё гладко». Отсутствие конфликтов — признак либо подавления, либо безразличия. Сильные команды спорят продуктивно. -
Позиционная война
Фразы вроде «я настоял на своём». Выигрыш в споре ради ego разрушает отношения. В фокусе должно быть не «кто прав», а «как решить проблему». -
Нет документирования итога
Конфликт разрешили, но через месяц повторился, потому что не зафиксировали согласованные правила. Всегда пишите RFC/ADR с acceptance criteria.
Возможные дополнительные вопросы интервьюера
Что делаешь, если конфликт личный, а не технический?
Организую приватную встречу 1-on-1, применяю активное слушание, стараюсь понять глубинные потребности. Если не помогает — привлекаю нейтрального фасилитатора (Scrum Master, EM). Принципиально — не допускаю публичного выяснения отношений.
Приходилось ли тебе эскалировать конфликт руководству?
Да, один раз, когда бывший лид подрывал авторитет нового тимлида манипуляциями в кулуарах. Поскольку это угрожало поставке, после неудачных прямых разговоров я эскалировал инженеринг-менеджеру с конкретными фактами, после чего провели медиацию и перевели человека в другую команду.
Был ли опыт наставничества
Краткий ответ (30–60 секунд)
Да, менторил 12 разработчиков от junior до senior. Системно: строю индивидуальный план развития на основе компетентностной матрицы, провожу еженедельные сессии с разбором кода и архитектуры. Трое моих менти стали тимлидами, один — core-контрибьютором в etcd. Мой подход — guided mastery: не даю готовые решения, а задаю вопросы, чтобы человек сам пришёл к ответу.
Развёрнутый ответ
Пример: junior, пишущий на Go после буткемпа, не понимал concurrency. План:
- Диагностика: дал задание на написание веб-краулера. Выявил проблемы с гонками и утечками горутин.
- Фундамент: объяснил модель памяти Go, CSP, ушёл в исходники
select, показал под капотом. - Практика с обратной связью: совместно написали worker pool с graceful shutdown, parallel map-reduce.
- Код-ревью менти: ревьюил его PR с фокусом на идиоматичность и безопасность конкурентности.
- Расширение кругозора: рекомендовал классику «Concurrency in Go» и доклады Кэтрин Кокс.
- Ответственность: через 2 месяца доверил ему одному реализовать компонент real-time уведомлений, он справился.
Под капотом (internals)
- Зона ближайшего развития (Выготский): задания даю чуть выше текущего уровня, но с поддержкой. Важно, чтобы менти не был в панике.
- Модель Дрейфуса: junior — нужны правила, middle — контекст, senior — ментальные модели. Адаптирую стиль: для новичков — инструкции, для опытных — сократовский диалог.
- Когнитивное обучение: использую deliberate practice — изолированные упражнения на конкретный навык (написать data race, потом исправить).
- Мотивация 3.0 (Дэниель Пинк): стараюсь развивать автономию, мастерство и цель. Объясняю, как его задача влияет на пользователя.
Типичные ошибки кандидатов
-
Решение проблем за менти
«Я показал, как правильно, и он запомнил». Это создаёт зависимость. Вместо этого нужно, чтобы менти сам страдал над проблемой, а я лишь направлял. -
Одноразовый подход
Одна сессия — и всё. Наставничество эффективно только при регулярности и измеримых целях. Как минимум 3 месяца с промежуточными чекпоинтами. -
Игнорирование soft skills
Учат только tech. Но senior — это influence. Надо развивать коммуникацию, лидерство, умение давать и принимать фидбек.
Возможные дополнительные вопросы интервьюера
Как ты понимаешь, что менти готов к повышению?
Сверяюсь с карьерной матрицей компании. Также оцениваю способность решать неопределённые задачи, проактивность, влияние на смежные команды, получение положительных отзывов от peers.
Был ли негативный опыт менторства? Чему научил?
Да, один разработчик не хотел учиться глубже, ждал готовых решений. Я научился рано определять «необучаемость» и честно обсуждать это с менеджером, а не тратить ресурс впустую.
Как оцениваешь задачи
Краткий ответ (30–60 секунд)
Использую трёхточечную оценку на основе разбиения задачи до юнитов, помещающихся в один день. Применяю reference class forecasting: опираюсь на исторические данные похожих задач + калибровку по фактическому времени, корректируя свой «коэффициент неопределённости». Оценку даю в идеальных инженерных днях, затем умножаю на фактор команды (в среднем 1.5–2) для учёта коммуникаций и непредвиденного.
Развёрнутый ответ
На Planning Poker для задачи «интеграция с платёжным шлюзом X»:
- Декомпозировал на: изучение API, реализация client SDK на Go, обработка вебхуков, написание тестов (включая sandbox), документация, деплой и мониторинг — всего 8 подзадач.
- По каждой оценил реалистично (most likely): 1d SDK, 1d вебхуки, 1d тесты, 0.5d док, 0.5d деплой — всего 4 дня.
- Добавил оптимистичную (2 дня) и пессимистичную (8 дней из-за нестабильности sandbox API).
- Формула PERT: (O+4M+P)/6 = (2+16+8)/6 ≈ 4.3 дня.
- Выявил риск: нестабильность песочницы. Запросил у вендора гарантии, заложил retry с exponential backoff. В итоге с учётом истории аналогичных интеграций в команде (4–6 дней) дал 5 дней с буфером.
- После завершения провёл ретроспективу оценки: факт 5.5 дней, учёл причины задержки для будущих оценок.
Под капотом (internals)
- Planning fallacy (ошибка планирования): люди недооценивают время. Противодействие — reference class и премортем (задаю вопрос «почему задача затянется на 3 недели?»).
- Закон Паркинсона: работа расширяется до отведённого времени. Коучу команду разбивать задачи на ≤1 день и ограничивать WIP.
- Теория вероятностей: PERT использует бета-распределение. Калибрую экспертно, но с оглядкой на статистику — записываю свои оценки и фактические, высчитываю Brier score для самооценки.
- Ментальный байес optimism bias: обязательный пункт «предположения» в оценке: перечисляю явные допущения (API стабилен, документация верна) — если нарушаются, оценка пересматривается.
Типичные ошибки кандидатов
-
Оценка в человеко-часах без разбиения
«Мне кажется, это займёт 3 дня». Такая оценка субъективна и не повторяема. Необходимо декомпозировать и базироваться на данных. -
Игнорирование non-coding активностей
Не учитывают код-ревью, CI настройки, документацию и итерации по обратной связи. Время на «отполировать» иногда равно написанию. Использую «Definition of Done» как чеклист. -
Слепое следование story points
Переводят story points в дни линейно. Story points — относительная сложность, нельзя конвертировать 1:1. Оцениваю скорость команды через throughput (количество задач в неделю) а не часы.
Возможные дополнительные вопросы интервьюера
Как объясняешь менеджменту, что оценка — не обязательство?
Использую конус неопределенности: на старте точность ±50%, к середине ±20%. Обещаю пересмотр оценки после инцепшена и прошу закладывать буфер на уровне портфеля.
Что делаешь, если задача не влезает в спринт?
Обсуждаю с продакт-менеджером trade-off: сократить scope, увеличить срок или распараллелить. Никогда не жертвую качеством (не пропускаю тесты) ради дедлайна.
Что делаешь, если не согласен с решением архитектора
Краткий ответ (30–60 секунд)
Сначала глубоко пойму его аргументы — задаю вопросы, а не спорю. Затем проверю свои предположения данными: проведу быстрый PoC или напишу краткий RFC с альтернативой и trade-offs. Обсужу тет-а-тет, чтобы не ставить под сомнение авторитет публично. Если разногласие фундаментально и влияет на бизнес-метрики, эскалирую с предложением провести Architecture Review Board с участием независимого эксперта, всегда оставаясь уважительным.
Развёрнутый ответ
Пример: архитектор принял решение писать новый сервис на Java, ссылаясь на зрелость экосистемы. Я, как Go-чемпион, видел, что для I/O-bound сервиса Go даст лучшую утилизацию и скорость разработки.
- Понял позицию: спросил, какие риски видит в Go — ответ: отсутствие корпоративной поддержки библиотек и мало разработчиков.
- Данные: собрал метрики с похожего Go-сервиса — p99 latency, потребление CPU/Mem. Показал, что команда из 2 человек уже пишет на Go и может поддерживать.
- Альтернатива с компромиссом: предложил сделать экспериментальный сервис на Go с чётким SLA и через 3 месяца принять решение.
- Провёл встречу 1:1, выслушал опасения, предложил risk mitigation (тренинг, код-ревью от экспертов).
- Договорились на эксперимент. Через 3 месяца по метрикам Go удовлетворил, и мы приняли его как стандарт для новых сервисов.
Под капотом (internals)
- Принципы influence (Роберт Чалдини): взаимный обмен (я предлагал уступку в виде тренировок), авторитет (ссылался на успешные кейсы внутри компании), консистентность (связал с целями CTO).
- Сложные переговоры (Harvard method): отделять людей от проблемы, фокус на интересы, а не позиции, придумывать взаимовыгодные варианты, использовать объективные критерии (метрики).
- Модель виртуальной архитектурной власти: в матричных структурах истинная власть — influence. Строил доверие через delivery.
- Psychological safety: явно говорил, что не ставлю под сомнение компетентность архитектора, а хочу снизить технический риск.
Типичные ошибки кандидатов
-
Публичный вызов
«На стендапе я сказал, что это глупость». Это подрывает авторитет архитектора и создаёт конфронтацию, команда теряет уверенность. Обсуждать несогласие нужно приватно. -
Саботаж решения
«Я сделал по-своему втихую». Вредит командному единству и может привести к инцидентам. Лучше явно эскалировать, чем идти в обход. -
Нет данных
Оппонируют на основе личного вкуса, а не объективных измерений. Технические решения в старших грейдах принимаются через метрики, а не мнения.
Возможные дополнительные вопросы интервьюера
Что делаешь, если решение архитектора нарушает инженерные принципы (например, нет observability)?
Привожу к обсуждению стандарты и SLA сервиса, показываю риск: без трейсов мы не выполним SLO. Если аргумент игнорируется, эскалирую до EM с рисками для бизнеса.
Приходилось ли тебе идти против архитектора и выигрывать?
Да, я предложил иной подход шардирования БД, доказав через симуляцию, что его вариант приведёт к hot-spots. Он согласился, и позже мы совместно написали ADR.
Как убедить команду использовать новую технологию
Краткий ответ (30–60 секунд)
Я использую подход «покажи, а не рассказывай»: создаю минимальный, но впечатляющий PoC, который решает конкретную боль команды. Подкрепляю метриками (скорость разработки, производительность), провожу воркшоп, чтобы команда «пощупала» технологию. Далее продвигаю через champions — заинтересованных коллег. Итеративно, с правом на ошибку.
Развёрнутый ответ
Кейс: внедрение gRPC вместо REST для межсервисного взаимодействия. Команда привыкла к JSON и отказывалась.
- Нашёл боль: генерация клиентов по OpenAPI была ручной, постоянно расходилась. Продемонстрировал генерацию кода из
.protoи автоматическую совместимость. - PoC с цифрами: перевёл один не критичный внутренний эндпоинт, показал снижение latency на 40% и пропускную способность выше в 2 раза.
- Снизил порог входа: сделал внутренний шаблон сервиса с gRPC, добавил в CI проверку обратной совместимости protobuf (buf breaking).
- Пилотная группа: убедил пару сеньоров присоединиться к пилоту, они стали адвокатами.
- Страховка: оставили REST Gateway для внешних клиентов, чтобы не ломать совместимость.
- Обучение: провёл Brown Bag сессию с реальными задачами.
Под капотом (internals)
- Diffusion of innovation (Эверетт Роджерс): сначала убеждаю инноваторов и ранних последователей, затем большинство идёт за ними.
- Техника «Trojan Horse»: встроил новую технологию как часть давно желаемого улучшения производительности, а не как самоцель.
- FUD и сопротивление: боязнь неизвестного. Снимаю через прозрачность, документацию, поддержку в чате.
- Организационное изменение (модель ADKAR): Awareness (показал боль), Desire (личные выгоды), Knowledge (обучил), Ability (шаблон), Reinforcement (метрики успеха).
Типичные ошибки кандидатов
-
Продвигать технологию ради технологии
«Давайте перепишем всё на Rust, потому что он модный». Никакой бизнес-выгоды. Технология должна решать конкретную проблему и иметь измеримый эффект. -
Навязывание сверху
«Я архитектор, я так сказал». Убивает вовлечённость и порождает скрытое сопротивление. Команда должна прийти к согласию через участие. -
Бросать после внедрения
Показал PoC и ушёл, оставив без поддержки. Адоптация требует поддержки, документации и champions. Нужно оставаться до момента, когда технология станет нормой.
Возможные дополнительные вопросы интервьюера
Что делать, если PoC не убедил команду?
Значит, я недостаточно понял их боль. Проведу ещё интервью, чтобы выяснить истинные возражения, и либо доработаю PoC, либо признаю, что технология сейчас не подходит.
Как избежать фрагментации стека?
Перед внедрением провожу Tech Radar-совещание всей инженерной организации и обязан получить одобрение архитектурного комитета. Определяем уровень «Adopt / Trial / Assess / Hold».
Приведи пример неудачного проекта и чему он научил
Краткий ответ (30–60 секунд)
Проект по построению real-time аналитической платформы провалился из-за переоценки возможностей ClickHouse под наш паттерн обновлений и недооценки сложности миграции данных. Потеряли 6 месяцев. Главный урок: перед выбором хранилища необходимо точное моделирование нагрузки и обязательный PoC с прод-объёмом данных. Также я осознал ценность fail-fast культуры и раннего прототипирования критических компонентов.
Развёрнутый ответ
Мы строили панель мониторинга для трейдеров с обновлением каждые 2 секунды. Архитектор выбрал ClickHouse как аналитическую БД, соблазнившись скоростью чтения. Проблемы:
- Нагрузка была 70% update/insert (постоянное пополнение агрегатов) => ClickHouse плох для мутаций, начались тормоза merge.
- Модель данных пришлось переделывать 3 раза, теряя время.
- Команда не имела опыта, принимали решения на основе бенчмарков вендора.
Когда поняли, что не укладываемся, переписали на комбинацию PostgreSQL + Redis time-series, но потеряли доверие бизнеса. Проект закрыли.
Уроки:
- Всегда проводить стресс-тест с реальными данными и паттернами (не только идеальные условия).
- Внедрили обязательный Architecture Decision Record и pre-mortem.
- Ставку на unfamiliar tech делать только с параллельным fallback-планом.
Под капотом (internals)
- Sunk cost fallacy: команда продолжала, потому что уже много вложили. Научился проводить «premortem» и ставить hard deadlines на pivot.
- Теория нормальных аварий (Perrow): в сложной системе инциденты неизбежны, если компоненты плотно связаны. У нас была сильная связка: модель данных зависела от внутренних особенностей ClickHouse.
- Неопределённость требований (Cynefin): были в сложном хаосе, но вели проект как в простом домене. Надо было итеративно уточнять требования и пересматривать архитектуру.
- Психологический эффект иллюзии контроля: архитектор переоценивал управляемость технологии. Выработал правило «trust but verify».
Типичные ошибки кандидатов
-
Перекладывание вины
«Это всё архитектор виноват». Senior-инженер должен разделять ответственность за провал и показывать, что извлёк личные уроки. -
Нет количественного ущерба
Просто «проект не взлетел». Необходимо указать стоимость: потерянное время, упущенная выгода, репутационные потери, чтобы показать глубину анализа. -
Отсутствие конкретных изменений процессов
Описывают неудачу, но не говорят, что изменили в подходе. Важно показать, что именно вы внедрили после: pre-mortem, PoC критерии, review архитектуры.
Возможные дополнительные вопросы интервьюера
Как ты сообщил бизнесу о провале?
Подготовил отчет с корневой причиной, потерями, уроками и планом предотвращения. Не защищался, а взял ответственность. Предложил закрыть проект и сэкономить деньги.
Что бы ты сделал иначе как лид?
Настоял бы на 2-недельном спринте валидации самой рисковой гипотезы (мутации в ClickHouse) до начала полномасштабной разработки.
Какой твой вклад в open-source
Краткий ответ (30–60 секунд)
Maintainer Go-библиотеки для работы с финансовыми протоколами FIX/FAST, используемой в нескольких компаниях. Вклад в etcd — исправление race condition при компактировании. Также веду блог с разбором устройства Go-рантайма, публикую RFC-подобные статьи. Моя мотивация — отдавать сообществу то, чем пользуюсь сам, и повышать инженерный уровень через публичный код и документацию.
Развёрнутый ответ
- go-fix: библиотека парсера/сериализатора FIX сообщений с нулевым аллоцированием. Реализовал кодогенерацию на основе spec-схемы. Пришлось глубоко изучить unsafe для манипуляций слайсами без побега в кучу. Развиваю её 3 года, 200 звезд, принял PR от 15 контрибьюторов.
- etcd: заметил, что под нагрузкой компактирование может вызвать панику, воспроизвел, отправил PR с тестом и фиксом. Научился читать кодовую базу таких проектов.
- Образовательный контент: перевел на русский спецификацию Go memory model с комментариями; написал цикл статей «Go scheduler: под капотом».
Под капотом (internals)
- Open-source как инженерия: требует умения работать с чужим кодом, четко описывать мотивацию в issue, следовать стилю проекта, проходить строгий review. Это развивает «influence без authority».
- Лицензии и compliance: разбираюсь в MIT/Apache, совместимости, CLA.
- Социальная динамика сообщества: понимаю, что мейнтейнеры — добровольцы, поэтому мои PR всегда минимальны, с бенчмарками и тестами.
Типичные ошибки кандидатов
-
Завышение роли
«Я контрибьютил в Kubernetes» — а на деле поправил опечатку в README. Это видно по PR. Лучше честно сказать про мелкий вклад и акцентировать значимость своих проектов. -
Отсутствие вклада
Кандидат говорит, что нет времени. Senior может хотя бы вести технический блог или помогать на StackOverflow, это показывает инженерную культуру. -
Неумение рассказать о влиянии
Рассказывают только про код, но не про пользователей. Важно: кто использует, зачем, какие проблемы решает.
Возможные дополнительные вопросы интервьюера
Почему ты решил написать свою библиотеку FIX, если есть QuickFIX/Go?
QuickFIX/Go имел проблемы с производительностью и аллокациями для высокочастотного трейдинга. Мой фреймворк даёт возможность zero-copy парсинга и полностью генерируется из schema.
Как ты продвигал свою библиотеку?
Через доклады на профильных митапах, публикацию сравнительных бенчмарков в блоге компании, и предоставление бесплатного саппорта первым пользователям.
Как ты учишься новому
Краткий ответ (30–60 секунд)
Моя стратегия — «T-shaped skill deepening»: 70% через практику и написание кода, 20% через чтение исходников и стандартов, 10% через книги и доклады. Составляю план обучения на квартал с конкретными проектами/пет-проектами. Обучение обязательно завершаю публичным артефактом (доклад, статья, код) — это кристаллизует знания.
Развёрнутый ответ
Когда осваивал eBPF для Go-сервисов:
- Обзор: прочитал документацию и понял возможности.
- Глубокое погружение: прошёл курс «Linux Kernel Tracing», написал простые программы на C.
- Связывание с Go: изучил библиотеку
cilium/ebpf, собрал программу, которая считает latency системных вызовов. - Пет-проект: создал агент для мониторинга сетевых аномалий в Go-сервисах.
- Публикация: сделал внутренний воркшоп и статью в блоге, что заставило упорядочить знания.
Под капотом (internals)
- Кривая забывания Эббингауза: повторяю материал по spaced repetition, веду Zettelkasten заметки в Obsidian.
- Метод Фейнмана: объясняю сложное простыми словами. Если не могу объяснить, значит, не понял.
- Модель сознательной компетентности: осознаю, на какой стадии нахожусь (бессознательная некомпетентность → сознательная компетентность), что помогает смириться с фрустрацией на этапе «я ничего не понимаю».
- Пирамида обучения: учу других, пишу код — это максимальное усвоение.
Типичные ошибки кандидатов
-
Пассивное обучение
«Читаю много статей». Без практики и проверки понимания знания быстро улетучиваются. Надо применять в коде или учить других. -
Распыление
Пытаться одновременно выучить Rust, ML, блокчейн. Глубина > ширина. Лучше иметь план и фокусироваться на одной теме до продуктивного уровня. -
Отсутствие измеримых целей
«Хочу лучше знать алгоритмы». Цель должна быть конкретной: «Решить 20 задач с LeetCode hard, написать библиотеку графов для Go».
Возможные дополнительные вопросы интервьюера
Как остаешься в курсе развития Go?
Читаю release notes, слежу за proposal в go-review, подписан на рассылку Golang Weekly, смотрю избранные доклады с GopherCon.
Что учишь прямо сейчас?
Глубже изучаю формальные методы верификации (TLA+) для описания распределенных консенсусов, потому что планирую применять в проектировании финансовых транзакций.
Как относишься к code review
Краткий ответ (30–60 секунд)
Code review — основной инструмент обеспечения качества и sharing знаний. Я отношусь к нему как к асинхронному сотрудничеству: проверяю не только корректность, но и дизайн, читаемость, тестируемость, производительность. Всегда комментирую уважительно и с предложением альтернативы. При получении ревью благодарен, не воспринимаю персонально. Моё правило: PR менее 400 строк, time-to-merge < 4 часов.
Развёрнутый ответ
Мои критерии ревью:
- Дизайн: соответствует ли архитектурным принципам, нет ли утечки абстракций.
- Корректность: edge cases, обработка ошибок, идемпотентность.
- Безопасность: валидация ввода, дыры типа SQL-инъекций (даже в ORM).
- Testability: код легко тестировать, зависимости внедряются через интерфейсы.
- Observability: достаточны ли метрики, логи, трейсы.
- Идиоматичность Go: эффективное использование интерфейсов, избегание преждевременных обобщений, правильная конкурентность.
Процесс: автоматические линтеры + golangci-lint обязательны. Далее я захожу в PR, оставляю комментарии по severity: nitpick, suggestion, important, blocker. Блокирую только при реальных рисках. Завершаю позитивным комментарием, чтобы поощрить хорошие решения.
При получении ревью: если не согласен, предлагаю встретиться у доски или обсудить в треде, не переходя в глухую оборону.
Под капотом (internals)
- Парадокс code review: слишком строгий review снижает throughput, слишком мягкий — качество. Оптимум в культуре «достаточно хорошо, чтобы в прод» с последующей доработкой.
- Эффект Эгора/угрозы статуса: получение замечаний активирует защитные реакции. Я осознанно отделяю код от личности, использую язык «этот подход может привести к...» вместо «ты неправильно сделал».
- Теория когнитивной нагрузки: слишком большой PR не ревьюится тщательно. Поэтому автоматически бью на части и требую small batches.
- Conventional Comments: стандартизация тона (praise, nitpick, suggestion) снижает негатив.
Типичные ошибки кандидатов
-
Ревью как придирки
Комментируют каждое форматирование (для этого есть линтер). Это создаёт токсичную атмосферу. Автоматизируй стиль, фокусируйся на существенном. -
«LGTM» без содержания
Кандидат говорит, что быстро аппрувит. Если на PR стоит твоя подпись, ты делишь ответственность за баг. Нужно проводить минимум поверхностный логический анализ. -
Защита своего кода
Принимают критику как личное оскорбление. Senior должен показывать пример открытости и благодарности за каждое замечание.
Возможные дополнительные вопросы интервьюера
Как ты поступаешь, если автор не соглашается с твоим важным замечанием?
Объясняю риск и предлагаю вовлечь третью сторону (другого сеньора или архитектора). Если риск не критичен, помечаю как non-blocking, но прошу оставить TODO с твоим комментарием.
Как ускорять ревью в команде?
Ввести SLA на review (например, 2 часа в рабочее время), авто-назначение ревьюверов по CODEOWNERS, уменьшить размер PR, вознаграждать быстрое ревью.
Как ты тестируешь свой код
Краткий ответ (30–60 секунд)
Придерживаюсь пирамиды тестирования: множество юнит-тестов (table-driven, с моками через интерфейсы), среднее количество интеграционных (с реальными БД в testcontainers), и несколько e2e для критических путей. Обязательно тестирую ошибки и граничные условия. Использую property-based testing для сложных алгоритмов и mutation testing для оценки качества тестов. Всё в CI, с проверкой покрытия >80% на критичных пакетах.
Развёрнутый ответ
Для типичного Go-сервиса:
- Юнит-тесты:
go testсtestify, интерфейсами для моков (ручные или mockgen). Пример: тестирую сервис создания заказа, подставляя мок репозитория и брокера событий. -
Table-driven tests: обязательны для обработчиков, чтобы покрыть все кейсы ошибки валидации, бизнес-правил.
Go tests := []struct { name string input OrderRequest want error }{ {"valid order", validReq, nil}, {"negative quantity", negReq, ErrInvalidQuantity}, } -
Интеграционные тесты: testcontainers-go поднимаю PostgreSQL, Redis, Kafka в CI. Проверяю реальные SQL-запросы и идемпотентность.
- Property-based testing:
gopterилиrapidдля компонента расчета комиссий — генерирую случайные входы и проверяю инварианты (комиссия всегда <100%). - Тесты производительности (benchmark): в пакете с критичными секциями, сравниваю до/после рефакторинга, защищаю от регрессии.
- Contract testing: с Pact для взаимодействия с внешними сервисами.
- Fuzzing:
go test -fuzzдля парсеров пользовательского ввода.
Под капотом (internals)
- Coverage и fault detection: покрытие не гарантирует отсутствие багов, поэтому добавляю mutation tests (
go-mutesting) — мутирует код и проверяет, что тест упадёт. - Test Pyramid & Trophy: осознаю, что UI/e2e хрупкие, заменяю основную часть на интеграционные и контрактные.
- Go testing runtime: знаю, что юнит-тесты компилируются с race detector опционально, включаю его. Также понимаю кеширование результатов (
go test -count=1для избежания кеша). - Parallel tests: использую
t.Parallel()для ускорения, но слежу за изолированностью.
Типичные ошибки кандидатов
-
Тесты только happy path
Не проверяют ошибки, таймауты, некорректный ввод. В реальности продакшен падает именно на edge cases. Каждый if err != nil должен тестироваться. -
Использование глобального состояния
Тесты зависят от глобальной переменной конфига, что делает их невоспроизводимыми. Внедрять зависимости через конструктор или интерфейс, использоватьt.Setenv. -
Слишком много моков
Мокают всё, включая стандартную библиотеку. Это приводит к тестам, проверяющим моки, а не логику. Предпочитать реальные реализации для интеграционных тестов.
Возможные дополнительные вопросы интервьюера
Как ты определяешь, какие тесты писать в первую очередь?
Применяю risk-based: тестирую критичные для бизнеса сценарии (платежи, аутентификация) и компоненты с наибольшей цикломатической сложностью.
Как ты тестируешь конкурентный код?
Использую go test -race обязательно, тестирую с разным числом горутин, пишу тесты с детерминированным планировщиком (например, через каналы синхронизации). Для сложных структур типа lock-free кольцевых буферов — property-based с параллельными операциями и проверкой инвариантов.
Что для тебя значит "хороший код"
Краткий ответ (30–60 секунд)
Хороший код — это код, который легко читается, тестируется и расширяется командой. Он идиоматичен для Go, с чёткими границами ответственности, явной обработкой ошибок, малым количеством магии. Имеет высокое покрытие тестами, но не жертвует простотой ради догматических показателей. Главный критерий: новый разработчик может внести фичу без страха сломать соседние модули.
Развёрнутый ответ
Принципы, которые я культивирую:
- Простота (KISS): избегаю преждевременной абстракции, не усложняю без причины. В Go это выражается в маленьких интерфейсах, предпочтении композиции наследованию.
- Читаемость: код — в первую очередь для людей. Имена переменных отражают смысл, функции — не более 30 строк, «happy path» слева, ранние возвраты.
- Идиоматичность: следование Effective Go и Code Review Comments. Например, не использовать панику для контроля потока, аккуратный
context.Context. - Тестируемость: зависимости инжектируются, интерфейсы используются для возможности замены в тестах.
- Производительность: не преждевременная, но осознанная: избегаю аллокаций в горячих путях (синк-пулы,
strings.Builder), профилирую. - Документированность: godoc-комментарии на публичных функциях, README с примерами запуска.
- Консистентность: если в проекте принят определенный подход к логгированию или конфигурации, я не приношу свой стиль.
Пример «хорошего кода»: сервис, где бизнес-логика отделена от транспорта, ошибки домены типизированы, а конфигурация загружается строго типизированным способом.
Под капотом (internals)
- Когнитивная нагрузка: хороший код снижает WTF в минуту. Оцениваю через Cyclomatic Complexity < 10, Depth of Inheritance = 1.
- Закон Деметры: метод должен знать только о своих непосредственных зависимостях, минимизирую цепочки вызовов.
- Принцип наименьшего удивления: поведение соответствует ожиданиям читающего (например,
Getне должен мутировать). - Теория информации: избыточность комментариев — шум. Комментирую «почему», а не «что».
Типичные ошибки кандидатов
-
Переоценка DRY
Выносят каждые 2 строки в функцию, создавая «спагетти абстракций». В Go дублирование иногда лучше неверной абстракции. Применяю правило трёх: выношу только при третьем использовании. -
Игнорирование идиом Go
Пишут в стиле Java (наследование, геттеры/сеттеры для всего). Это вносит ненужную сложность. Использовать композицию, публичные поля для plain data, error-ы как значения. -
Нечитаемые однострочники
Ставят целью shorter is better, жертвуя читаемостью. Код читается в десятки раз чаще, чем пишется, поэтому явность > краткость.
Возможные дополнительные вопросы интервьюера
Как ты оцениваешь качество кода в ревью?
Смотрю на метрики: сложность, test coverage, но главное — могу ли я понять логику без комментариев автора. Прошу пояснить, если «магия» не очевидна.
Что такое «чистая архитектура» по-твоему?
Это независимость бизнес-логики от фреймворков и БД, направление зависимостей внутрь, явные границы. В Go это достигается использованием интерфейсов и разделением пакетов по доменам.
Как ты работаешь с требованиями от заказчика
Краткий ответ (30–60 секунд)
Отношусь к требованиям как к гипотезам, требующим проверки. Не принимаю «хотелки» за чистую монету, а выясняю проблему, которую они решают, через технику «5 почему». Формализую в виде user story с критериями приёмки, фиксирую неоднозначности. Технически невозможные или слишком дорогие требования — аргументирую альтернативой, просчитывая TCO и time-to-market.
Развёрнутый ответ
Кейс: заказчик потребовал синхронную интеграцию с внешним риск-скорингом в процессе авторизации, что добавило бы 500 мс к каждому запросу и нарушило SLO.
- Выяснил проблему: «Почему нужно синхронно?» — «Чтобы не пропустить мошенника». «Что будет, если ответ придёт через 2 секунды?» — «Можем пропустить транзакцию и потом откатить».
- Предложил асинхронный подход: авторизация быстрая, риск-скоринг постфактум с возможностью блокировки карты и уведомлением. Показал, что 99% транзакций легитимны, и задержка неоправданна.
- Прототип: за 2 дня сделал демо с отложенной проверкой, где мошенническая операция всё равно блокировалась через 1 секунду, что устроило комплайнс.
- Зафиксировали договорённости: спецификация с acceptance criteria, включая допустимое время задержки.
Под капотом (internals)
- Техника «Job to be Done» (Клейтон Кристенсен): ищу, какую «работу» нанимает заказчик. Это смещает фокус с фичи на результат.
- Impact Mapping: связываю требования с бизнес-целями, чтобы приоритизировать.
- Когнитивное искажение «solutionism»: клиент предлагает решение, а не проблему. Я возвращаю к проблемному пространству.
- Теория игр (переговоры): иногда заказчик завышает требования, ожидая торг. Предлагаю варианты trade-off, сохраняя отношения.
Типичные ошибки кандидатов
-
Бездумное исполнение
«Сказали сделать кнопку — сделал». Инженер должен влиять на продукт, предлагая лучшие решения. Это и есть уровень senior. -
Конфликт с заказчиком
«Это глупое требование, я не буду делать». Так сжигаются мосты. Нужно через цифры и risk/benefit обосновывать альтернативу. -
Отсутствие документации требований
Не фиксируют Acceptance Criteria, потом заказчик говорит «я имел в виду другое». Всё должно быть записано и согласовано.
Возможные дополнительные вопросы интервьюера
Как ты приоритизируешь конфликтующие требования от двух стейкхолдеров?
Организую встречу с обоими, выясняю бизнес-ценность каждого требования, перевожу на язык денег/риска. Предлагаю компромисс, если не получается — эскалирую владельцу продукта.
Приходилось ли отказывать заказчику?
Да, когда требование противоречило нормам безопасности (хранение CVV в открытом виде). Объяснил риски PCI-DSS и предложил безопасное решение через токенизацию. Заказчик был благодарен за защиту от возможного штрафа.
Как ты обеспечиваешь наблюдаемость observability сервиса
Краткий ответ (30–60 секунд)
Наблюдаемость строю на трёх столпах: структурированные логи в JSON, распределённые трейсы с OpenTelemetry и метрики Prometheus с чёткими RED (Rate, Errors, Duration) показателями. Каждый сервис при старте проверяет health/readiness endpoint. Автоматически настраиваю алерты на SLO (burn rate). Использую Grafana дашборды как код.
Развёрнутый ответ
Для Go-микросервиса:
- Трейсинг: middleware на уровне HTTP/gRPC создаёт спан, пробрасывает
traceparent. Каждый вызов БД или внешнего API оборачивается в дочерний спан. Использую OpenTelemetry SDK. - Метрики: регистрирую
http_requests_total,http_request_duration_seconds(гистограмма),http_errors_total. Бизнес-метрики: количество успешных заказов, время обработки. - Логи:
zerologс контекстом (trace_id,user_id). Никогда не логирую персональные данные. - Health probes:
/healthz— проверка жив ли процесс,/readyz— готов принимать трафик (проверка коннекта к БД). - Алерты: определяю SLO (99.9% availability), настраиваю multiwindow burn-rate алерты в Prometheus Alertmanager, чтобы не будить по пустякам и не пропустить серьёзное.
- Дашборды: Grafana dashboard provisioned через Git, показывают RED для каждого сервиса, тепловую карту latency, top ошибок.
Под капотом (internals)
- Модель USE и RED: USE (Utilization, Saturation, Errors) для инфраструктуры, RED для сервисов.
- Context propagation в Go:
context.Context— идеальный носитель trace ID. Мои middlewares всегда извлекают и кладут в контекст. - Семплирование трейсов: чтобы не хранить всё, использую tail-based sampling или head-based probability (0.1% для normal, 100% для errors).
- High cardinality: осторожно с метриками по
user_id— это убьёт Prometheus. Использую логи для детализации.
Типичные ошибки кандидатов
-
Мониторинг без SLO
Собирают метрики, но не знают, какой latency приемлема. Без SLO невозможно понять, когда будить. Начинать нужно с определения порогов. -
Слишком много алертов
Алерты на всё подряд вызывают alert fatigue и игнорирование. Только бизнес-критичные: нарушение SLO, высокая частота ошибок, исчерпание ресурсов. -
Логи как текст без структуры
log.Printf("User %s did something", user). Парсить такое больно. Всегда структурированный JSON с постоянными полями.
Возможные дополнительные вопросы интервьюера
Как ты тестируешь observability?
Пишу интеграционные тесты, которые проверяют, что метрики инкрементируются после запроса и trace ID присутствует в логах. В CI поднимаю тестовый Prometheus и проверяю контракты.
Как отлаживаешь проблему «медленный запрос»?
Смотрю трейс: какой спан занимает время. Далее метрики этого спана, логи с ошибками. Если БД — смотрю query profiling.
Как ты выбираешь между созданием собственного решения и использованием стороннего
Краткий ответ (30–60 секунд)
Применяю правило: «строим только то, что является ключевой дифференцирующей компетенцией». Для остального выбираю best-of-breed open-source или коммерческий продукт. Сравниваю по критериям: зрелость, лицензия, community, стоимость поддержки, lock-in. Если open-source решение покрывает 80% потребностей без «уродливых обходных путей» — выбираю его. Если нужно нестандартное поведение в ключевой области — строю своё, но с чёткими границами.
Развёрнутый ответ
Пример: нужен движок workflow для цепочки согласования кредита. Варианты: Temporal, Camunda, самописный на Go.
- Анализ потребностей: главные требования — DAG с динамическими ветвлениями, поддержка saga, visibility, живучесть.
- Оценка Temporal: 95% match, отличное сообщество, API на Go, но требует отдельного кластера и сложен для локального запуска.
- Оценка Camunda: 70% match, Java стек, неудобно встраивать в Go, высокий overhead.
- Вывод: строить свой workflow было бы безумием, учитывая зрелость Temporal. Выбрали Temporal, обернули в тонкий Go-интерфейс, чтобы можно было заменить при необходимости (Anti-Corruption Layer).
- Свой код написали только для специфичного тайм-менеджмента в банковские дни — лёгкий плагин.
Под капотом (internals)
- Теория транзакционных издержек (Коуз): делай сам, пока внутренние издержки меньше рыночных. Но для зрелых продуктов external cost обычно ниже.
- Make vs Buy decision matrix: с весами оценка по бизнес-ценности, времени, рискам, гибкости.
- Технический долг интеграции: любое стороннее решение тащит зависимость. Обязательно создаю тонкий интерфейс-адаптер, чтобы изолировать вендора.
- Innovation Token Allowance: у команды ограниченное количество инноваций в год, не тратим на тулзы, которые не приносят конкурентного преимущества.
Типичные ошибки кандидатов
-
Not Invented Here синдром
«Мы напишем свой Kubernetes, потому что можем». Тратится время на поддержку аналога, а не на продукт. Исключение — только core бизнес. -
Слепое следование хайпу
«Все используют Kafka, значит и нам надо». Не надо усложнять стек без обоснованной потребности. -
Недооценка скрытой стоимости
Игнорирование операционной нагрузки от стороннего решения. Оцениваю TCO: сервера, обновления, мониторинг, экспертиза.
Возможные дополнительные вопросы интервьюера
Как избежать vendor lock-in?
Строю абстрактный интерфейс с использованием DIP, реализую адаптер для конкретной технологии. Держу возможность миграции через контрактное тестирование.
Был ли случай, когда пришлось отказаться от стороннего решения и переписать на своё?
Да, использовали универсальный библиотечный SDK для платежей, но он имел баги и низкую производительность на пиках. Постепенно переписали критический путь, вынеся его в минималистичный собственный клиент.
Расскажи о случае, когда тебе пришлось пойти на компромисс в архитектуре
Краткий ответ (30–60 секунд)
В проекте маркетплейса хотел применить CQRS для разделения чтения и записи, но команда была небольшая и сроки жёсткие. Я пошёл на компромисс: внедрили простой синхронный read-write с PostgreSQL и отложенными materialized views. Архитектуру CQRS зафиксировали как будущее развитие, когда нагрузка вырастет. Это позволило выпустить MVP вовремя, не жертвуя корректностью.
Развёрнутый ответ
Идея CQRS: команды — одна модель, запросы — денормализованные проекции, обновляемые через события. Но:
- Команда не имела опыта event-driven архитектуры.
- Сжатые сроки — 2 месяца до демо инвесторам.
- Нагрузка ожидалась ~50 rps на старте.
Компромисс: реализовать монолитный сервис с хорошо изолированными сервисами (пакетами) на Go, с единой БД. Для отчётов создали в PostgreSQL materialized view, обновляемые раз в минуту. При этом я спроектировал интерфейсы репозитория так, чтобы позже можно было безболезненно разделить на read/write модели: интерфейс OrderRepository с методами Save, GetByID, Search. Контракт был ясен.
Результат: выпустили вовремя, а через 6 месяцев, когда нагрузка выросла до 2k rps и понадобилась денормализация, мы плавно перешли к CQRS с Kafka, заменив реализацию Search на чтение из проекции Elasticsearch. Без компромисса мы бы не выполнили обязательства.
Под капотом (internals)
- Принцип Парето: 20% усилий дают 80% результата. На старте CQRS дало бы лишь незначительное улучшение производительности, но 5x рост сложности.
- Эволюционная архитектура (Форд, Парсонс): заложил fitness functions (производительность поиска <100ms) и trigger для миграции.
- Технический долг как стратегия: сознательно взял управляемый долг (материализованные представления), оформив его в backlog с чёткими критериями.
- Переговоры с командой и PM: использовал технику BATNA — определил наихудший приемлемый вариант, что позволило не впадать в перфекционизм.
Типичные ошибки кандидатов
-
Перфекционизм
«Я не согласился на урезанный дизайн и проект провалился по срокам». Иногда лучше работающее сегодня, чем идеальное завтра. Важно оценивать контекст. -
Бездумное соглашательство
«Ладно, давайте сделаем кучу хаков». Компромисс должен быть явным, с фиксацией долга и планом его погашения, иначе он превращается в неконтролируемый легаси. -
Не объяснять trade-offs
Просто пошли на уступки, не донеся до команды риски. Старший инженер обязан протоколировать решение в ADR: что теряем и когда исправим.
Возможные дополнительные вопросы интервьюера
Как ты гарантировал, что компромисс не станет постоянным?
Завёл задачу в бэклоге с меткой «архитектурный долг» и привязал к метрике: когда p99 поиска превысит 200ms, начинаем миграцию. Так бизнес видел стоимость.
Чувствовал ли ты профессиональный дискомфорт от несовершенства?
Да, но я направил энергию на то, чтобы сделать «временное» решение максимально простым и заменяемым. Гордость не должна мешать доставке ценности.
Как ты определяешь и предотвращаешь технический долг
Краткий ответ (30–60 секунд)
Технический долг идентифицирую через статический анализ (сложность, дублирование), ретроспективы, метрики DORA. Классифицирую его по Мартину Фаулеру: reckless/prudent, deliberate/inadvertent. Управляю через backlog с тегом «tech-debt», где каждый элемент имеет оценку влияния на скорость и риск. Профилактика — строгие Definition of Done, инвестиционные 20% времени, архитектурные runways.
Развёрнутый ответ
В одном проекте мы накопили долг из-за быстрых релизов.
- Выявление: SonarQube показывал 15% дублирования, время сборки росло. На ретроспективе команда жаловалась на сложность добавления фич в модуль заказов.
- Измерение: оценили, что добавление среднего фичи занимает 5 дней вместо 2.
- Управление: создали «инициативу по уплате долга». Разбили на конкретные задачи: покрыть тестами критический код, рефакторинг монолитного
OrderServiceна компоненты, обновление библиотек. - Профилактика: внедрили правило «boy scout rule» (оставляй код чище, чем нашёл), обязательное ревью архитектуры для новых модулей, защитили 20% спринта на техдолг и рефакторинг. Ввели качественные ворота в CI: не допускать ухудшения覆盖率 линтерами.
Под капотом (internals)
- Модель квадрантов технического долга: объясняю команде разницу между осознанным долгом (мы знаем, что делаем, и фиксируем) и неосознанным (плохой дизайн из-за незнания). Первый приемлем, второй нет.
- Экономика долга: рассматриваю «проценты» — сколько времени мы тратим из-за долга каждый спринт. Если >10% capacity, это сигнал к интервенции.
- Fitness functions в CI: тесты архитектурных правил (например, зависимости пакетов) для предотвращения эрозии.
- Социальный аспект: давать команде чувство ownership за качество; публично поощрять рефакторинг.
Типичные ошибки кандидатов
-
Не различать виды долга
Тратят время на рефакторинг всего подряд без приоритетов. Нужно фокусироваться на долге, который тормозит бизнес или угрожает стабильности. -
Не учитывать «проценты»
Не измеряют влияние. Субъективное «грязный код» не убедит PM. Нужно показывать, как долг снижает velocity. -
Отсутствие профилактики
Только тушат пожары. Senior настраивает процессы, чтобы долг не появлялся: парное программирование, стандарты, статанализ.
Возможные дополнительные вопросы интервьюера
Как продать бизнесу необходимость снижения техдолга?
Показать график падения velocity и увеличения времени фич, перевести в упущенную прибыль. Предложить окупаемость: после X недель рефакторинга скорость вырастет на Y%.
Что делать, если менеджер не даёт время на техдолг?
Включаю небольшие улучшения в каждую фичу (boy scout rule), а крупные — оформляю как часть проекта по повышению надёжности, что напрямую связано с SLA.
Опиши свой подход к проектированию нового сервиса
Краткий ответ (30–60 секунд)
Стартую с определения границ сервиса (DDD bounded context), затем определяю API контракт (gRPC/REST), модель данных и её владение. Далее проектирую компоненты внутри по чистой архитектуре: домен, use cases, адаптеры. Определяю SLO и схему observability. Описываю это в RFC, получаю фидбек команды, затем приступаю к реализации с частыми интеграционными тестами.
Развёрнутый ответ
Новый сервис «Уведомления» (push, email, SMS):
- Бизнес-контекст: уведомления — supporting subdomain, поэтому не перегружаем, делаем простым.
- API First: написал Protobuf спецификацию
NotificationServiceс методамиSendиGetStatus. Обсудил с заказчиками (мобильные клиенты, внутренние сервисы). - Модель данных: PostgreSQL для шаблонов и статусов, очередь (NATS) для асинхронной отправки, чтобы не блокировать вызывающих.
- Архитектура:
- Транспортный слой: gRPC server.
- Use Case:
SendNotificationUseCaseвалидирует, сохраняет в БД, публикует задачу в очередь. - Воркеры-адаптеры:
EmailSender,PushSender,SmsSender— каждый со своей реализацией интерфейсаSender. - Observability: трейсы, метрики количества ошибок по провайдерам.
- Безопасность: rate limiting на API ключ, валидация шаблонов против инъекций.
- Инфраструктура: контейнеризация, Helm чарт, настройка HPA.
- SLO: 99.9% доступность API, 95-й перцентиль отправки ≤ 10 сек.
Под капотом (internals)
- DDD и bounded contexts: гарантирую, что сервис не лезет в данные других сервисов напрямую.
- Data mesh принципы: чёткое владение данными, публикация событий изменения статуса уведомлений для аналитики.
- C4 model: описываю контекст, контейнеры, компоненты и код — помогает команде и архитекторам.
- Fitness functions: проверка, что зависимости не нарушают слои, через
go-archлинтеры в CI.
Типичные ошибки кандидатов
-
Начинать с БД
«Спроектирую схему, потом API». Это ведёт к утечке базы в API. Контракт важнее хранения, начинаю с API и поведения. -
Перегружать first release
Закладывают Kafka, Redis, шардирование сразу. YAGNI. На старте монолитная БД и простой брокер, если не доказано иное. -
Нет SLO
Не знают, какой latency допустим. Без измерений невозможно принять правильные архитектурные trade-off.
Возможные дополнительные вопросы интервьюера
Как ты проектируешь под отказоустойчивость?
Применяю паттерны Circuit Breaker, Retry, Timeout, Bulkhead. Внедряю chaos engineering на этапе тестирования.
Когда нужно использовать синхронное взаимодействие вместо асинхронного?
Когда вызывающему критичен немедленный ответ для принятия решения. Но всегда проектирую так, чтобы можно было перейти на асинхронность.
Как ты пишешь документацию для своего кода и API
Краткий ответ (30–60 секунд)
Документация — часть продукта. Код документирую godoc-комментариями к публичным функциям и пакетам, объясняя «почему». Для API генерирую спецификацию (OpenAPI из proto) и публикую developer portal. Сложные архитектурные решения фиксирую в ADR. Руководства по runbook и on-call хранятся в репозитории вместе с кодом, чтобы не расходились.
Развёрнутый ответ
Для Go-сервиса:
-
Код: каждый экспортируемый идентификатор имеет комментарий, начинающийся с имени. Пример:
Go // OrderService processes orders and ensures idempotency via idempotency key. type OrderService struct { ... }Внутренние пакеты — документирую архитектурные решения в
doc.go. -
API: Protobuf комментарии транслируются в документацию. С помощью
protoc-gen-openapiгенерирую OpenAPI v3, выкладываю в Swagger UI, доступный внутри компании. - ADR: в папке
docs/adr/лежат решения с номерами, статусами, контекстом, последствиями. Это позволяет через полгода понять, почему выбрали MongoDB, а не PostgreSQL. - Runbooks: в
docs/runbooks/— инструкция по реагированию на алерты. Пишу их вместе с DevOps, проверяю актуальность на каждом post-mortem. - README: содержит quick start, как собрать, запустить локально с Docker-compose, примеры запросов.
Под капотом (internals)
- Docs-as-Code: вся документация в git, проверяется линтерами (markdownlint), собирается в статический сайт (MkDocs, Hugo) в CI.
- Diátaxis framework: делю документацию на tutorials, how-to, explanation, reference — каждая часть имеет свою структуру.
- Кривая забывания: знаю, что сам через месяц забуду контекст, поэтому пишу так, чтобы будущий я сказал спасибо.
- Информационная теория: минимизирую WTF/мин, но не жертвую полнотой. Лучше чуть больше, чем разработчик гадает.
Типичные ошибки кандидатов
-
Комментарии «что», а не «почему»
// Save сохраняет заказ. Это очевидно. Нужно объяснить, гарантирует ли идемпотентность, блокирует ли, какие side effects. -
Устаревшая документация
Полагаются на Wiki, которая не обновляется. Единственный источник правды — репозиторий, документация как код. -
Нет API-спецификации
REST API без OpenAPI, все передают из уст в уста. Генерация серверных/клиентских заглушек из спецификации экономит кучу времени.
Возможные дополнительные вопросы интервьюера
Как ты документируешь сложные бизнес-правила?
Пишу в domain пакете godoc и добавляю ссылки на ADR. Использую примеры в тестах — они служат живой документацией.
Как проверяешь, что документация корректна?
В CI запускаю тесты, которые валидируют примеры в godoc (в Go это нативно). Для API — контрактные тесты.
Как ты подходишь к планированию и декомпозиции больших задач
Краткий ответ (30–60 секунд)
Использую технику «слона по кусочкам»: от бизнес-эпика перехожу к user stories, затем к техническим задачам, каждая из которых занимает не более 1–2 дней. Применяю Vertical Slice Architecture, чтобы каждый инкремент давал ценность, а не просто технический слой. Визуализирую на доске, выявляю зависимости, определяю MVP.
Развёрнутый ответ
Задача: «Интеграция с новым эквайрингом».
- Эпик: возможность принимать платежи через Stripe.
- User Stories Mapping: выписал шаги пользователя (выбрать способ, оплатить, получить чек). Декомпозировал на истории: «Как покупатель, я могу оплатить через Stripe и увидеть статус».
- Техническая декомпозиция:
- Создать интерфейс
PaymentGatewayи выделить общую логику из существующего адаптера. - Разработать
StripeAdapter, реализующий методыAuthorize,Capture,Refund. - Настроить webhook handling для асинхронных уведомлений.
- Добавить мониторинг и алерты для ошибок Stripe.
- Feature-флаг для rollout.
- Создать интерфейс
- Вертикальный срез: первая задача — провести минимальный successful платеж со Stripe в тестовом окружении (все слои: UI чуть-чуть, API, адаптер, БД). Это занимает 2 дня и даёт проверку гипотез.
- Оценка и планирование: каждая подзадача ≤ 2 дня, всего ~8 задач, спринт 2 недели.
- Управление зависимостями: интерфейс
PaymentGatewayнужно сделать до Stripe-адаптера, поэтому ставим порядок.
Под капотом (internals)
- Техника SMART и INVEST: задачи конкретные, оценимые, независимые насколько возможно.
- Теория ограничений: ищу самую долгую цепочку задач и работаю над ускорением.
- Принцип Парето: определяю 20% функционала, дающего 80% ценности, и начинаю с него.
- Когнитивная нагрузка: ограничиваю WIP, чтобы не перегружать рабочую память.
Типичные ошибки кандидатов
-
Горизонтальная декомпозиция
«Сначала сделаем слой БД, потом сервис, потом API». Это приводит к интеграционным сюрпризам в конце. Каждая задача должна быть вертикальным срезом. -
Слишком крупные задачи (эффект 90%)
Задача на неделю часто недооценена. Разбиваю до уровня, где можно завершить за день и показать progress. -
Игнорирование зависимостей
В задачи не включают код-ревью, тестирование, деплой. DoD должен включать всё вплоть до работы в продакшене под флагом.
Возможные дополнительные вопросы интервьюера
Как ты оцениваешь неопределённость в задаче?
Провожу spike — выделяю часов 4-8 на исследование, чтобы снять неопределённость, перед тем как коммитить оценку.
Что делать, если после декомпозиции понимаешь, что сроки нереалистичны?
Сообщаю продакт-менеджеру немедленно, предлагаю опции: сократить объём, подвинуть срок, увеличить команду (последнее редко помогает сразу).
Расскажи о ситуации, когда тебе пришлось быстро развернуть исправление в продакшене
Краткий ответ (30–60 секунд)
Случился инцидент: баг в новом билде платёжного шлюза вызывал двойные списания. Я за 5 минут откатил релиз через кнопку в CI/CD (Argo Rollouts), затем за 1 час подготовил hotfix с дополнительной проверкой идемпотентности, развернул на канареечном окружении, проверил и выкатил на прод. После провёл blameless post-mortem и добавил интеграционный тест на идемпотентность.
Развёрнутый ответ
Система: Kubernetes, Go-сервис с Helm-чартом и ArgoCD.
- Обнаружение: алерт на рост ошибок «duplicate transaction». Я как дежурный инженер принял алерт, проверил логи, понял, что проблема в новой версии.
- Действие немедленное: прервал rollout, инициировал откат к предыдущей стабильной версии (Argo Rollouts позволяет сделать это моментально). Ущерб минимизирован.
- Диагностика: на тестовом стенде воспроизвёл проблему — оказалось, что при network timeout повторный запрос не проверял идемпотентность из-за ошибки в key extraction.
- Hotfix: написал исправление (извлёк
Idempotency-Keyзаголовок до обработки повтора), покрыл юнит-тестом и интеграционным тестом с симуляцией таймаута. - Развёртывание: собрал образ, задеплоил на canary (1% трафика), мониторил 15 минут, убедился в отсутствии ошибок, раскатил на всех.
- Post-mortem: задокументировал timeline, корневую причину, добавил в CI тест на идемпотентность, внёс в чеклист ревью пункт «проверка идемпотентности».
Под капотом (internals)
- Принципы SRE: MTTR важнее MTBF. Откат — первый инструмент. Всегда иметь возможность одной кнопкой вернуться.
- Graceful degradation: сервис был спроектирован так, что при ошибке возвращал код, не блокируя весь поток.
- CI/CD pipeline: сборка занимала 5 минут, деплой 2 минуты. Канареечный анализ с автоматическим сравнением метрик.
- Стрессоустойчивость: тренированные действия по incident management (команда, роли), что позволило не паниковать.
Типичные ошибки кандидатов
-
Медленный откат
Пытаются фиксить на ходу. Time to recover дороже всего. Откати сначала, чини потом. -
Нет post-mortem
Просто исправили и забыли. Без анализа система будет повторять ошибки. Blameless-разбор обязателен. -
Неавтоматизированный деплой
Собирали бинарник на локальной машине. Senior обеспечивает CI/CD с воспроизводимыми сборками.
Возможные дополнительные вопросы интервьюера
Как ты гарантируешь, что hotfix сам не создаст новых проблем?
Прохожу стандартный pipeline: юнит-тесты, интеграционные тесты, деплой на staging, canary, проду. Hotfix не исключение.
Что бы ты улучшил в процессе?
Добавил бы автоматизированные тесты на идемпотентность, которые инжектируют хаос (network errors), чтобы поймать до прода.
Как ты оцениваешь риск при внедрении новой технологии или архитектурного решения
Краткий ответ (30–60 секунд)
Оценку риска провожу через матрицу: вероятность отказа * тяжесть последствий. Для этого собираю информацию (опыт сообщества, PoC, краш-тесты), определяю неизвестные (unknown unknowns) через pre-mortem. Создаю risk mitigation plan: например, canary deployments, feature flags, параллельное функционирование старого и нового решения, план отката.
Развёрнутый ответ
Пример: внедрение Service Mesh (Istio) в кластер.
- Идентификация рисков: задержка сети, сложность отладки, несовместимость с gRPC health checks.
- Анализ: вероятность проблем с latency — высокая для трафика с жёсткими SLO; влияние — крит (потеря клиентов).
- Mitigation:
- Развернул Istio в тестовом кластере, замерил latency overhead (оказалось ~2ms).
- Включил mTLS в permissive mode, чтобы не сломать сервисы.
- Провёл A/B тест на 5% трафика с автоматическим анализом SLO.
- Имел план быстрого отключения через аннотации pod.
- Решение: приняли на вооружение, но оставили возможность байпаса sidecar для latency-critical сервисов.
- Мониторинг риска: ввели дашборд latency по сервисам до/после внедрения.
Под капотом (internals)
- Модель FMEA (Failure Mode and Effects Analysis): систематически перебираю возможные отказы, их причины и последствия.
- Теория чёрного лебедя (Талеб): учитываю маловероятные события с огромным воздействием. Проектирую антихрупкость.
- Принцип ALARP (As Low As Reasonably Practicable): снижаю риск до уровня, где стоимость дальнейшего снижения перевешивает выгоду.
- Monte Carlo симуляции: для оценки вероятности нарушения SLO при росте нагрузки.
Типичные ошибки кандидатов
-
Игнорирование организационных рисков
Технология хороша, но команда не умеет с ней работать. Риск «недостаток компетенций» часто выше технического. -
Не иметь плана отката
Верят в успех. Senior всегда планирует путь отступления. -
Оценивать только технический риск, игнорируя бизнес
Например, блокировка поставок из-за санкций на in-house софт. Нужно рассматривать legal, compliance.
Возможные дополнительные вопросы интервьюера
Как ты убеждаешь менеджмент принять остаточный риск?
Представляю риски в финансовых терминах (ожидаемые потери), показываю, что mitigation стоит дороже приемлемого уровня риска, и прошу официального акцепта.
Приведи пример, когда ты отказался от технологии из-за риска.
Отказались от Cassandra для финансового кошелька, так как риск потери консистентности (eventual consistency) был неприемлемым для аудита, выбрали CockroachDB.
Как ты управляешь своим временем и приоритетами в условиях высокой неопределенности
Краткий ответ (30–60 секунд)
В хаосе стартапа применяю матрицу Эйзенхауэра и принцип «самая важная задача» (MIT) на день. Утром определяю 1-3 задачи, которые двигают ключевую метрику. Для внезапных запросов — буфер 30% времени. Использую технику Pomodoro для фокуса, отключаю уведомления. Еженедельно сверяю приоритеты с бизнесом, чтобы не уйти в сторону.
Развёрнутый ответ
Ситуация: одновременно нужно запустить пилот для крупного клиента, исправить критичный баг и участвовать в найме.
- Сбор всех задач и запись в трекер.
- Категоризация:
- Срочно и важно: bug fix (влияет на текущих пользователей) → делаю немедленно.
- Важно, не срочно: пилот (стратегически важно) → выделяю блок 3 часа в день.
- Срочно, не важно: вопросы рекрутинга → делегирую координатору, оставляю себе только финальное интервью.
- Timeboxing: в календаре блокирую «deep work» 9:00-12:00.
- Борьба с переключениями: включаю Do Not Disturb, закрываю Slack.
- Регулярный пересмотр: на daily standup синхронизирую, не появилось ли более горячих задач.
- Управление входящими: запросы не в MIT — ставлю в очередь, явно сообщаю ETA.
Под капотом (internals)
- Теория ограничений и WIP: ограничиваю количество одновременных задач до 2-3, чтобы избежать затрат на переключение (до 20 мин на возврат в поток).
- Принцип Парето: 20% усилий дают 80% результата, фокусируюсь на них.
- Эффект срочности (urgency addiction): осознаю, что срочное не всегда важное, тренирую способность отказывать или договариваться о сроках.
- Метод GTD (Getting Things Done): выгружаю всё из головы в систему, чтобы не тратить когнитивный ресурс на запоминание.
Типичные ошибки кандидатов
-
Отсутствие приоритезации
«Я делаю то, что прилетело». Это реактивный подход, свойственный джуниорам. Senior проактивно формирует свою повестку. -
Многозадачность
Гордятся переключением. Это снижает качество и увеличивает время выполнения. Последовательное выполнение эффективнее. -
Не обсуждать конфликт приоритетов
Страдают молча, пытаясь сделать всё. Нужно идти к менеджеру с вопросом: «Вот эти две задачи, я могу качественно сделать одну из них к сроку, какую выбираем?»
Возможные дополнительные вопросы интервьюера
Как ты справляешься с перегрузкой?
Составляю обновлённый план с реалистичными датами, прошу помощи у менеджера в расстановке приоритетов и, если необходимо, в перераспределении задач.
Как часто ты переключаешь контекст?
Стараюсь не чаще 2 раз в день. Если много срочных вопросов — назначаю «офисные часы», когда мне можно задавать вопросы, чтобы не разрывать поток.
Расскажи о самом интересном баге, который ты нашел
Краткий ответ (30–60 секунд)
Самый интересный баг — самовосстанавливающаяся паника в Go-сервисе, которая пропадала при добавлении логов. Оказалось, гонка данных между горутинами при инициализации sync.Once, где внутри функции использовалась переменная, захваченная по указателю, и планировщик менял порядок. Race detector не ловил из-за inlining оптимизаций. Нашёл, изучая ассемблерный код сгенерированной функции.
Развёрнутый ответ
Симптомы: раз в ~100k запросов паника в sync.Once.Do, но если добавить fmt.Println — не воспроизводится. Хайзенбаг.
- Воспроизведение: написал нагрузочный тест, запускающий по 50 горутин конкурентный вызов инициализации конфига.
- Сужение: исключил GC, добавил sleep — не влияет. Понял, что влияет вывод в лог.
- Компиляторный анализ: собрал бинарник с
-gcflags="-S", сравнил ассемблер с логами и без. Увидел, что компилятор инлайнит функциюOnce.Doи переупорядочивает операции, при этом одна из переменных не была защищена happens-before отношением. - Корень: мой код передавал в
Once.Doзамыкание, которое захватывало*someObj, но саму переменнуюsomeObjменяли в другой горутине до вызоваDo. Spec гарантирует, чтоDoзавершится до возврата, но не гарантирует синхронизации с внешним изменением указателя. - Фикс: присвоил локальную копию до
Once.Do, а не захватывал внешнюю.
Под капотом (internals)
- Модель памяти Go: happens-before правила.
sync.Onceпредоставляет синхронизацию только между вызовамиDo, но не защищает гонки данных вне функции. - Escape analysis & inlining: логгирование отключало inlining, что меняло макет памяти и тайминг, гонка переставала проявляться — классический Heisenbug.
- Планировщик горутин: асинхронная преемптивность, разный порядок выполнения.
- Детектор гонок: ThreadSanitizer не мог обнаружить, потому что гонка была не на словарном уровне, а на уровне compiler reordering + указатель.
Типичные ошибки кандидатов
-
Поверхностный фикс
«Обернул в lock и всё». Это не решает корень, а только маскирует, можно оставить другие гонки. Нужно докопаться до причины. -
Игнорирование компиляторных оптимизаций
Не учитывают, что компилятор имеет право переупорядочивать. Senior должен знать модель памяти и полагаться только на documented happens-before. -
Верить, что добавление логов «чинит»
Принимать работу хайзенбага за исчезновение. Это опасная практика, баг остался.
Возможные дополнительные вопросы интервьюера
Как ты убедился, что race detector не ловит, и не было ли ошибки в его запуске?
Я написал минимальный воспроизводимый пример, запускал под go test -race намертво, смотрел вывод — предупреждения не было. Смотрел исходники race detector, чтобы понять ограничения.
Что ты вынес для себя из этого опыта?
Глубже изучил модель памяти Go, написал статью для команды. Стал всегда передавать значения, а не указатели в замыкания для Once.
Как ты выстраиваешь отношения с продакт-менеджерами
Краткий ответ (30–60 секунд)
Строю партнёрство на основе общего видения целей продукта и метрик. Стараюсь понять бизнес-контекст и язык PM. Регулярные 1:1, где я объясняю технические риски и предлагаю варианты решений, не диктуя. Помогаю PM понять «стоимость» фичи не только в деньгах, но в техдолге и операционной нагрузке. Всегда даю прозрачные оценки и early warnings.
Развёрнутый ответ
- Погружение в продукт: прошу PM рассказать о метриках, CJM, проблемах пользователей. Так я понимаю, почему фича важна, и могу предложить альтернативный, более простой технический вариант, дающий ту же ценность.
- Общение на языке бизнеса: не «нужен рефакторинг базы», а «инвестиция в 2 недели сейчас сократит time-to-market новых фич с 5 до 2 дней в будущем».
- Совместный процесс принятия решений: использую Opportunity Solution Tree — вместе выявляем узкие места.
- Прозрачность: если срок под угрозой, сообщаю сразу, а не в последний день. Предлагаю trade-off: сократить объем (MVP) или продлить.
- Празднование успехов: отмечаю запуски, благодарю PM за хорошие спецификации.
Под капотом (internals)
- Модель доверия: доверие = (надёжность + искренность + компетентность) / self-orientation. Чем меньше я думаю о своей выгоде, тем выше доверие.
- Когнитивный диссонанс PM: часто PM перегружены, и моя задача — снижать неопределённость, предоставляя чёткие опции и их последствия.
- Переговорные техники: BATNA, win-win, активное слушание.
Типичные ошибки кандидатов
-
Техническое высокомерие
«PM ничего не понимает». Это путь к конфликту. Senior должен быть переводчиком с технического на бизнес-язык. -
Критиковать без альтернативы
Говорить «это невозможно» и ждать. Всегда предлагать варианты: «Не можем сделать точно так к сроку, но можем упростить так». -
Соглашаться на всё
Не говорить о рисках, только бы не спорить. Это приводит к провалу и обвинениям. PM ценит, когда инженер предупреждает заранее.
Возможные дополнительные вопросы интервьюера
Как ты поступаешь, если PM настаивает на решении, которое технически вредно?
Привожу данные: например, время ответа ухудшится, потеряем пользователей. Предлагаю A/B тест. Если не помогает, эскалирую до EM/CTO с аргументами, но всегда сохраняя профессиональное уважение.
Как ты вовлекаешь PM в agile-процесс?
Приглашаю на демо, прошу участвовать в refinement, спрашиваю обратную связь по рабочему прототипу. Показываю метрики на продуктовом дашборде.
Как ты проводишь post-mortem после инцидента
flowchart LR
classDef entry fill:#1e3a5f,stroke:#38bdf8,stroke-width:2px,color:#f8fafc
classDef process fill:#1e293b,stroke:#38bdf8,stroke-width:1px,color:#f8fafc
classDef accent fill:#1e1b4b,stroke:#818cf8,stroke-width:1px,color:#f8fafc
classDef warning fill:#78350f,stroke:#fbbf24,stroke-width:1px,color:#f8fafc
classDef success fill:#064e3b,stroke:#34d399,stroke-width:1px,color:#f8fafc
P1["1. Хронология и Timeline"]:::entry --> P2["2. Анализ 5 Whys (Root Cause)"]:::process
P2 --> P3["3. Что сработало эффективно"]:::accent
P3 --> P4["4. Системные пробелы"]:::warning
P4 --> P5["5. Action Items с дедлайнами"]:::success
Краткий ответ (30–60 секунд)
Post-mortem провожу в blameless-стиле: собираю timeline, определяю корневую причину (5 why), выделяю contributing factors. Основной вопрос: «Как мы можем улучшить систему, чтобы подобное не повторилось?» Итог — action items с ответственными и дедлайнами. Документ публикуется для всей организации, чтобы учились на ошибках.
Развёрнутый ответ
Шаблон post-mortem:
- Краткое описание: что произошло, влияние на пользователей, длительность.
- Timeline: все события с UTC-метками (алерт, кто заметил, какие действия).
- Корневая причина (5 Why): например, «Почему упал сервис? — Кончилась память. Почему? — Утечка горутин. Почему? — Не закрывался HTTP-клиент. Почему? — В коде пропущен
defer resp.Body.Close(). Почему? — Линтер не был настроен на проверку bodyclose». - Что сработало хорошо: откатились быстро, алерт сработал, команда отреагировала.
- Что можно улучшить: автоматизировать проверку утечек.
- Action items:
- Добавить
bodycloseлинтер вgolangci-lint(owner @dev, срок спринт). - Написать интеграционный тест, симулирующий 100k запросов (owner @qa, неделя).
- Добавить
- Обсуждение: встреча, где мы не ищем виноватых, а обсуждаем, как повысить надёжность.
Под капотом (internals)
- Психология blameless: ошибки — следствие системных недостатков. Если наказывать, люди будут скрывать инциденты.
- Теория нормальных аварий: в сложной системе мелкие сбои неизбежны, задача — минимизировать влияние и учиться.
- Just Culture: различаю человеческую ошибку (приемлемо), халатность (недопустимо) и рискованные действия без согласования.
- Цикл PDCA (Plan-Do-Check-Act): post-mortem — часть непрерывного улучшения.
Типичные ошибки кандидатов
-
Поиск виноватого
«Это Иванов забыл закрыть соединение». Это убивает культуру. Вместо этого: «Почему процесс ревью пропустил?». -
Нет конкретных action items
«Надо быть аккуратнее». Расплывчатые цели не решают проблему. Только конкретные задачи с владельцами. -
Сокрытие деталей
Не публикуют, стесняясь. Прозрачность помогает всей компании не наступать на те же грабли.
Возможные дополнительные вопросы интервьюера
Как ты определяешь корректен ли post-mortem?
Проверяю, что action items выполнены, и инцидент не повторился. Через 3 месяца анализирую статистику инцидентов.
Приходилось ли тебе проводить post-mortem с высоким эмоциональным напряжением?
Да, когда инцидент затронул клиентов, был стресс. Напомнил правила: не обвинять, фокус на системе. Дал слово каждому, но блокировал переход на личности.
Какой твой подход к безопасности при разработке
Краткий ответ (30–60 секунд)
Безопасность интегрирую в SDLC (Shift Left): Threat Modeling на этапе дизайна, статический анализ (gosec, Snyk) в CI, ручные ревью на OWASP Top 10. Использую принцип наименьших привилегий, все секреты в Vault, обязательное шифрование в транзите и покое. Провожу penetration testing и red team упражнения. Обучаю команду основам security champion.
Развёрнутый ответ
Для Go-сервиса API:
- Дизайн: модель угроз по STRIDE, выявил риски инъекций, обхода аутентификации.
- Внедрение:
- Валидация входа: все данные пользователя проходят строгую типизацию и очистку, SQL через параметризованные запросы.
- Аутентификация/авторизация: JWT с RS256, короткое время жизни, refresh токены, RBAC.
- Секреты: всё в HashiCorp Vault, в CI — динамические секреты.
- TLS everywhere, mTLS между сервисами.
- Проверка в CI:
golangci-lintс security-линерами (gosec).- Snyk для сканирования зависимостей.
- Проверка на секреты в коде (gitleaks).
- Тестирование: фаззинг для эндпоинтов, пентест раз в квартал.
- Мониторинг: аномальные паттерны запросов, попытки взлома.
- Культура: провожу brown bag сессии по OWASP, поощряю сообщение об уязвимостях (bug bounty internal).
Под капотом (internals)
- OWASP ASVS: использую как чеклист требований.
- Криптография в Go: понимаю нюансы
crypto/randvsmath/rand, опасность утечек через time comparison, используюcrypto/subtle. - Memory safety: Go безопасен в плане переполнения буфера, но нужно следить за data races (могут привести к логическим уязвимостям).
- Defense in depth: несколько уровней защиты: сеть (WAF), аутентификация, бизнес-логика, мониторинг.
Типичные ошибки кандидатов
-
Безопасность как последний этап
«Перед релизом попросим безопасников посмотреть». Это дорого и неэффективно. Безопасность должна быть в каждом спринте. -
Пренебрежение зависимостями
Используют библиотеки без проверки CVE. Необходимо регулярное сканирование и обновление, а также минимализация зависимостей. -
Небезопасные настройки по умолчанию
Например, дебаг-режим в проде, пермиссивные CORS. Настраиваю безопасные дефолты, проверяю конфигурации в CI.
Возможные дополнительные вопросы интервьюера
Как ты обрабатываешь уязвимость Log4j-подобного типа в экосистеме Go?
Go не подвержен таким инъекциям так же легко, но слежу за уязвимостями в golang.org/x/net и т.п. Имею канал оповещений (Go vuln DB), мержу исправления в течение суток.
Как ты защищаешь межсервисное взаимодействие?
mTLS с короткоживущими сертификатами из Vault или cert-manager, плюс аутентификация на уровне приложения (JWT пробрасывается).
Был ли опыт работы с высоконагруженными системами > 10k rps
Краткий ответ (30–60 секунд)
Да, строил систему real-time bidding (RTB) на Go, обрабатывающую 50k запросов в секунду с p99 < 50мс. Достигалось это через шардирование по пользователям, in-memory кеши с zero-alloc парсингом protobuf, lock-free структуры данных и тщательный профилинг escape analysis. Горизонтальное масштабирование на десятках нод Kubernetes с HPA по CPU и кастомным метрикам.
Развёрнутый ответ
Ключевые техники:
- Allocation-free path: свой protobuf-парсер с использованием
unsafeдля чтения полей без аллокаций (после бенчмарков стандартный unmarshal создавал слишком много мусора). - In-memory cache: lock-free hash map (сегментированный
sync.Map), обновляемый от Kafka. - Сеть: gRPC с HTTP/2 multiplexing, кастомный пул соединений.
- Планирование горутин: использовали пул worker'ов с фиксированным числом горутин, чтобы не перегружать планировщик (хотя Go 1.22+ и GOMAXPROCS рулят).
- Оптимизация GC:
GOGC=200в сочетании сmemory ballast(в старых версиях), потом перешли наGOMEMLIMIT. - Наблюдаемость: tail-based sampling трейсов, lightweight метрики.
- Тестирование под нагрузкой: vegeta + специальный стенд с зеркалированием трафика.
Под капотом (internals)
- Планировщик Go: при 50k qps горутины создаются очень быстро, важно избегать blocking syscall в hot path. Использовали
epollчерез netpoller. - Escape analysis: анализировал
go build -gcflags="-m", чтобы убедиться, что данные на стеке. - Сборщик мусора: низкие аллокации давали GC паузы < 1мс.
- NUMA-aware: на высоких нагрузках привязывали поды к NUMA узлам через topology manager.
- Операционная система: тюнинг ядра (TCP keepalive, backlog), отключение swap.
Типичные ошибки кандидатов
-
Микрооптимизации без профилирования
«Я всё переписал наunsafe, но производительность не улучшилась». Любую оптимизацию начинать с pprof и бенчмарков. -
Игнорирование GC
Аллокации как конфетти, потом удивляются паузам. Понимание работы GC и limit'ов обязательно. -
Нет гранулярного масштабирования
Масштабируют монолитом, хотя можно вынести компоненты с разным профилем нагрузки.
Возможные дополнительные вопросы интервьюера
Как вы обеспечивали балансировку и справедливость между пользователями?
Использовали rate limiting по user_id на уровне шлюза, а воркеры обрабатывали очереди с приоритетами.
Какой самый большой сюрприз от Go в high load?
Задержки из-за остановки мира при growing stack в старых версиях (уже не актуально). Сейчас — contention на sync.RWMutex при частых чтениях.
Как ты обеспечиваешь, что твой код легко поддерживать
Краткий ответ (30–60 секунд)
Пишу так, будто поддерживать его будет незнакомый коллега в 3 часа ночи. Это означает понятные имена, небольшие функции, явные зависимости, минимум магии, high test coverage и актуальную документацию в godoc. Придерживаюсь стандартов команды и идиом Go. Код не требует телепатии.
Развёрнутый ответ
Подходы:
- Читаемость: комментирую «почему», а не «что». Разбиваю сложные условия на промежуточные булевы переменные с осмысленными названиями.
- Консистентность: если в проекте принято возвращать ошибки определённым образом, я не придумываю новый стиль.
- Тестируемость как документация: тесты показывают, как использовать модуль и какие граничные случаи есть.
- Изоляция: разделяю доменную логику и инфраструктурный код. Меняя БД, не трогаю бизнес-правила.
- Маленькие PR: легко ревьюить и понимать контекст.
- Clean Code, но без фанатизма: не создаю 10-уровневые абстракции ради гипотетического будущего.
- Инструменты:
go vet,staticcheck, линтеры на complexity.
Под капотом (internals)
- Закон Конвея: код отражает структуру коммуникаций, поэтому стремлюсь к low coupling и high cohesion.
- Когнитивная размерность: анализирую, сколько концептов нужно держать в голове, чтобы понять модуль.
- Запахи кода: регулярно рефакторю «feature envy», «long parameter list», «primitive obsession».
- Стандарты Go: effective Go и Uber Go style guide.
Типичные ошибки кандидатов
-
Самонадеянность
«Я помню, как работает». Через месяц не помнишь. Код должен быть самодокументируемым, с пояснениями неочевидных мест. -
Излишняя умность
Использование редких паттернов, требующих экспертизы. Простота — главное достоинство поддерживаемого кода. -
Отсутствие тестов
Рефакторинг без тестов — русская рулетка. Безопасный рефакторинг возможен только с покрытием.
Возможные дополнительные вопросы интервьюера
Как ты поступаешь с непонятным legacy кодом?
Покрываю его характеризационными тестами (characterization tests), чтобы зафиксировать текущее поведение, потом аккуратно рефакторю, не меняя контракт.
Как ты оцениваешь поддерживаемость чужого кода?
Смотрю на время, за которое я смог понять и внести небольшое изменение, и количество ругательств в минуту (WTF/min). Если высоко — код плох.
Как ты подходишь к работе в распределенной команде
Краткий ответ (30–60 секунд)
Работа в распределённой команде требует асинхронной коммуникации, переиндексации доверия и прозрачности. Использую письменные RFC для принятия решений, чётко документирую всё, делаю оверкоммуникацию. Стараюсь пересекаться на онлайн-митапах и неформальных встречах для поддержания социальных связей.
Развёрнутый ответ
С командой из 5 часовых поясов:
- Асинхронные стендапы: бот собирает статусы в Slack.
- Документация: все решения — в ADR, видео демо записываю с комментариями и выкладываю на внутренний YouTube.
- Рабочие часы: выделяю слоты, когда я доступен для созвонов, остальное время — deep work.
- Инструменты: Linear/Jira, Notion, Zoom.
- Культура: «no meeting Wednesdays», уважение к личному времени.
- Совместная работа: парное программирование по видеосвязи, разделяя экран.
- Эмпатия и терпение: учитываю культурные особенности.
Под капотом (internals)
- Теория media richness: для сложных обсуждений выбираю видео, для простых — чат.
- Основы remote-культуры (GitLab Handbook): всё должно быть письменно, single source of truth.
- Психология изоляции: борюсь с чувством одиночества через регулярные 1:1 и социальные звонки.
Типичные ошибки кандидатов
-
Синхронное мышление
Ждут, пока коллега проснётся, вместо того чтобы оставить сообщение. Нужно перестраивать процессы на асинхрон. -
Мало письменной коммуникации
Решают всё на созвонах без протоколов. На удалёнке критично документировать итоги. -
Игнорирование timezone overlap
Назначают встречи утром для другого. Использую инструменты учета таймзон.
Возможные дополнительные вопросы интервьюера
Как ты строишь доверие с коллегами, которых никогда не видел?
Выполняю обязательства, быстро отвечаю, признаю ошибки, проявляю интерес к ним как к людям через casual разговоры.
Какие инструменты обязательны для распределённой разработки?
Хорошая IDE/терминал для удалённой работы, система контроля версий, CI/CD, чат, видеосвязь, shared whiteboard.
Что для тебя важнее скорость разработки или качество
Краткий ответ (30–60 секунд)
Это ложная дихотомия. В долгосрочной перспективе качество порождает скорость. Но в стартапе на ранней стадии скорость итерации критична, и я могу допустить чуть больше технического долга, который зафиксирую и погашу сразу после валидации гипотезы. Мой подход — «качество, достаточное для контекста»: определяю минимальную планку качества (нет критических багов, basic observability, тесты на ключевые сценарии) и ниже неё не опускаюсь никогда.
Развёрнутый ответ
- Контекст имеет значение: для прототипа к демо инвесторов скорость важнее, заложим долг сознательно. Для платёжной системы качество на первом плане.
- Определяю качество метриками: test coverage > 60% на старте, линтеры, обязательное CI, code review. Это не «идеальное», а достаточное.
- Tracer bullets: реализую сквозной путь с минимальным качеством, чтобы быстро получить обратную связь от пользователя, а не пишу идеальный код в вакууме.
- Скорость без качества — это накопление техдолга, который вскоре остановит разработку. Поэтому даже в спешке не пропускаю обязательные вещи: контроль версий, автоматические тесты на критические пути, observability.
Под капотом (internals)
- Модель технического долга: приемлемый уровень долга зависит от стадии продукта.
- Lean принципы: минимизация потерь, поставляемая ценность. Идеальное невостребованное качество — потеря.
- Cost of Delay: если задержка в месяц стоит миллионы, а дефект качества — тысячи, решение очевидно.
- Definition of Done: фиксирует минимальный уровень качества, ниже которого нельзя.
Типичные ошибки кандидатов
-
Фундаментализм «качество всегда»
Затягивают доставку, бизнес теряет рынок. Надо понимать, когда «хорошо» достаточно, а не «идеально». -
«Потом пофиксим»
Непрерывно жертвуют качеством, не выделяя время на исправление. Долг растёт экспоненциально. Ответственный подход — фиксировать и планировать погашение. -
Не обсуждать компромисс с командой и PM
Принимают решение в одиночку. Это collaborative решение: вместе оцениваем риски.
Возможные дополнительные вопросы интервьюера
Как ты измеряешь качество?
Через баги в проде, время на hotfix, Churn, покрытие тестами, стабильность сборки, удовлетворённость разработчиков.
Что делать, если менеджер давит на скорость в ущерб качеству?
Показать график накопления дефектов и затрат на поддержку из прошлого. Предложить компромисс: MVP с сокращенным скоупом, но должным качеством.
Как бы ты спроектировал систему, если бы мог сделать это с нуля без ограничений
Краткий ответ (30–60 секунд)
Я бы построил полностью асинхронную событийно-ориентированную систему на основе Go, с event sourcing и CQRS, поверх глобально распределённого хранилища вроде Spanner/CockroachDB, чтобы не думать о шардировании. Однородные бинарники, деплоящиеся на serverless-подобную платформу (Kubernetes + Knative) с автоматическим масштабированием до нуля. Полная наблюдаемость, непрерывный chaos engineering, инфраструктура как код с верификацией. Но главное — чёткие границы bounded contexts, чтобы каждая часть могла развиваться независимо.
Развёрнутый ответ
Идеальная архитектура:
- Стек: Go для всех сервисов, gRPC для синхронных вызовов, NATS/Kafka для асинхронных событий.
- Данные: основное хранилище — CockroachDB (глобальная консистентность), агрегаты — event store, запросы — ElasticSearch денормализованные через CDC.
- Инфраструктура: Kubernetes с Crossplane, всё в GitOps (ArgoCD), мониторинг Prometheus + Thanos, логи Loki, трейсы Tempo.
- Безопасность: zero-trust, mTLS everywhere, динамические секреты Vault.
- Архитектурные принципы: каждая команда владеет доменом, API first, все изменения через RFC, fitness functions в CI.
Под капотом (internals)
- Паттерны распределённых систем: Outbox, Saga, Idempotency.
- CAP теорема: сознательно выбрал CP (CockroachDB) для финансовых данных, AP для менее критичных.
- Data Mesh: децентрализованное владение данными, самообслуживание.
- Evolutionary architecture: возможность замены частей без переписывания всего.
Типичные ошибки кандидатов
-
Фантазирование без оглядки на реальность
«Я бы не использовал Go, а написал свой язык». Показывает непонимание бизнеса. Идеальная система должна быть практичной. -
Переусложнение
Включают всё подряд, даже если не нужно. Настоящее мастерство — выбрать простейшее решение, удовлетворяющее требованиям. -
Игнорирование команды
Описывают систему, которую никто не сможет поддерживать. Архитектура должна соответствовать компетенциям.
Возможные дополнительные вопросы интервьюера
Почему именно Go, а не Rust/Kotlin?
Go даёт отличный баланс скорость разработки, производительность и простоту конкурентности, что важно для микросервисов. Rust дал бы больше безопасности памяти, но медленнее разработка.
Как бы ты мигрировал старую систему на эту?
Использовал бы Strangler Fig, постепенно заменяя компоненты и синхронизируя данные через CDC.
Как ты выбираешь стек технологий для нового проекта
Краткий ответ (30–60 секунд)
Выбираю стек, исходя из требований проекта, компетенций команды и долгосрочной поддержки. Создаю матрицу критериев (производительность, экосистема, найм, community, лицензия), ранжирую кандидатов. Провожу PoC для проверки рискованных гипотез. В Go-экосистеме предпочитаю стандартную библиотеку плюс проверенные инструменты (Gin/Chi для HTTP, protobuf для сериализации, NATS/Kafka), без лишней экзотики.
Развёрнутый ответ
Для нового сервиса обработки событий:
- Требования: высокая пропускная способность, низкая задержка, простой API, эксплуатация небольшой командой.
- Кандидаты: Go, Rust, Java.
- Критерии:
- Производительность (Go и Rust отлично, Java требует тюнинга).
- Время вывода на рынок (Go выигрывает за счёт простоты).
- Найм: Go-разработчики доступны, Rust сложнее.
- Экосистема: для Go — богатые библиотеки для микросервисов.
- PoC: написали прототип на Go и Rust. Rust показал меньшую память, но разработка заняла в 1.5 раза больше. Go выбрали, так как time-to-market приоритетнее.
- Детали стека: Go, chi router, gRPC, PostgreSQL, Redis, Prometheus, OpenTelemetry.
Под капотом (internals)
- Оценка TCO (Total Cost of Ownership): лицензии, облачные издержки, оплата труда, поддержка.
- Wardley Mapping: определение, какие компоненты являются commodity (используем готовое), а какие custom.
- Tech Radar: применяю практики ThoughtWorks для категоризации технологий.
- Будущая поддержка: смотрю частоту коммитов, число мейнтейнеров, adoption.
Типичные ошибки кандидатов
-
Выбор по хайпу
«Используем gRPC + Envoy + Istio + Temporal + Dapr». Каждая технология должна иметь чёткую причину быть. -
Игнорирование команды
Выбирают эзотерическую БД, которую никто не знает. Если нет времени учиться, проект провалится. -
Не проверять совместимость лицензий
Используют библиотеку с AGPL в проприетарном продукте.
Возможные дополнительные вопросы интервьюера
Как ты решаешь, когда стоит заменить существующий компонент в стеке?
Когда стоимость эксплуатации перевешивает стоимость миграции, либо технология перестаёт поддерживаться.
Кто принимает окончательное решение по стеку?
Обычно Architecture Review Board, но я готовлю рекомендацию и обоснование.
Расскажи о случае, когда тебе пришлось отказаться от любимого инструмента в пользу командного стандарта
Краткий ответ (30–60 секунд)
Я предпочитал Viper для конфигурации, но команда стандартизировалась на cleanenv. Мой подход был лучше для сложных структур, но аргументы команды — единообразие и знание всеми — перевесили. Я отказался от любимого инструмента, потому что консистентность кодовой базы важнее моего личного комфорта. Написал ADR и зафиксировали стандарт.
Развёрнутый ответ
- Ситуация: в команде из 10 Go-сервисов использовался
cleanenv. Я пришёл и предложилViperдля нового сервиса, потому что он поддерживает множественные источники и hot reload. - Конфликт: лид и команда возражали: «У нас уже всё на cleanenv, и мы знаем его косяки и обходы. Единый стандарт упрощает ротацию разработчиков».
- Решение: я провёл сравнение в виде RFC, показал преимущества Viper, но признал, что стоимость внедрения нового инструмента (обучение, поддержка, отличие от остальных сервисов) перевешивает. Согласился использовать
cleanenv, а потребность в hot reload решили через стандартный signal handling + перечитывание. - Результат: не создал зоопарк, команда осталась довольна, доверие ко мне выросло.
Под капотом (internals)
- Парадокс инструментов: сила инерции. Единообразие уменьшает когнитивную нагрузку при перемещении между сервисами.
- Культура «disagree and commit»: я открыто не согласился, но после принятия решения полностью его поддержал.
- Принцип командной собственности: код принадлежит команде, а не мне. Важнее коллективная эффективность.
Типичные ошибки кандидатов
-
Упрямство
«Я всё равно протащил свою библиотеку». Это подрывает стандарты и отношения. -
Эмоциональная привязанность
Защищают инструмент, как личную идентичность. Надо быть прагматиком, а не фанатом. -
Не поднимать вопрос стандартов
Полностью подавляют своё мнение. Нужно конструктивно предлагать улучшения, но признавать коллективный выбор.
Возможные дополнительные вопросы интервьюера
Что бы ты делал, если бы стандарт был откровенно плох?
Подготовил бы детальный анализ с цифрами (производительность, уязвимости) и предложил бы обсудить переход всем коллективом, возможно, с экспериментальным периодом.
Как ты сейчас принимаешь решение о введении новых инструментов?
Обсуждаю с командой необходимость, оцениваю влияние на единообразие, и только при консенсусе меняем стандарты.
Как ты оцениваешь производительность своего кода до того, как он попадет в продакшен
Краткий ответ (30–60 секунд)
Производительность оцениваю через бенчмарки (go test -bench), нагрузочное тестирование (vegeta/k6) на staging-окружении, профилирование (pprof) для поиска узких мест. Сравниваю с SLO и историческими данными. Для критичных путей провожу capacity planning: матмодель или симуляция.
Развёрнутый ответ
Процесс для нового эндпоинта:
- Микробенчмарки: пишу
Benchmarkфункции для ключевых функций. Используюgo test -benchmemдля отслеживания аллокаций. - Нагрузочное тестирование: деплою на staging (изолированный кластер), подаю ожидаемую нагрузку и чуть выше, смотрю latency перцентили, пропускную способность.
- Профилирование под нагрузкой: включаю pprof endpoint, снимаю CPU и heap профили, анализирую flamegraph. Ищу hot spots.
- Проверка лимитов: смотрю, упираюсь ли я в CPU, память, сеть, файловые дескрипторы.
- Анализ GC:
GODEBUG=gctrace=1для понимания пауз и частоты срабатывания. - Сравнение с SLO: если p99 < 50ms (при SLO 100ms) — хорошо.
- Canary: при раскатке на прод, сперва 1% трафика, анализ метрик.
Под капотом (internals)
- pprof:
runtime/pprof— CPU, heap, mutex, block, goroutine. Интерпретация top, list. - Трейсер рантайма:
go tool traceдля анализа latency горутин, GC, планировщика. - Flamegraph: визуализация стека вызовов.
- Escape analysis: смотрю, не убегают ли структуры в кучу без необходимости.
- Memory bandwidth: на очень высоких нагрузках профилирую с
perfдля cache misses.
Типичные ошибки кандидатов
-
Полагаться только на бенчмарки
Микробенчмарки не показывают взаимодействие компонентов. Необходимо интеграционное нагрузочное тестирование. -
Игнорировать GC
Смотрят только на время CPU, но не на задержки GC. Латентность может быть незаметна в среднем, но убивать 99-й перцентиль. -
Не профилировать с реалистичными данными
Гоняют тесты на пустых ответах. Данные должны соответствовать продакшену, иначе аллокации и ветвления другие.
Возможные дополнительные вопросы интервьюера
Как ты определяешь capacity?
Строю зависимость latency от rps на staging, нахожу точку перегиба, добавляю запас 30%.
Что делать, если производительности не хватает, а дедлайн завтра?
Ищу quick wins: отключить неиспользуемые middleware, увеличить пул соединений, вертикально скейлировать под, включить кеш, если ещё нет.
Как ты работаешь с обратной связью, особенно критической
Краткий ответ (30–60 секунд)
Воспринимаю критику как подарок. Стараюсь не переходить в защитную реакцию: выслушиваю полностью, благодарю, задаю уточняющие вопросы, чтобы понять конкретные примеры. Затем анализирую и составляю план действий. Отделяю эмоции от фактов. Если критика кажется несправедливой, прошу время подумать и возвращаюсь к разговору позже с фактами, а не оправданиями.
Развёрнутый ответ
Пример: на ревью коллега жёстко раскритиковал мой дизайн API, назвав его «не интуитивным и опасным».
- Реакция: подавил желание защищаться, поблагодарил за детали.
- Уточнил: попросил показать, где именно не интуитивно, какие риски видит.
- Понял: оказывается, мой API допускал неоднозначную интерпретацию параметра, что могло привести к двойному списанию.
- Применил: предложил исправленный контракт, обсудил с коллегой, он одобрил.
- Ретроспектива: отметил, что из-за спешки недостаточно подумал о UX API. Ввёл для себя обязательный шаг «ревью дизайна API» у двух коллег перед реализацией.
Под капотом (internals)
- Принципы ассертивности: разделять факты, интерпретации, чувства.
- Когнитивная защита: понимаю, что включается amygdala hijack. Делаю паузу.
- Growth mindset (Кэрол Дуэк): ошибки — возможность для роста.
- Radical Candor (Ким Скотт): ценю прямое указание на недостатки, потому что это проявление заботы.
Типичные ошибки кандидатов
-
Отрицание или агрессия
«Ты просто не понимаешь моего кода». Это разрушает репутацию. Senior открыт к критике. -
Притворное согласие без изменений
«Спасибо, я учту», но не меняют поведение. Это заметно и подрывает доверие. -
Принимать всё на свой счёт
Код != личность. Отделять себя от работы, иначе каждая критика будет ранить.
Возможные дополнительные вопросы интервьюера
Как ты даёшь критическую обратную связь?
Использую SBI (Situation-Behavior-Impact): «На встрече (S) ты перебивал коллегу (B), из-за чего он замолчал и мы потеряли его идеи (I). Как думаешь?»
Что делать, если критика неконструктивна?
Спросить: «Можешь привести конкретный пример и как, по-твоему, лучше сделать?» Если наезд продолжается, обратиться к менеджеру за модерацией.
Опиши идеальный для тебя процесс CI/CD
Краткий ответ (30–60 секунд)
Идеальный CI/CD — это полностью автоматизированный пайплайн от коммита до продакшена с минимальным ручным вмешательством, но с качественными воротами. Триггер — push в ветку. Этапы: линтинг, секреты, юнит/интеграционные тесты, сборка контейнера, деплой на staging, дымовые тесты, затем canary, автоматическое сравнение метрик и либо откат, либо продвижение на прод. Всё конфигурация как код, наблюдаемо, с уведомлениями.
Развёрнутый ответ
- Source: Git, trunk-based development, feature flags.
- CI (Continuous Integration):
- Pre-commit хуки (базовый линтинг), но основное в CI.
golangci-lint,go vet,staticcheck.- Unit tests, race tests.
- Сборка
go build, потом Docker build (multi-stage). - Сканирование уязвимостей (Trivy, Snyk).
- Публикация образа в регистр с тэгом коммита.
- CD (Continuous Delivery/Deployment):
- GitOps (ArgoCD) следит за репозиторием манифестов.
- Автоматический деплой на staging.
- Integration/e2e smoke тесты.
- Ручной промоушн на прод (если не хотим полный CD), затем canary 5% → 100% с автоматическим анализом (Prometheus metrics) и откатом при ошибках.
- Observability: дашборд CI/CD, DORA метрики.
Под капотом (internals)
- Теория CI/CD: чем быстрее обратная связь, тем качественнее продукт.
- Progressive delivery: Argo Rollouts, Flagger.
- Immutable infrastructure: контейнеры, не меняем на ходу.
- Supply chain security: SBOM, Cosign подпись контейнеров.
Типичные ошибки кандидатов
-
Долгий CI
Пайплайн на 30 минут. Нужно параллелить, кешировать зависимости, оптимизировать. -
Нет автоматического отката
Надеются на ручное обнаружение. Система должна сама понять по SLO и откатить. -
Ручные шаги в деплое
«Я билжу на своей машине». Невоспроизводимость, риск. Сборка только в CI.
Возможные дополнительные вопросы интервьюера
Как ты обеспечиваешь безопасность пайплайна?
Минимальные привилегии для CI-сервисной учётки, изоляция сред, проверка секретов, неизменяемые образы, подписанные коммиты.
Как ты внедрял GitOps в существующую команду?
Провёл воркшоп по ArgoCD, начал с одного не критичного сервиса, показал, как работает автосинхронизация и откат, потом внедрили на все.
Как ты работаешь с "легаси" кодом
Краткий ответ (30–60 секунд)
С легаси работаю, как с минным полем: сначала покрываю характеризационными тестами (characterization tests), чтобы зафиксировать текущее поведение. Затем выполняю серию безопасных рефакторингов (выделение методов, введение интерфейсов, устранение глобального состояния), не меняя контракт. Постепенно вычленяю модуль в микросервис/новый пакет, когда это оправдано.
Развёрнутый ответ
Пример: монолитный Java-сервис, который нужно частично перенести в Go.
- Изучение: чтение кода и тестов (их почти нет).
- Инструментарий: добавляю логирование и метрики для понимания фактического поведения.
- Характеризационные тесты: пишу интеграционные тесты, которые пропускают запросы через весь стек и сохраняют ответы (золотые файлы).
- Рефакторинг: отделяю нужную логику в отдельный пакет/класс, навожу мосты через интерфейс.
- Стратегия Strangler Fig: новый Go-сервис обрабатывает вызов, старый вызывается как fallback или для справочных данных.
- Удаление: когда трафик полностью переключён, старый код удаляется.
Под капотом (internals)
- Теория работающего с легаси (Майкл Физерс): код без тестов — легаси. Добавление тестов — первый шаг.
- Spout & Span analysis: анализ зависимостей.
- Психология неприязни к легаси: объясняю команде, что это просто код, написанный в других условиях, а не чья-то глупость.
- Правило бойскаута: каждое прикосновение должно делать код чуть лучше.
Типичные ошибки кандидатов
-
Большой рефакторинг «всё сломаю и перепишу»
Это риск полного паралича. Переписывать нужно постепенно, с возможностью отката. -
Презрительное отношение
«Кто этот ужас писал?» Это нарушает командную культуру. Автор мог быть умным человеком в ограниченных обстоятельствах. -
Не добавлять тесты
Меняют код, надеясь, что ничего не сломается. Без характеризационных тестов вы вносите регрессии.
Возможные дополнительные вопросы интервьюера
С чего ты начинаешь знакомство с большим легаси-проектом?
Запускаю локально, прогоняю основные сценарии, ищу документацию, читаю тесты. Делаю заметки, рисую C4 диаграмму.
Как решаешь, что пора удалять старый код?
Когда метрики показывают отсутствие трафика на старый код в течение достаточного времени (например, неделя), и все зависитмости от него убраны.
Что такое "архитектурное решение" ADR и зачем оно нужно
Краткий ответ (30–60 секунд)
ADR (Architecture Decision Record) — это документ, фиксирующий принятое архитектурное решение, контекст, рассмотренные альтернативы и последствия. Нужен, чтобы через полгода/год команда понимала, почему система такая, и не повторяла анализ. Это основа эволюционной архитектуры и знания.
Развёрнутый ответ
Структура ADR:
- Номер и заголовок: ADR-001 Выбор БД.
- Статус: Proposed, Accepted, Superseded.
- Контекст: какая была проблема.
- Решение: что мы выбрали и почему.
- Альтернативы: что рассматривали и почему отвергли.
- Последствия: что стало проще, что сложнее, риски.
Хранятся в репозитории рядом с кодом в docs/adr/.
Пример: ADR-003 «Использование gRPC для внутреннего взаимодействия». Благодаря ему новый разработчик через год не предлагает перейти на REST без понимания причин выбора.
Под капотом (internals)
- Эволюционная архитектура (Building Evolutionary Architectures): ADR позволяет управлять изменением.
- Память организации: предотвращает institutional forgetting.
- Инструментарий:
adr-toolsдля создания.
Типичные ошибки кандидатов
-
Не писать ADR
Думают, что и так запомнят. Через месяц контекст теряется. -
Писать слишком подробно
Трактат на 10 страниц никто не прочтёт. Краткость, чёткий контекст. -
Не обновлять статус
Не помечают Superseded. Нарушается актуальность.
Возможные дополнительные вопросы интервьюера
Как вы обеспечиваете, что команда следует ADR?
Включаю ссылки на ADR в PR и код, иногда добавляю fitness functions, проверяющие соответствие.
Что делать, если решение нужно отменить?
Создаю новый ADR со статусом «Supersedes ADR-NNN» и объясняю, что изменилось в контексте.
Как ты обеспечиваешь консистентность кодовой базы в большой команде
Краткий ответ (30–60 секунд)
Через автоматизацию и стандарты: единый golangci-lint конфиг, Uber Go style guide как baseline, кодогенерация для шаблонного кода, архитектурные линтеры (go-arch), CODEOWNERS и обязательное CR. Провожу регулярные рефакторинги для выравнивания стиля, провожу internal open source (внутренние библиотеки).
Развёрнутый ответ
В команде из 30 Go-разработчиков:
- Линтеры и форматеры:
gofumpt,goimports,golangci-lintс жёстким конфигом. В CI — блокирующий шаг. - Общие библиотеки: выделили core-команду, которая развивает внутренний фреймворк для типовых задач (логирование, конфигурация, HTTP-сервер). Все сервисы используют его.
- Шаблоны:
gonewили cookiecutter для создания структуры нового сервиса. - Code Review: обязательное, с фокусом на консистентность. Использую
reviewdogдля автоматического комментирования. - Архитектурный надзор:
go-archlint для проверки, что зависимости между пакетами не нарушают договорённости. - Документация: ADR и style guide в репозитории.
- Обучение: onboarding с объяснением, почему так, а не иначе.
Под капотом (internals)
- Конвенции важнее конфигураций: принцип Rails.
- Теория сломанных окон: быстро исправляю отступления от стиля, чтобы не расползались.
- Психология ownership: когда команда сама вырабатывает стандарты, она их и соблюдает.
Типичные ошибки кандидатов
-
Только устные договорённости
«Мы так договорились на встрече». Нужны записанные правила и автоматические проверки. -
Излишняя жёсткость
Блокируют любой нестандартный подход без обсуждения. Иногда стоит обновить стандарт, если есть обоснование. -
Устаревшие стандарты
Не пересматривают style guide годами. Надо раз в квартал проводить ретроспективу.
Возможные дополнительные вопросы интервьюера
Как ты поступаешь, если разработчик систематически игнорирует стандарты?
Сначала 1:1 беседа, выяснение причин (может, стандарт неудобен). Если продолжается — эскалирую до тимлида, т.к. это вредит команде.
Как вы синхронизируете изменения standards?
Через RFC и встречи лидов, после принятия — PR в style guide.
Как ты объясняешь сложные технические концепции нетехническим стейкхолдерам
Краткий ответ (30–60 секунд)
Использую аналогии и визуализации, связываю технические концепции с бизнес-результатами. Говорю на языке выгод и рисков, а не технологий. Например, не «внедряем Kafka», а «создаём систему гарантированной доставки сообщений, чтобы заказы не терялись при пиковых нагрузках, что сэкономит до 100к убытков в месяц».
Развёрнутый ответ
- Знай аудиторию: для CEO — деньги и сроки, для PM — влияние на клиентов и roadmap.
- Аналогии: «Микросервисы — это как команды в ресторане: официант, повар, бармен работают независимо, и ошибка на кухне не останавливает разлив напитков».
- Визуализация: диаграммы потоков данных, графики latency vs нагрузки.
- Избегаю жаргона, заменяю на понятные термины (пентест = проверка защиты).
- Истории: «Представьте, Black Friday, 1000 заказов в секунду. Наша новая архитектура выдержит без тормозов».
- Готовлюсь: перед встречей продумываю ключевые сообщения.
Под капотом (internals)
- Модель ментальных представлений: стейкхолдеры видят систему упрощённо, я подстраиваюсь.
- Теория перевода (латентное значение): перевожу с технического на бизнес-язык без потери сути.
- Storytelling: факты, завёрнутые в историю, запоминаются в 12 раз лучше.
Типичные ошибки кандидатов
-
Уход в дебри
«Там используется 2-phase commit с оптимизацией read repair». Глаза стекленеют. Говорите о результате. -
Снисходительный тон
«Это сложно, вы не поймёте». Оскорбительно. Всё можно объяснить доступно. -
Нет визуализации
Только слова. Набросок на доске ускоряет понимание в разы.
Возможные дополнительные вопросы интервьюера
Как ты объяснишь, зачем нам Kubernetes, если мы просто хостим сайт?
«Kubernetes автоматически перезапустит сайт при сбое, добавит мощности при наплыве посетителей и сэкономит нам деньги на серверах, потому что мы не держим простаивающий резерв».
Приходилось ли тебе готовить презентацию для совета директоров?
Да, готовил презентацию по бюджету на миграцию. Фокус на ROI, сроках окупаемости, рисках и что будет, если не сделать. Никакого кода.
Расскажи о твоем опыте проектирования API и взаимодействия с другими командами
Краткий ответ (30–60 секунд)
Проектирую API First. Пишу Protobuf (для внутренних) или OpenAPI (для внешних) спецификацию, делюсь с потребителями до реализации, собираю фидбек. Использую принцип «robustness principle»: моё API консервативно в том, что отправляет, и либерально в том, что принимает, но с жёсткой валидацией. Для взаимодействия — назначаю API review с заинтересованными командами, провожу ранние интеграционные тесты.
Развёрнутый ответ
Проект: публичный API для партнёров.
- Старт: определили ресурсы, эндпоинты, аутентификацию. Оформили в OpenAPI 3.0.
- Обсуждение: разослали черновик командам партнёров, провели встречу, собрали требования (например, им нужен был webhook вместо polling).
- Итерация: переработали, учли webhook, пагинацию, формат ошибок (RFC 7807).
- Версионирование: решили следовать URL-based v1/v2, с обратной совместимостью.
- Документация: автоматически генерируем портал из OpenAPI, с примерами на Go, Python.
- Взаимодействие: проводим «API office hours», где партнёры могут задать вопросы, я или кто-то из команды отвечает.
Под капотом (internals)
- Postel's Law: как применяется в API дизайне.
- Семантическое версионирование: мажорные изменения — новая версия.
- Психология API потребителя: разработчик, использующий мой API — мой клиент. Удобство превыше всего.
- gRPC vs REST: для внутренних сервисов gRPC с явной схемой и генерацией.
Типичные ошибки кандидатов
-
Проектирование в изоляции
«Мы сделали API, а потом сказали другим пользоваться». Получается неудобный для потребителя контракт. Обязательно включать их в процесс. -
Пренебрежение версионированием
«Мы всегда можем изменить, это же наши клиенты». Ломание обратной совместимости убивает доверие. -
Нестандартные ошибки
HTTP 200 с телом «error». Использовать правильные коды и Problem Details.
Возможные дополнительные вопросы интервьюера
Как ты тестируешь интеграцию API между командами?
Проводим контрактное тестирование (Pact) и регулярные интеграционные тесты в общем CI, где поднимаются оба сервиса.
Как решаешь конфликт требований двух команд-потребителей одного API?
Пытаюсь найти обобщённое решение, покрывающее оба кейса, но не усложняющее без необходимости. Если нет — эскалирую до владельцев продукта для определения приоритета.
Как ты подходишь к выбору между микросервисами и монолитом
Краткий ответ (30–60 секунд)
Стартую с модульного монолита — он даёт простоту развёртывания и рефакторинга на старте. Переход к микросервисам обосновываю тогда, когда появляются разные темпы изменений модулей, независимые требования к масштабированию или технологическому разнообразию, либо когда команда растёт и нужно разделять зоны ответственности. Решение принимаю на основе оценки текущих болей и прогнозируемого роста.
Развёрнутый ответ
- Монолит сначала: в проекте от 2 до 5 разработчиков монолит выигрывает по скорости разработки и простоте. Я разделяю его на модули (пакеты в Go) с чёткими границами.
- Сигналы к декомпозиции:
- Разные SLO у функций (поиск vs платежи).
- Разные циклы релизов (одна команда хочет деплоить чаще).
- Необходимость независимого масштабирования.
- Рост команды > 10, когда в одном репозитории начинаются конфликты и проблемы с владением.
- Миграция: извлекаю модуль в сервис по шаблону Strangler Fig, налаживаю API, затем вырезаю из монолита.
- Никогда не начинаю с микросервисов, если нет организационной потребности (разные команды) или особых требований к масштабированию.
Под капотом (internals)
- Закон Конвея: архитектура отражает структуру организации. Если команды не разделены, микросервисы создают лишнюю сложность.
- Распределённые системы: каждый микросервис — это распределённая система со своими проблемами (сеть, частичные отказы).
- MonolithFirst (Мартин Фаулер): итеративный подход.
Типичные ошибки кандидатов
-
Микросервисы ради моды
«Все делают микросервисы, и мы так же». Без понимания зачем, это дорого. -
Слишком позднее разделение
Монолит превратился в большой ком грязи, но боятся тронуть. Нужно рефакторить постоянно, выделяя модули, даже не вынося в отдельный сервис. -
Наносервисы
Каждая функция — отдельный сервис. Слишком много сетевых вызовов и overhead.
Возможные дополнительные вопросы интервьюера
Как ты перестраивал монолит в микросервисы без остановки поставки?
Через Strangler Fig: постепенно заменял функционал, используя feature flags и параллельный запуск.
Что такое модульный монолит на Go, как ты его делаешь?
Использую разделение на пакеты по bounded context, с интерфейсами на границах, запрещаю прямые импорты из других контекстов (линтер).
Какова твоя роль в инцидент-менеджменте
Краткий ответ (30–60 секунд)
Как старший инженер, я либо Incident Commander (IC), либо subject matter expert. Моя задача: стабилизировать систему (откат, масштабирование, фича-флаг), а не искать root cause. Слежу за таймлайном, коммуницирую статус заинтересованным лицам. После инцидента веду post-mortem. В спокойное время работаю над снижением вероятности и влияния инцидентов через улучшение наблюдаемости и runbook-ов.
Развёрнутый ответ
- До инцидента: пишу runbook, участвую в учениях, настраиваю алерты (SLO based).
- Во время инцидента:
- Если IC: объявляю роли, запускаю канал связи, слежу за временем, принимаю решение об эскалации/откате.
- Если эксперт: помогаю с диагностикой, предлагаю mitigation.
- Важно: не тушить героически в одиночку, а координировать.
- После: blameless post-mortem, добавляю action items, проверяю их выполнение.
- Непрерывное улучшение: анализ трендов инцидентов, внесение исправлений в архитектуру.
Под капотом (internals)
- SRE практики (Google): принципы управления инцидентами.
- Командная структура: четкое разделение ролей (IC, Operations Lead, Communications Lead).
- Психология стресса: тренировки (game days) снижают панику.
Типичные ошибки кандидатов
-
Сразу искать причину
Вместо стабилизации. MTTR – критично. Сначала восстановить сервис. -
Работать без чёткой роли
Геройство создаёт суматоху. Необходимо назначить IC. -
Игнорировать коммуникацию
Заказчики не знают, что происходит. Статусы каждые 15 минут.
Возможные дополнительные вопросы интервьюера
Как ты проводишь учения?
Инжектирую отказы в staging через Chaos Mesh, даю команде задачу восстановить сервис, засекаем время и улучшаем runbook.
Как ты решал, когда эскалировать инцидент?
Если инцидент длится >30 мин или затрагивает критичный бизнес-процесс, и мы не имеем прогресса, зову старшего дежурного или менеджера.
Как ты справляешься с "выгоранием" burnout и помогаешь справляться другим
Краткий ответ (30–60 секунд)
Распознаю выгорание по ранним признакам: цинизм, хроническая усталость, снижение продуктивности. Для себя: строгие границы рабочего времени, физическая активность, хобби, цифровой детокс. Для команды: создаю среду, где можно открыто говорить о нагрузке, защищаю от переработок, слежу за WIP и праздную победы. Если вижу симптомы у коллеги — провожу заботливый 1:1, предлагаю помощь, могу рекомендовать обратиться к специалисту.
Развёрнутый ответ
- Профилактика для себя: планирую отпуск каждые 3 месяца, не проверяю почту после 19:00, медитирую, занимаюсь бегом.
- Распознавание у других: замечаю, что разработчик стал раздражительным, безразличным к качеству, часто берёт больничные.
- Действия как лида:
- Конфиденциальная беседа без давления: «Я заметил, ты выглядишь уставшим, как ты себя чувствуешь?»
- Снижаю давление: пересматриваю приоритеты, переношу дедлайн, если возможно.
- Переключаю на более интересную задачу или обучение.
- Убеждаю брать отгулы, не дожидаясь срыва.
- Культура: «команда не герои», работа без overtime — признак зрелости.
Под капотом (internals)
- Три компонента выгорания (Маслах): эмоциональное истощение, деперсонализация, редукция личных достижений.
- Требования JD-R модели: ресурсы (поддержка, автономия) должны превышать требования.
- Self-care: фундамент продуктивности.
Типичные ошибки кандидатов
-
Романтизация переработок
«Я работал по 14 часов, чтобы спасти проект». Это приводит к выгоранию и ошибкам. Senior ценит устойчивость. -
Игнорирование признаков у коллег
«Он сам справится». Иногда человеку нужна инициация помощи извне. -
Нет границ
Доступен 24/7. Учит команду, что вас можно дёргать всегда, создаёт культуру срочности.
Возможные дополнительные вопросы интервьюера
Что делать, если менеджмент сам создаёт burnout культуру?
Обсуждаю с EM/C-level на языке данных: снижение качества, текучка, затраты на найм, потери от инцидентов из-за усталости.
Как ты восстанавливался после собственного выгорания?
Признал проблему, взял отпуск, пересмотрел нагрузку, сменил проект на менее стрессовый. Сейчас я vigilante к первым признакам.
Как ты организуешь процесс "knowledge sharing" в команде
Краткий ответ (30–60 секунд)
Организую культуру «учимся вместе»: регулярные тех-толки (Brown Bag), парное программирование, обязательное документирование архитектурных решений (ADR), менторство и code review как обучающий инструмент. Создал внутренний портал с runbook’ами, записями воркшопов и Kb. Каждый член команды должен вести минимум один доклад в квартал.
Развёрнутый ответ
В команде из 20 инженеров:
- Внутренние митапы: раз в 2 недели, темы выбираем голосованием (Go internals, gRPC, Kafka). Обязательно записываем.
- Code review with learning: ревьювер объясняет не только «что плохо», но и «как можно лучше», ссылается на первоисточники.
- Парное программирование: особенно для сложных задач или новых областей.
- Writing culture: поощряю писать статьи во внутреннюю базу (Notion/Confluence/Hugo) за вознаграждение.
- Onboarding: у каждого новичка есть ментор и структурированный план изучения сервисов и инструментов.
- Распространение экспертизы: если кто-то становится single point of failure, его задача — обучить минимум двух коллег.
Под капотом (internals)
- Кривая обучения команды: shared knowledge растёт экспоненциально при правильной культуре.
- Принцип Эджертона: learning organization.
- Социальное доказательство: когда лидеры делятся, остальные подтягиваются.
Типичные ошибки кандидатов
-
Хранить знания в головах
«Я и так знаю, зачем писать». Bus factor = 1. Это риск для проекта. -
Формальные скучные лекции
Никто не приходит. Нужно интерактивно, практично, с едой. -
Не давать время
Требовать knowledge sharing, но грузить тасками. Выделяю рабочее время для этого.
Возможные дополнительные вопросы интервьюера
Как ты оцениваешь эффективность knowledge sharing?
Через onboarding time новых сотрудников, уменьшение числа вопросов «как это работает?», метрики участия в митапах.
Как бороться с «knowledge hoarding»?
Через performance review включать пункт «sharing», поощрять публично тех, кто делится, и создавать систему, где выгодно обучать (например, дежурить меньше).