Руслан Куянец | Reactify – Telegram
Руслан Куянец | Reactify
5.85K subscribers
703 photos
52 videos
39 files
286 links
Я IT-специалист, ментор и основатель проекта YeaHub и сообщества Reactify. Здесь рассказываю про Frontend и IT.

Менторство:
https://reactify.ru

YouTube канал:
https://youtube.com/@reactify-it

YeaHub:
https://yeahub.ru/

Связь:
@ruslan_kuyanets
Download Telegram
🖥 Лайвкодинг в компании Postgres Pro

Позиция Middle Frontend Разработчик

Достаточно сложные вопросы были по опыту, проектам. А так же не было стандартных технических вопросов.

На собеседовании нужно было реализовать Игру "Crush the mole".
Описание задачи:
Необходимо реализовать игру "Crush the mole" на TypeScript. Игра представляет собой поле 4x4 клетки, на котором через случайные промежутки времени в случайной клетке появляется крот. Игрок должен успеть "прихлопнуть" крота, кликнув по нему левой кнопкой мыши. После успешного клика крот исчезает и появляется в новой случайной клетке. Игру можно остановить и начать заново с помощью кнопки.

Требования:
- Поле игры: Игровое поле состоит из 16 клеток (4x4).
- Появление крота: Крот появляется в случайной клетке через случайные промежутки времени.
- Управление: Игрок кликает по клетке, чтобы "прихлопнуть" крота. Если клик был по клетке с кротом, крот исчезает и появляется в новой случайной клетке.
- Кнопка управления: Игру можно остановить и начать заново с помощью одной кнопки.
- Отображение крота: Крот отображается символом, например, @.
- Генерация случайных чисел: Для генерации случайного числа можно использовать Math.random().


import React from 'react';

const elements = Array(16).fill(0);

export default function App() {
const [randomIndex, setRandomIndex] = React.useState(0);
const [isStart, setStart] = React.useState(false);

// Ваш код здесь

return (
<div className="App">
<h1> Crush the mole </h1>
<button onClick={() => { /* Ваш код здесь */ }}>
{isStart ? "Остановить" : "Начать игру"}
</button>
<div className="container">
{elements.map((elem, index) => (
<div
key={index}
className="item"
onClick={() => { /* Ваш код здесь */ }}
>
{index === randomIndex ? "@" : ""}
</div>
))}
</div>
</div>
);
}


Задачи для кандидата:
- Реализовать логику появления крота в случайной клетке через случайные промежутки времени.
- Реализовать обработку клика по клетке: если клик был по клетке с кротом, крот исчезает и появляется в новой случайной клетке.
- Реализовать кнопку, которая будет останавливать и запускать игру.
- Убедиться, что игра корректно работает и не содержит багов (например, крот не появляется в той же клетке сразу после исчезновения).

Дополнительные вопросы для обсуждения:
- Как можно оптимизировать код для улучшения производительности?
- Как можно добавить дополнительные функции в игру (например, счетчик очков, таймер, уровни сложности)?
- Как можно протестировать эту игру?

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

#interview
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥19👍21🤝1
💬 Как работает HR в условиях текущего рынка?

Сейчас на рынке труда мало вакансий, а конкуренция среди кандидатов высокая. Компании диктуют правила: они могут позволить себе быть избирательными, не торопиться с наймом и рассматривать только самых подходящих кандидатов. В такой ситуации даже идеальное резюме не гарантирует приглашения на собеседование, а кандидат со средним резюме может стабильно проходить скрининги и получать офферы.

Почему так происходит? Давайте разберёмся в логике HR-специалистов.

💡 Как HR отбирает кандидатов?

1. Первичная фильтрация: жёсткие критерии
На одну вакансию может прийти 1000+ откликов. В первую очередь HR задаёт максимально строгие фильтры, чтобы отсеять 90% кандидатов. Например:

- Город (только Москва/СПб, без релокации)
- Возраст (часто 25–35 лет, особенно для middle/senior)
- Опыт работы (не «от 3 лет», а «ровно 5+»)
- Уровень английского (B2+ даже там, где он реально не нужен)

После такой фильтрации остаётся 10–20 «идеальных» кандидатов. Их проверяют в первую очередь – зачем смотреть остальных, если среди этих уже может быть подходящий?

2. Постепенное расширение поиска: партийный отбор
Если среди топ-кандидатов никто не подошёл, HR ослабляет критерии, но не сразу. Например:
- Берут тех, кто соответствует 6–8 из 10 пунктов (например, опыт 4 года вместо 5, или английский B1 вместо B2).
- Приглашают партиями по 5–10 человек – если вакансия закроется на первых же кандидатах, остальных даже не увидят.

Проблема: пока HR дойдёт до вашего резюме (особенно если вы «середнячок»), вакансия может уже закрыться.


3. Влияние алгоритмов: «Лучший кандидат» и случайность
Платформы вроде HeadHunter используют автоматическую сортировку (например, функцию «Лучший кандидат»). Но алгоритмы работают неидеально:
- Они не понимают контекст (например, могут продвинуть резюме с кучей ключевых слов, но без реального опыта).
- HR часто доверяет этой сортировке и зовёт первых 5–10 из списка, не проверяя остальных.

Отсюда эффект рандома – иногда на скрининг попадает не самый подходящий, а просто тот, кого алгоритм поставил выше.


⚡️ Что это значит для вас?

- Даже маленький «недожёг» в резюме (например, 4 года опыта вместо 5) может отбросить вас во вторую/третью очередь.
- Важно попасть в топ выдачи (через ключевые слова, обновления резюме и т. д.).
- Скорость отклика критична – чем раньше, тем выше шанс попасть в первую партию.
- Алгоритмы несправедливы – иногда нужно «обходить» их вручную (писать HR напрямую, искать рефералов и т. д.).

Вывод: в текущих условиях пассивный поиск почти не работает. Нужна агрессивная стратегия – оптимизация резюме под алгоритмы, быстрые отклики и прямое взаимодействие с рекрутерами.


А как у вас дела? Получается ли находить работу? Делитесь лайфхаками!

#interview #hr #work
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14🔥52💯2
👩‍💻 Сложное Frontend Собеседование + Live Coding. Promises, This, Memo, Generics, Solid, HTTP

Изначально запись этого собеседования не планировалась для публикации — она была сделана для детального разбора навыков и поведения Даниила. Для него это был первый опыт мокового собеседования, и, как он сам отметил, волнение и стресс сопровождали его на протяжении всего процесса. Однако такой формат оказался крайне полезным: он позволил объективно оценить слабые места и наметить план работы.

Какие проблемы выявил разбор?
- Ответы давались кратко, без необходимой аргументации и пояснений
- Активное использование слов-паразитов: «наверное», «вроде», «не знаю», что создавало впечатление неуверенности
- Даже правильные ответы звучали неубедительно из-за нерешительной манеры подачи
- Многие вопросы оставались раскрытыми неполно, без углубления в суть
- На базовые вопросы, которые кажутся очевидными, давались неполные или частично верные ответы

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

Видео уже на канале!
Я не оставляю ссылку, так как видео лучше продвигается, если заходить на него напрямую с YouTube. Это помогает улучшить его рейтинг и увеличить шансы на органическое продвижение.

#frontend #interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👍27🔥73
🌐 IT-сообщества, митапы и путешествия — как я заряжаюсь энергией и развиваюсь

Мне нравится IT за безграничные возможности и открытость. Здесь столько интересных, продвинутых людей — они не боятся пробовать новое, путешествуют, развиваются и постоянно учатся. Кажется, ни в одной другой сфере нет такого драйва!

Я активно участвую в IT-сообществах, хожу на онлайн- и офлайн-мероприятия. Это помогает понимать тренды, расти в доходе и просто становиться лучше. Для меня айтишники — это про современность: они следят за собой, ходят в зал, имеют кучу хобби и не сидят на месте.

Весна — время встреч и путешествий☀️✈️

С приходом тепла хочется больше общаться вживую. В марте я встретился с классными ребятами — гуляли в парке, болтали за кофе и матчей. А уже на этих выходных жду сходку с учениками в Краснодаре: часть из них уже работает, другие в поиске. Обсудим жизнь, карьеру и обучение.

Летом планирую 1,5-2-месячное турне по Центральной России — хочу объехать кучу городов, где живут мои друзья, ученики и участники IT-сообществ, в которых я состою. В Москве, например, ждут около 30 моих учеников — наконец-то увидимся вживую!😅

Где искать крутые IT-мероприятия? 📺

Я постоянно мониторю митапы и хакатоны. В Краснодаре их немало, но в Москве, думаю, просто адское количество ивентов. Чтобы не тратить время на поиски, пользуюсь каналом IT мероприятия России / ITMeeting / IT events. Там всё структурировано: митапы, вебинары, конференции — в одном месте.

Это лучший источник анонсов, всегда советую его ученикам, которые хотят прокачаться в нетворкинге. Подписывайтесь — вдруг встретимся на каком-нибудь митапе? 🤝

Куда еду летом? 🚗

Сейчас составляю маршрут. В каждом городе планирую быть 1-3 дня, а в Москве — 1-2 недели. Пока в списке: Воронеж, Москва, Нижний Новгород, Печоры, Суздаль, Тула, Владимир

Думаю заехать и в Питер на недельку — там тоже много знакомых. Если знаете крутые места или города, которые стоит посетить — пишите в комменты!

А вы часто ходите на митапы?
Какие запомнились больше всего?
Какие города и локации советуете?


Давайте общаться! Может, встретимся на одной из сходок? 🤝

🔗 Ссылка на канал событий в IT

#frontend #events
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥116👍2🤝1
🥇 Что делать кандидату? Стратегия прорыва в условиях жесткого рынка

Сейчас недостаточно просто отправить резюме и ждать — нужно атаковать рынок со всех сторон. Чем больше действий, тем выше шансы. Вот рабочие тактики:

1. Оптимизация резюме и профиля
- Ключевые слова из вакансии — HR и алгоритмы ищут по ним.
- Несколько версий резюме под разные вакансии (или даже новый аккаунт с другим телефоном/почтой).
- Обновляйте резюме раз в 1-2 дня, чтобы подняться в поиске.
- Цифры и метрики — автоматические системы любят конкретику.
- Приукрашивайте опыт, усиливайте достижения, используйте сильные слова.

2. Обход алгоритмов и фильтров
- Откликайтесь в первые часы после публикации — чем раньше, тем выше шанс.
- Реферальные ссылки — если есть знакомые в компании, просите приглашение (таких кандидатов часто рассматривают в приоритете).
- Пишите напрямую HR или рекрутерам (но коротко — 3-4 предложения о вашем соответствии).

3. Альтернативные способы выхода на компанию
- Ищите вакансии на сайтах компаний — иногда их публикуют там раньше, чем на агрегаторах.
- Telegram-каналы, чаты по поиску работы — некоторые вакансии не доходят до HH.
- Митапы и конференции — нетворкинг до сих пор один из самых сильных инструментов.
- Изучите LinkedIn — это ещё одна возможность быть замеченным.
- Пишите не только HR, но и текущим работникам компании (можно найти в чатах и попросить зарефералить).
Please open Telegram to view this post
VIEW IN TELEGRAM
👍193💯1
🐝 Собеседование в компании Билайн

Позиция Middle Frontend Разработчик

1. Разница между WebSocket и SSE?
2. Разница между юнит-тестами и интеграционными тестами?
3. Допишите код хука и его типы:

type UseArrayActions = {
push: (item) => void,
removeByIndex: (index) => void
}

export function useArray(initialValue): { value } & UseArrayActions {
const [value, setValue] = useState(initialValue);

const push = (item) => setValue();
const removeByIndex = (index) => setValue();

return { value, push, removeByIndex };
}


4. Дан массив строк (не меньше 3 элементов), в котором одна из строк отличается по составу входящих в неё букв от остальных строк в массиве. Порядок, количество, регистр букв и пробелы роли не играют. Реализовать метод, который принимает на вход такой массив строк, и возвращает отличающуюся строку.

console.assert( findUniq(['a', 'a Aa', 'ab a', 'AA a']) === 'ab a' );
console.assert( findUniq(['ab', 'a Aa', 'ab a', 'bAA a']) === 'a Aa' );
console.assert( findUniq([1,2,1,1]) === 2 );
console.assert( findUniq(['aBca', 'ac b', 'bac', 'fO o', 'bca', 'cabaccBA', ' Ccba']) === 'fO o' );

function findUniq(strings) {
???
}


5. Объясните, что произойдет при выполнении следующего кода:

const Andrey = {
name: 'Андрей',
surname: 'Малахов',
city: {
name: 'Москва'
},
}

const Genadius = {
name: 'Генадий',
surname: 'Малахов',
city: Andrey.city,
}

Genadius.city.name = 'Санкт-Петербург'


6. В каких случаях может выполниться “something code”?

const checkIntervalMs = 2000;
const toleranceMs = 2000;
let lastCheckStamp: number = null;

setInterval(
() => {
const now = Date.now();
if (lastCheckStamp && now - lastCheckStamp > checkIntervalMs + toleranceMs){
//something code
}
lastCheckStamp = now;
},
checkIntervalMs
);


7. Что такое Server-Sent Events?
8. Опыт работы с постоянным соединением через WebSocket?
9. Что такое Event Loop?
10. Что происходит при вводе адреса в адресной строке и нажатии Enter?
11. Что такое чистая функция?

#interview
👍29🔥65
👩‍💻 Инжектирование эндпоинтов в RTK Query и организация API в отдельных файлах

Когда вы работаете с несколькими сущностями в приложении, может возникнуть необходимость разделить логику работы с API на несколько частей для лучшей организации кода и повышения читаемости. Инжектирование эндпоинтов позволяет вам добавлять новые запросы к уже созданному базовому API, что упрощает управление и масштабирование вашего приложения.

Организация базового API

Рекомендуется создать отдельный файл для базового API, который будет содержать общие настройки, такие как baseQuery, reducerPath и другие параметры, а также общие эндпоинты.


// baseApi.js
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';

const baseApi = createApi({
reducerPath: 'baseApi',
baseQuery: fetchBaseQuery({ baseUrl: '/api' }),
tagTypes: ['User', 'Post'], // Определяем типы тегов для инвалидации кэша
});

export default baseApi;


Создание эндпоинтов для различных сущностей

Теперь вы можете создать отдельные файлы для каждой сущности, добавляя в них необходимые эндпоинты и используя базовый API.


// userApi.js
import baseApi from './baseApi';

// injectEndpoints автоматически добавит эндпоинты к baseApi
const userApi = baseApi.injectEndpoints({
endpoints: (builder) => ({
fetchUsers: builder.query({
query: () => 'users',
providesTags: ['User'], // Указываем, что этот запрос использует тег 'User'
}),
addUser: builder.mutation({
query: (newUser) => ({
url: 'users',
method: 'POST',
body: newUser,
}),
invalidatesTags: ['User'], // Инвалидируем кэш для 'User'
}),
}),
overrideExisting: false, // Не переопределяем существующие эндпоинты
});

export const { useFetchUsersQuery, useAddUserMutation } = userApi;
export default userApi;

Пример эндпоинтов для постов

// postApi.js
import baseApi from './baseApi';

// injectEndpoints автоматически добавит эндпоинты к baseApi
const postApi = baseApi.injectEndpoints({
endpoints: (builder) => ({
fetchPosts: builder.query({
query: () => 'posts',
providesTags: ['Post'], // Указываем, что этот запрос использует тег 'Post'
}),
addPost: builder.mutation({
query: (newPost) => ({
url: 'posts',
method: 'POST',
body: newPost,
}),
invalidatesTags: ['Post'], // Инвалидируем кэш для 'Post'
}),
}),
overrideExisting: false, // Не переопределяем существующие эндпоинты
});

export const { useFetchPostsQuery, useAddPostMutation } = postApi;
export default postApi;


Инжектирование эндпоинтов в RTK Query позволяет вам создавать гибкую и масштабируемую архитектуру для работы с несколькими сущностями. Разделение логики API на отдельные файлы помогает поддерживать чистоту и порядок в коде, а использование базового API упрощает добавление новых эндпоинтов. Такой подход способствует улучшению читаемости и поддерживаемости вашего приложения.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍235🔥4
🎤 Задание с лайвкодинга в Авито

Проанализируйте код и определите, что будет выведено в консоли.

(function () {
function modifyItemData(price, platform) {
price.rub = 5000;
platform = 'iOS';
isModified = true;

function printItemData() {
console.log(price); // ?
console.log(platform); // ?
console.log(isModified); // ?
}

return printItemData;
}

let price = { rub: 3500 };
let platform = 'Android';
let isModified = false;

const printItemData = modifyItemData(price, platform, isModified);

console.log(price); // ?
console.log(platform); // ?
console.log(isModified); // ?

price = { usd: 100 };
platform = 'Web';
isModified = null;

printItemData();
})();

Вопросы:
1. Почему price изменяется, а platform — нет?
2. Как работает область видимости переменной `isModified`?


#собеседование #лайвкодинг
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🔥7💯1
Фронтенд в картинках — просто, наглядно и понятно. Новые знания в компактном формате каждый день.

Присоединяйтесь: @FrontendPortal
👍24🔥43💯1
👩‍💻 Проектирование таблицы в React: SOLID, IoC и Render Props

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

Проблема:
Если делать отдельный компонент под каждую сущность (UsersTable, ProductsTable), получим дублирование кода. Если запихать всю логику в один компонент — он превратится в монстра с кучей if-else.

Решение:
Делаем единную таблицу, но гибкую. Вместо хардкода данных и столбцов, выносим рендеринг наружу.

Какие техники применяем?
✔️ Render Props – Передаём renderRow и renderHeader как пропсы. Внутри Table только разметка, логика рендеринга — снаружи.

✔️ Принцип открытости/закрытости – Если для товаров нужна иконка валюты, а для пользователей — аватарка, не лезем внутрь Table, а просто рисуем нужное в переданной функции.

✔️ Dependency Injection – Зависимости (рендер-функции) приходят через пропсы. Можно подставить любую логику без изменений самого компонента.

✔️ Инверсия управления (IoC) – Table не знает, что в нём будет. Управление содержимым — у родителя.

✔️ Паттерн "Стратегия" – renderRow и renderHeader — это стратегии отображения. Подменяем их под задачу.

Итог:
Одна таблица на все случаи, без дублирования, с возможностью кастомизации под любую сущность.

Если тема интересна, сделаю серию постов про другие типовые компоненты: модалки, фильтры, карточки. Как вам идея?


#react #solid #patterns
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍39🔥127
🎂 Мой год перемен

В 27 лет я был в найме, только пробовал себя в менторстве, YeaHub существовал на уровне "в свободное время что-то пилим, одну страницу делаем месяц". На YouTube было 4000 подписчиков, в Telegram3000. Только родилась дочь, работы — море, пахал 24/7 без выходных.

Год спустя, в 28, всё иначе.

Я ушел из найма и полностью погрузился в свой проект. Сейчас в нём — 2000 зарегистрированных пользователей, 40 000 посещений за 5 месяцев, ежедневно платформу посещают 500–800 человек. Сеть каналов YeaHub выросла до 6000+ подписчиков. YouTube приближается к 10 000, Telegram5200.

За год для учеников я создал полноценный курс-роадмап: от основ HTML/CSS до продвинутых тем вроде Docker и CI/CD. Записал 150+ уроков, собрал базу гайдов и материалов. В мае выйдет бесплатный курс по JS DOM API на YouTube – я продолжаю делиться знаниями бесплатно.

Но главное — люди.

За этот год я обучил (и продолжаю обучать) больше 150 человек. Сообщество учеников и выпускников — уже 130+ человек. Помог трудоустроиться более 30 ребятам. Познакомился с крутыми ребятами — блогерами, менторами, экспертами. Вступил в сильные IT-сообщества. Прочувствовал мощь нетворкинга и силу окружения. Стал лучше, пересмотрел взгляды, прокачал мышление.

А ещё — это самый тёплый день рождения в моей жизни.

Утро началось с 40+ поздравлений от учеников. Жена с дочкой встретили меня с тортиком — не сдержался, прослезился 🥹. Писали коллеги, друзья, знакомые — столько тёплых слов, благодарностей и пожеланий.

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

Я бесконечно благодарен миру за эти возможности, людям — за доверие и помощь, IT — за крутое комьюнити и бесконечный рост.

И знаю: впереди — ещё больше свершений. 💪
🔥67👍279🤝2