RecallDeck
Направление

Подготовка к собеседованию — Go-разработчик

Колода из 333+ карточек с вопросами для собеседования по направлению «Go-разработчик» — по темам и уровню сложности, с возвратом ровно перед тем, как вы забудете. Посмотрите несколько карточек ниже, затем выберите доступ, чтобы учить всё направление по расписанию в стиле Anki (SM-2).

333 карточки19 тем
Посмотреть цены и начать

7 дней бесплатно на месяц или год · все функции включены.

Что внутри

Все темы направления, сгруппированные так, как вы будете их учить.

Основы языка: слайсы, мапы и строки

15 карточек
Слайсы, мапы и строки

Интерфейсы и система типов

6 карточек
Интерфейсы и типы

Горутины, каналы и select

12 карточек
Горутины и каналы

sync, atomic и context

12 карточек
sync и context

Планировщик, GC и память

8 карточек
Рантайм и память

Ошибки, defer и panic

7 карточек
Ошибки и defer

Паттерны конкурентности (live-coding)

8 карточек
Паттерны конкурентности

Тестирование, тулинг и дженерики

7 карточек
Тесты и тулинг

Распределённые системы

12 карточек
Распределённые системы

Kafka и очереди

12 карточек
Kafka и очереди

Кэширование вглубь

10 карточек
Кэширование

Производительность и конкурентность

11 карточек
Производительность

Надёжность и инциденты

10 карточек
Надёжность и инциденты

Базы данных

104 карточки
Основы SQLВнутренности Postgres и оптимизацияNoSQL и Redis

DevOps и инфраструктура

35 карточек
Docker, CI/CD и Linux

Системный дизайн

29 карточек
Системный дизайн

Поведенческое интервью

35 карточек
Поведенческое интервью

Примеры вопросов

Несколько карточек из колоды — откройте ответ, затем выберите доступ, чтобы учить весь набор по расписанию.

Чем слайс отличается от массива и как слайс устроен под капотом?

Короткий ответ: Массив — это value-тип фиксированного размера, причём размер зашит в сам тип ([3]int и [4]int — разные типы), и он копируется целиком при присваивании и передаче. Слайс — это лёгкий дескриптор поверх массива: заголовок из трёх полей {указатель на backing array, len, cap}. Копируется только заголовок, данные остаются общими.

Подробно:

  1. Массив[N]T, длина — часть типа, данные лежат единым непрерывным блоком прямо по месту объявления (в стеке, структуре или куче) и копируются побайтово. Передал в функцию — получил копию всех элементов.
  2. Слайс[]T, три машинных слова: ptr на элемент backing array, len (сколько видно) и cap (сколько влезет до реаллокации).
  3. Срезarr[1:3] не копирует данные, а строит новый заголовок, указывающий внутрь того же массива.
s := arr[1:3]

  slice header          backing array [5]int
 ┌──────────┐          ┌───┬───┬───┬───┬───┐
 │ ptr  ────┼────────► │ 0 │ 1 │ 2 │ 3 │ 4 │
 │ len = 2  │              ▲       ▲
 │ cap = 4  │              └─ ptr  └─ len
 └──────────┘

⚠️ Частая ошибка: думать, что s2 := s1 даёт независимую копию. Копируется только 24-байтовый заголовок — оба слайса смотрят в один и тот же backing array, и запись s2[0] = x видна через s1.

Как в Go реализован полиморфизм без классов и наследования?

Короткий ответ: Полиморфизм даёт неявная (структурная) реализация интерфейсов: тип удовлетворяет интерфейсу автоматически, если у него есть нужный набор методов — никакого implements. Вместо наследования — композиция через встраивание (embedding), а инкапсуляция — регистром первой буквы имени.

Подробно:

  1. Структурная типизация (duck typing) — «если крякает как утка». Тип и интерфейс нигде явно не связывают; связь проверяется по сигнатурам методов на этапе компиляции.
  2. Композиция вместо наследования — встраивание продвигает методы встроенного типа наружу, но это has-a, а не is-a.
  3. Инкапсуляция — имя с заглавной буквы экспортируется, со строчной — приватно внутри пакета.
type Stringer interface{ String() string }

type Point struct{ X, Y int }

func (p Point) String() string { // Point реализует Stringer
    return fmt.Sprintf("(%d,%d)", p.X, p.Y)
} // без "implements Stringer" — достаточно совпадения метода

⚠️ Частая ошибка: называть embedding «наследованием». Здесь нет подтипов и виртуальных вызовов: внешний тип не приводится к встроенному, а метод встроенного типа не «переопределяется» и не видит полей внешнего.

Чем горутина отличается от потока ОС?

Короткий ответ: Горутина — это лёгкая единица выполнения, которой управляет рантайм Go, а не ядро ОС. Её стек стартует с ~2 КБ и растёт динамически, тогда как поток ОС резервирует мегабайты фиксированного стека. Рантайм мультиплексирует тысячи горутин на небольшое число потоков по модели M:N, поэтому в одном процессе спокойно живут сотни тысяч горутин.

Подробно:

  1. Стек — горутина: ~2 КБ с ростом/сжатием по мере надобности; поток ОС: фиксированные 1–8 МБ, зарезервированные заранее.
  2. Планировщик — горутины планирует рантайм Go (модель GMP: G — горутина, M — поток ОС, P — процессор-контекст) в user space; потоки планирует ядро.
  3. Стоимость переключения — переключение горутины не заходит в ядро и на порядки дешевле переключения контекста потока.
  4. Масштаб — потоков реалистично тысячи, горутин — сотни тысяч и больше.
Критерий Горутина Поток ОС
Стек ~2 КБ, растёт 1–8 МБ, фиксирован
Кто планирует рантайм Go (M:N) ядро ОС
Переключение user space, дёшево системный вызов, дорого
Сколько на процесс сотни тысяч тысячи

⚠️ Частая ошибка: ответить «это лёгкий поток» и остановиться. Без упоминания планировщика рантайма и модели M:N ответ звучит по-джуновски — интервьюер ждёт именно механику.

В чём разница между sync.Mutex и sync.RWMutex и когда RWMutex реально оправдан?

Короткий ответ: Mutex даёт эксклюзивный доступ — одна горутина в критической секции в любой момент. RWMutex разделяет блокировку на две: под RLock() читатели заходят параллельно, а Lock() писателя эксклюзивен и ждёт, пока все читатели выйдут. RWMutex оправдан только там, где чтений заметно больше, чем записей.

Подробно:

  1. Mutex — простой замок: Lock()/Unlock(), всегда один владелец. Дефолтный выбор.
  2. RWMutexRLock() для читателей (можно много одновременно), Lock() для писателя (один, эксклюзивно).
  3. Когда переходить на RWMutex — только если профилирование показало contention на чтениях и соотношение read:write велико (условно 10:1 и выше), а критическая секция не микроскопическая.
Критерий sync.Mutex sync.RWMutex
Читатели по одному параллельно
Писатель эксклюзивно эксклюзивно
Накладные расходы ниже выше (сложнее внутри)
Когда по умолчанию чтений >> записей

⚠️ Частая ошибка: ставить RWMutex «на всякий случай» и пугать голоданием писателей. В Go его нет: RWMutex write-preferring — ожидающий Lock() блокирует новых читателей (побочный эффект: рекурсивный RLock() в одной горутине может дать дедлок). Реальная цена — более дорогой захват: на коротких секциях обычный Mutex часто быстрее.

Что задаёт GOMAXPROCS и чему он равен по умолчанию?

Короткий ответ: GOMAXPROCS задаёт число P — максимум потоков ОС, одновременно исполняющих Go-код. По умолчанию он равен числу логических CPU (runtime.NumCPU()) — так с Go 1.5.

Подробно:

  1. Что именно ограничивает. Только параллельное исполнение Go-кода. Горутины, заблокированные на syscall или сетевом I/O, в лимит не входят — потоков в процессе может быть куда больше, чем GOMAXPROCS.
  2. Как менять. Через переменную окружения GOMAXPROCS или в рантайме runtime.GOMAXPROCS(n).
  3. Ловушка контейнеров. Исторически дефолт брал число ядер всей ноды, игнорируя CPU-лимит cgroup: на 64-ядерной ноде с лимитом «2 CPU» рантайм поднимал 64 P — лишние переключения контекста и троттлинг. Классическое лечение — uber-go/automaxprocs.
  4. Свежий Go. С Go 1.25 рантайм по умолчанию учитывает CPU-лимит cgroup — на Linux дефолт округляется вверх от лимита, поэтому проверяйте версию, прежде чем тащить костыль.
// GOMAXPROCS=4 ./app — через переменную окружения
runtime.GOMAXPROCS(4)      // или в рантайме
n := runtime.GOMAXPROCS(0) // 0 — прочитать текущее значение, не меняя

⚠️ Частая ошибка: на Go < 1.25 положиться на дефолт в Kubernetes с CPU-лимитом. Без automaxprocs рантайм видит все ядра ноды, а не выделенную квоту.

Как обернуть ошибку, добавив контекст, но сохранив цепочку для errors.Is/As?

Короткий ответ: Через fmt.Errorf с глаголом %w: fmt.Errorf("read config: %w", err). Именно %w вшивает исходную ошибку в цепочку Unwrap, так что errors.Is/errors.As продолжают её видеть. Глаголы %v и %s вставляют только текст и обрывают цепочку.

Подробно:

  1. %w сохраняет цепочку — оборачивает ошибку, оставляя доступ к оригиналу через Unwrap. Добавляй короткий контекст: что делал код, а не пересказ ошибки.
  2. %v/%s рвут цепочку — годятся только когда исходную ошибку намеренно скрываешь от вызывающего (граница абстракции).
  3. Контекст по слоям — на каждом уровне добавляй свой префикс; получается читаемый след open user file: read config: permission denied.
if err != nil {
    return fmt.Errorf("read config %q: %w", path, err)
}
// errors.Is(err, os.ErrPermission) по-прежнему работает

⚠️ Частая ошибка: обрабатывать ошибку дважды — и залогировать, и вернуть её наверх. Каждый слой либо оборачивает и возвращает, либо (на самом верху) логирует — не одновременно, иначе логи задваиваются.

Готовы закрепить навсегда?

Первая сессия — меньше минуты. Ваше будущее «я» на собеседовании скажет спасибо.

Вопросы об этом направлении

Как готовиться к собеседованию на «Go-разработчик»?

Учите концепции, которые придётся объяснять, а не только те, что умеете кодить. Направление «Go-разработчик» в RecallDeck даёт 333+ отобранных вопросов и возвращает каждый по расписанию в стиле Anki (SM-2) ровно перед тем, как вы забудете — чтобы на собеседовании ответы были под рукой.

Какие темы охватывает направление «Go-разработчик»?

Направление «Go-разработчик» разбито на ключевые области, которые реально проверяют на таких собеседованиях, — по темам и уровню сложности (Concept, Junior, Middle, Senior). Полный план и примеры вопросов можно посмотреть выше до входа.

Помогает ли интервальное повторение в подготовке к «Go-разработчик»?

Да. Активно вспоминать ответ и честно себя оценивать — куда прочнее для памяти, чем перечитывать заметки. RecallDeck планирует каждую карту «Go-разработчик» так, чтобы она вернулась перед моментом забывания: ежедневных повторений становится меньше, а знания держатся.

Можно попробовать направление «Go-разработчик» до оплаты?

Да. Месячный и годовой варианты включают семь пробных дней со всем направлением «Go-разработчик», полным планировщиком SM-2, статистикой, гибким темпом и блиц-режимом. Отменить можно онлайн до первого списания.

Другие направления