IT/программирование

Реальные собеседования Middle/Senior: Frontend и Java — что спрашивают

Разбор двух реальных технических собеседований: Frontend React/TS на 260-290K и Java Middle/Senior. Конкретные вопросы, задачи и типичные ошибки кандидатов.

Реальные собеседования Middle/Senior: Frontend и Java — что спрашивают

Реальные собеседования Middle/Senior: Frontend и Java — что спрашивают

Мы разобрали два реальных технических интервью — одно для Frontend-разработчика (React/TypeScript, вилка 260–290K рублей на руки), второе для Java Middle/Senior. Суммарно около двух часов живого контента: вопросы, live coding, разбор ошибок, фидбэк.

Статья для тех, кто готовится к смене работы или хочет понять, где именно… (31:26) ▶ 31:26

Статья для тех, кто готовится к смене работы или хочет понять, где именно «сыпятся» кандидаты на этих уровнях. Не пересказ теории из документации — конкретные вопросы, конкретные задачи, конкретные грабли.

Главный вывод: оба интервью показывают одно и то же — глубина важнее ширины. Кандидат, который знает три темы по-настоящему хорошо, выглядит убедительнее того, кто знает десять тем поверхностно.


Что спрашивают на Frontend Middle/Senior: структура интервью

Собеседование делилось на две части — теория и live coding. Теория шла блоками: браузер → JavaScript → React → TypeScript. Live coding — четыре задачи разной сложности.

Важный момент по структуре: вопросы шли от общего к частному. Сначала «что такое браузер», потом «как работает DOM», потом «что такое CORS и кто его настраивает». Это не случайность — интервьюер проверял, умеет ли кандидат выстраивать цепочку понятий, а не просто воспроизводить определения.

Браузер и сеть: базовый блок, который режет кандидатов

Вопросы по браузеру кажутся простыми — и именно поэтому здесь легко потерять очки.

DOM — это API, представляющее HTML-документ в виде дерева объектов. Кандидат должен не просто знать определение, но и уверенно называть методы: getElementById, querySelector, querySelectorAll, remove. На практике это проверяется быстро.

CORS — механизм браузера, который через HTTP-заголовки решает, может ли страница с одного домена запросить ресурс с другого. Ключевой момент, который часто путают: настройкой CORS занимается бэкенд, не фронтенд. Браузер только исполняет правила. Под капотом CORS использует preflight-запрос методом OPTIONS — это стоит знать и уметь объяснить.

WebSockets — протокол для двустороннего соединения поверх TCP. Отличие от обычного HTTP: одно постоянно открытое соединение вместо отдельного соединения на каждый запрос. Классика применения — чаты, live-уведомления, биржевые тикеры.

HTTP-методы — GET, POST, PATCH, PUT, DELETE, OPTIONS. (04:36) ▶ 04:36

HTTP-методы — GET, POST, PATCH, PUT, DELETE, OPTIONS. Разница между PATCH и PUT — частый уточняющий вопрос: PATCH обновляет часть ресурса, PUT заменяет его целиком.

JavaScript: где кандидаты теряют баллы

Восемь типов данных в JS — это не «восемь», это конкретный список, который нужно воспроизвести без запинок. Семь примитивов: number, string, boolean, null, undefined, bigint, symbol. Один непримитивный — object.

Два типа из этого списка регулярно вызывают затруднения:

  • BigInt — для целых чисел больше 2⁵³ − 1. Обычный number не справляется с такими значениями из-за ограничений IEEE 754.
  • Symbol — уникальное неизменяемое значение, используется как ключ в объектах. Два Symbol() с одинаковым описанием не равны между собой.

Event Loop — один из самых частых вопросов на Middle и выше. Суть: сначала выполняется весь синхронный код, затем очередь микрозадач (промисы, queueMicrotask), затем макрозадачи (setTimeout, setInterval). На интервью дают код и просят назвать порядок вывода в консоль. Разберём по пунктам на примере из разобранного материала:

// Порядок вывода: 1, 6 → 3, 2 → 5
// Синхронный код → микрозадачи (промисы) → макрозадачи (setTimeout)

Это не абстрактная теория — это конкретный навык, который проверяется кодом.

Сборка мусора — алгоритм «пометок и очистки» (mark-and-sweep): движок помечает… (03:47) ▶ 03:47

Сборка мусора — алгоритм «пометок и очистки» (mark-and-sweep): движок помечает все достижимые объекты, недостижимые удаляет. Ускорить или отключить этот процесс нельзя. Для сравнения: в C/C++ разработчик управляет памятью вручную — это и мощь, и источник утечек.

localStorage vs sessionStorage — данные в localStorage живут после закрытия браузера, в sessionStorage — только в рамках вкладки/сессии. Очистка через DevTools → Application или программно через removeItem, clear.

React: Virtual DOM, мемоизация и ловушки с Context

Virtual DOM — виртуальная копия реального DOM, хранящаяся в памяти как объект. Работает в три этапа: первоначальный рендеринг (создание виртуального дерева при монтировании), reconciliation (сравнение нового и старого виртуального дерева), коммит (применение изменений к реальному DOM). Смысл всего этого — минимизировать дорогостоящие операции браузера: layout, painting, reflow.

Сравнение React, Vue, Angular — стандартный вопрос. Коротко:

| | React | Vue | Angular | |---|---|---|---| | Тип | Библиотека | Фреймворк |… (17:35) ▶ 17:35

React Vue Angular
Тип Библиотека Фреймворк Фреймворк
DOM Virtual DOM Virtual DOM Incremental DOM
State Redux Toolkit / MobX Pinia NgRx

Мемоизация — здесь кандидаты часто знают «что», но не знают «когда». Три инструмента:

  • useMemo — кэширует результат вычисления, принимает функцию и массив зависимостей
  • useCallback — кэширует саму функцию, чтобы не пересоздавать её при каждом рендере
  • React.memo — HOC, предотвращает ре-рендер компонента при неизменившихся пропсах

Ключевой момент, который часто упускают: если пропсы меняются при каждом рендере — мемоизация не даёт выигрыша. Она добавляет накладные расходы на сравнение и при этом ничего не кэширует. Применять useMemo и useCallback везде подряд — антипаттерн.

Context vs Redux — частый вопрос. Context передаёт данные через дерево без явной передачи пропсов. Главный минус: при изменении значения в контексте перерендериваются все подписанные компоненты. Redux (точнее Redux Toolkit) даёт глобальное хранилище с более тонкой подпиской — компонент перерендерится только при изменении конкретного среза состояния.

TypeScript: interface vs type — вечный вопрос

TypeScript — статически типизированная надстройка над JS. Компилируется в обычный JS перед запуском, поэтому от runtime-ошибок не спасает. Это важно понимать: TypeScript работает на этапе разработки, не в продакшне.

Разница между interface и type:

Иллюстрация из видео (33:07) ▶ 33:07

  • interface — для описания структур объектов и сущностей. Например, структура пользователя с полями name, role, id. Интерфейс может наследоваться от другого интерфейса.
  • type — для союзных типов и алиасов. Например, поле status может быть 'admin' | 'banned' | 'deleted'. Тип не поддерживает наследование так же, как интерфейс.

Когда TypeScript избыточен: быстрые прототипы, pet-проекты без долгосрочной перспективы. В таких случаях накладные расходы на типизацию не окупаются.


Live coding на Frontend: четыре задачи и их разбор

Практическая часть — четыре задачи. Разберём каждую.

sortById — функция принимает массив объектов с полем id, возвращает новый массив, отсортированный по возрастанию. Решение: spread-оператор для создания нового массива, затем sort с компаратором по полю id. Задача на знание иммутабельности — исходный массив трогать нельзя.

Event Loop — код с синхронными блоками, промисами и setTimeout. Нужно назвать порядок вывода. Проверяет понимание очередей задач, не синтаксис.

simplifyPath — упрощение Unix-пути: убрать двойные слэши, обработать . (текущая директория) и .. (переход на уровень выше). Решение через стек: разбить путь по /, пройтись по частям, пропускать пустые строки и ., при .. делать pop (если стек не пуст), иначе push. В конце — join('/') и добавить ведущий слэш. Задача на алгоритмическое мышление, а не на знание React.

customEvery и customFlat — реализация стандартных методов массива вручную. customEvery принимает массив и колбэк, возвращает false при первом несоответствии. customFlat — рекурсивная реализация с параметром глубины, Array.isArray для проверки вложенности.

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


Что спрашивают на Java Middle/Senior: восемь блоков за час

Java-интервью оказалось плотнее по охвату. Восемь тематических блоков за 67 минут — это высокий темп. Разберём по блокам.

Коллекции: иерархия и внутреннее устройство

Иерархия: IterableCollectionList / Queue / Set. Map стоит отдельно от этой иерархии — это частая ловушка.

ArrayList vs LinkedList — классика, но с нюансом. ArrayList хранит данные в непрерывной области памяти — процессор кэширует их эффективно. LinkedList хранит элементы в разных участках памяти, связанных указателями. На практике ArrayList быстрее даже при вставке в середину, потому что при создании резервирует пространство: дефолтный размер 10 элементов, при заполнении расширяется в 1.5 раза. Часть индексов уже свободна — сдвигать нужно меньше элементов, чем в теории.

HashMap — внутреннее устройство нужно знать детально:

  1. put вычисляет хэш-код ключа
  2. Через остаток от деления определяется номер бакета
  3. Если бакет пуст — элемент помещается сразу
  4. Если занят — сравниваются хэш-коды (быстро), затем вызывается equals (медленнее)
  5. При коллизии элементы выстраиваются в связный список внутри бакета
  6. При достижении 8 элементов в бакете — перестройка в красно-чёрное дерево, сложность поиска улучшается с O(n) до O(log n)

Многопоточность: synchronized, Lock и дедлоки

ExecutorService — четыре реализации: - SingleThreadExecutor — один поток - FixedThreadPool — фиксированное число потоков - CachedThreadPool — динамически создаёт потоки, простаивающий поток живёт 60 секунд по умолчанию - ScheduledThreadPool — для задач по расписанию

Смысл пула потоков: создание нового потока — дорогая операция (выделение памяти, регистрация в ОС). Пул переиспользует уже созданные.

synchronized vs Locksynchronized прост, но негибок. ReentrantLock даёт больше контроля: - tryLock(timeout) — поток пытается захватить монитор в течение заданного времени, затем отступает - параметр fairness — монитор получает поток, который ждёт дольше всех, что предотвращает thread starvation (голодание потоков)

Важное предупреждение: synchronized на статическом методе блокирует монитор всего класса. Это нежелательная практика — последствия при использовании сторонними компонентами непредсказуемы.

Дедлок — два потока захватывают ресурсы в обратном порядке и блокируют друг друга навсегда. Решение: захватывать ресурсы всегда в одном порядке, либо использовать tryLock. Лайвлок — потоки активны, но не продвигаются вперёд, постоянно уступая друг другу. Аналогия: два человека в узком коридоре, которые одновременно пытаются уступить дорогу.

Базы данных: индексы, изоляция, MVCC

Индексы — два основных типа в PostgreSQL: - B-Tree — покрывает ~95% случаев, поддерживает поиск по диапазону и точному значению - Hash — быстрый поиск по точному значению, диапазоны не поддерживает

Селективность — ключевое понятие. Столбец с двумя возможными значениями (например, пол) — индекс бессмысленен. Столбец с уникальными значениями (например, email) — индекс максимально эффективен.

Составной индекс — работает как вложенные деревья: дерево A → дерево B → дерево C. Если запрос использует только B и C, минуя A — индекс не сработает. Это правило «левого префикса», и его незнание — частая ошибка.

Создавать индексы по всем столбцам — ошибка. При каждой вставке и обновлении все индексы нужно перестраивать. Это замедляет запись.

Уровни изоляции транзакций — четыре уровня, три проблемы: - Грязное чтение — читаем незакоммиченные данные другой транзакции - Неповторяемое чтение — одно и то же значение в рамках транзакции читается дважды с разным результатом - Фантомное чтение — количество строк между двумя чтениями в одной транзакции изменилось

В PostgreSQL уровень Read Uncommitted отсутствует — его заменяет механизм MVCC (многоверсионное управление параллелизмом). Каждая транзакция видит свою версию данных. После удаления строк образуются «мёртвые» версии — их очищает процесс VACUUM.

Spring, Kafka и паттерн Transactional Outbox

@Transactional — два подводных камня: 1. Не работает на приватных методах 2. Не работает при вызове транзакционного метода из другого метода того же класса (self-invocation обходит прокси Spring)

Решение в обоих случаях — вынести метод в отдельный бин.

Kafka и гарантии доставки — три уровня: At Least Once, At Most Once, Exactly Once. Реальная проблема: сервис сохраняет заказ в PostgreSQL и отправляет сообщение в Kafka. Если сервис падает после записи в базу, но до отправки в Kafka — сообщение теряется.

Решение — паттерн Transactional Outbox: сохранять сообщение в отдельную таблицу в рамках той же транзакции, что и основные данные. Отдельный планировщик читает эту таблицу и отправляет сообщения в брокер. Для защиты от дублирования — идемпотентный идентификатор на стороне потребителя.


Практический чек-лист: что делать прямо сейчас

Для Frontend-разработчика

  1. Браузер и сеть — объясни вслух, как работает CORS, кто его настраивает и зачем нужен preflight. Если запнулся — повторить.
  2. Event Loop — возьми любой онлайн-визуализатор Event Loop, прогони 5–10 примеров с промисами и setTimeout. Порядок вывода должен быть очевиден без раздумий.
  3. Типы данных JS — напиши все восемь по памяти. Объясни разницу между null и undefined, между bigint и number.
  4. Virtual DOM — нарисуй на бумаге три этапа: первоначальный рендеринг, reconciliation, коммит. Объясни, зачем это нужно.
  5. Мемоизация — напиши пример, где useMemo оправдан, и пример, где он бесполезен. Объясни разницу.
  6. TypeScript — возьми реальную структуру данных из своего проекта и опиши её через interface. Потом через type. Объясни, что выбрал и почему.
  7. Live coding — реши customFlat и customEvery без подсказок. Потом реши задачу на стек (например, simplifyPath или валидация скобок).

Для Java-разработчика

  1. Коллекции — нарисуй иерархию интерфейсов по памяти. Объясни внутреннее устройство HashMap: бакеты, коллизии, красно-чёрное дерево при 8 элементах.
  2. Многопоточность — объясни разницу между synchronized и ReentrantLock. Приведи пример дедлока и скажи, как его избежать.
  3. GC — назови все сборщики в HotSpot JVM. Объясни, почему G1 — дефолтный. Что такое Stop-the-World.
  4. Индексы — объясни правило левого префикса для составных индексов. Приведи пример столбца с низкой селективностью.
  5. Транзакции — назови четыре уровня изоляции и три проблемы, которые они решают. Объясни MVCC в двух предложениях.
  6. @Transactional — воспроизведи оба сценария, где аннотация не работает. Скажи, как исправить.
  7. Transactional Outbox — нарисуй схему: база данных → таблица outbox → планировщик → Kafka. Объясни, зачем идемпотентный идентификатор.

Что мы заметили: где подходы совпадают, где расходятся

Оба интервью — разные стеки, разные уровни сложности, но несколько общих паттернов бросаются в глаза.

Где материалы сходятся:

— Интервьюеры в обоих случаях идут от общего к частному. Сначала «что это такое», потом «как работает внутри», потом «где ломается». Кандидат, который знает только определение, — не проходит.

— Практические задачи важнее теории. В обоих интервью живой код занимал значительную часть времени. Умение думать вслух и объяснять решение — отдельный навык, который оценивается.

— Типичные ошибки — не в сложных темах. Кандидаты спотыкаются на мемоизации (применяют везде), на @Transactional (self-invocation), на индексах (создают на все столбцы). Это не rocket science — это детали, которые нужно знать.

Где подходы расходятся:

Более консервативный взгляд (прослеживается в Frontend-интервью): акцент на базовых концепциях браузера и JS. Если кандидат не может объяснить Event Loop — дальнейшие вопросы по React теряют смысл.

Более системный взгляд (Java-интервью): интервьюер явно ожидает понимания архитектурных паттернов и компромиссов. Вопрос «а что если сервис упадёт?» — это не теория, это проверка инженерного мышления. Паттерн Transactional Outbox здесь — не бонус, а ожидаемый ответ на уровне Middle+.

— В Frontend-интервью достаточно знать инструмент и уметь его применять. В Java-интервью от кандидата ожидают понимания, почему инструмент работает именно так — вплоть до внутреннего устройства HashMap и механизма MVCC в PostgreSQL.


Итог

Оба интервью подтверждают одну вещь: на уровне Middle/Senior «знаю, что это… (23:43) ▶ 23:43

Оба интервью подтверждают одну вещь: на уровне Middle/Senior «знаю, что это такое» — недостаточно. Нужно «знаю, как это работает внутри» и «знаю, где это ломается».

Хорошая новость: большинство вопросов из обоих интервью — конечный список. Коллекции Java, Event Loop, Virtual DOM, уровни изоляции транзакций — это не бесконечная область. Это конкретные темы, которые можно проработать за несколько недель систематической подготовки. Возьмите чек-лист выше, закройте одну тему за раз, и через месяц картина будет другой.

Использованные видео

Хотите такой же разбор для своего видео?

ZUB-AI проанализирует любое YouTube-видео и пришлёт структурированный отчёт. Первый анализ — бесплатно.

Попробовать ZUB-AI →