> Что интересного вы делали и чему научились на ошибках (Go)
Уровень: middle · Роль: backend · Категория: Технические вопросы
Компании: Автомакон
Стек: Go
> Пример ответа
Короткий ответ
Расскажу про проект, где я переписывал legacy-сервис на Go. Основная ошибка была в том, что я сразу начал оптимизировать горячий путь, не измерив профиль. В итоге потратил время на микрооптимизации, а реальная проблема оказалась в N+1 запросах к БД. Научился всегда начинать с profiling и pprof, а не с предположений.
Подробное объяснение
В одном из сервисов, отвечающем за агрегацию данных, был высокий latency на чтение. Я решил, что проблема в аллокациях и сложности алгоритма, и начал переписывать хот-пат через sync.Pool и ручное управление буферами. Через неделю работы стало понятно, что выигрыш минимален - 3-5%. Тогда я запустил pprof и увидел, что 70% времени уходит на блокировки при обращении к PostgreSQL из-за отсутствия индексов и лишних JOIN.
Из этой ошибки я вынес несколько принципов:
- сначала профилируй, потом оптимизируй;
- не доверяй интуиции о "медленном коде";
- проверяй интеграции с БД и внешними системами до внутренних оптимизаций.
Второй случай - это работа с graceful shutdown. Я не обрабатывал сигналы корректно, и при деплое терялись in-flight запросы. Научился использовать context.WithTimeout и errgroup для координации завершения воркеров.
На практике
Сейчас в новых задачах я всегда начинаю с написания бенчмарков и профилирования, если есть подозрение на производительность. Для БД - включаю логирование медленных запросов и смотрю explain. Для graceful shutdown - пишу тесты, которые эмулируют SIGTERM и проверяют, что все запросы завершились.
Также я стал больше внимания уделять code review: если вижу, что коллега оптимизирует без измерений, предлагаю сначала собрать метрики.
Пример кода
Пример того, как я теперь делаю graceful shutdown с errgroup:
GOfunc main() {ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)defer stop()g, gCtx := errgroup.WithContext(ctx)g.Go(func() error {return runHTTPServer(gCtx)})g.Go(func() error {return runWorker(gCtx)})if err := g.Wait(); err != nil {log.Printf("shutdown: %v", err)}}
Как отвечать на собеседовании
Структурируйте ответ по схеме: ситуация - действие - результат - вывод. Назовите конкретную ошибку, объясните, как вы её нашли (профилирование, логи, метрики), что изменили и какой эффект получили. Если ошибка была в архитектуре, расскажите, как перепроектировали. Важно показать, что вы умеете анализировать свои действия и не повторяете их.
Что проверяет интервьюер
Интервьюер оценивает:
- способность к рефлексии и признанию ошибок;
- инженерный подход: измерение, гипотезы, проверка;
- знание инструментов: pprof, tracing, метрики;
- умение рассказывать о trade-off и последствиях решений.
Типичные ошибки
- Рассказывать про ошибку без конкретики: "было плохо, стало хорошо".
- Сваливать вину на других или на внешние факторы.
- Называть ошибкой то, что на самом деле было осознанным решением.
- Не показывать, что вы сделали выводы и изменили процесс работы.
> Похожие задачи по backend
В чем разница между EXPLAIN и EXPLAIN ANALYZE
Какой опыт работы с Kubernetes и какие задачи выполнял
Какова текущая команда и сколько человек в ней
Расскажите про опыт работы с базами данных и используемые СУБД
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью