Найм в IT. Как правильно проводить технические собеседования?

Ранее я описывал свое видение организации процесса найма и построения команды в общих чертах. В данной статье хочу рассказать подробнее про этап технического интервью. Тема горячая и всегда бурно обсуждаемая в комьюнити. Споры про "Зачем спрашивать алгоритмы если я верстаю кнопочки на Реакте?", похоже, будут жить вечно и всегда будут актуальны.
Для наглядности будут показаны примеры конкретных задач для позиции Senior Frontend Developer. Как и в прошлый раз, сама роль и стек технологий не играет большой роли. Если бы я нанимал DevOps или QA - подход был бы примерно тот же.
За начальное условие мы берем уже как-то настроенный процесс найма с воронкой из нескольких этапов, где мы уже отсеяли большую часть входного потока кандидатов на этапе L0 (HR) и L1 (технический скрининг). Если человек не может внятно ответить как работает Event loop в JS и bubbling/capturing DOM-событий - воронка должна это отловить как можно раньше. До того как он попадет на главное 2-3 часовое тех. интервью с самыми экспертными ребятами из вашей команды.
Структура интервью
Знакомство. Предыдущий опыт (5-15 минут)
Валидация знаний по основному стеку из резюме (10-20 минут)
Практические задачи (50-90 минут)
System design (15-30 минут)
Понимание agile-процессов (10-15 минут)
Продаем кандидату нашу вакансию (10-20 минут)
Иметь четкий план на интервью всегда лучше, чем импровизация. Поэтому, перед тем как собеседовать кандидатов, интервьюеру будет полезно проделать определенную домашнюю работу и стандартизировать процесс. Я обычно стараюсь поместить кандидатов в более-менее одинаковые условия по формату, сложности задач, продолжительности интервью. Так легче объективно оценивать уровень экспертности инженеров и сравнивать их между собой.
В целом, все интервью построено по нарастанию сложности вопросов и задач. Это не значит, что в начале мы спрашиваем элементарные вещи из документации или туториалов. Для этого в воронке найма есть предыдущий этап скрининга. На главном техническом интервью не должно быть легких вопросов, которые гуглятся за 5 секунд. Особенно на позицию Senior.
Практические задачи - обязательная и самая важная часть интервью, она же самая стрессовая для кандидата. Поэтому, я подвожу интервью к ней плавно, давая человеку время почувствовать себя в своей тарелке, привыкнуть к обстановке и набрать уверенности.
Знакомство. Предыдущий опыт
Знакомство - процесс обоюдный. Перед тем как начать спрашивать кандидата про его опыт, неплохо хотя бы парой фраз рассказать кто вы и чем занимаетесь в данной компании.
В начале интервью даем кандидату время, чтобы он спокойно без стресса рассказал то, что он точно знает - чем он занимался на последнем месте работы. Меня в первую очередь интересует не стек технологий, проект или архитектурные решения, а такие вещи как: а) Размер команды? б) Роль и зона ответственности кандидата? в) Кто принимал основные технические решения в команде? г) Есть ли менеджерский опыт или только технический? д) Как были устроены процессы внутри команды?
Я считаю это более важным, потому что для человека проще изучить новую библиотеку для state management, чем перейти из микро-стартапа где всего 10 человек в крупную компанию, где 10 человек только коммитят с тобой в одну репу каждый день. Не все готовы работать с огромным объемом чужого кода и искать компромиссы. Не все готовы работать по четким процессам с оценками и сроками. Если для вас это актуально - будет не лишним обратить внимание насколько вы подходите друг другу с кандидатом концептуально.
Так же, я всегда обращаю внимание на тон, в котором человек отзывается о коллегах и начальстве на предыдущем месте. Поверьте, лучше не нанимать людей, у которых всегда кто-то виноват, а он за всех все сделал бы лучше. Техническая экспертиза в таком случае для меня уже не играет роли т.к я всегда настроен на долгосрочное сотрудничество и хочу быть уверен, что мы сможем работать в одной команде на протяжении нескольких лет.
Валидация знаний по основному стеку из резюме
Продолжаем разговор в области, которую кандидат знает хорошо(но это не точно...). Можно довольно быстро померить глубину технических знаний, если начать задавать advanced-вопросы по тому стеку, который человек считает основным для себя. Даже если этот стек не пересекается с нашим. Пример:
У нас на проекте React, но человек больше работал с Angular - не страшно. Я спрошу как работает change detection и zone.js в Angular. Зачем в Angular модули (NgModule) и как работает Dependency Injection. Если человек эксперт в своем текущем стеке - он так же глубоко изучит и новый. Плюс это лучше выявляет синьйорность, чем работал/не работал с библиотекой X.
Так же работает в обратную сторону. Если знания поверхностные даже в технологиях, с которыми человек работает каждый день - половину следующих вопросов из категории "сложные" можно будет даже не задавать и сэкономить себе время.
Другой пример - TypeScript. В резюме есть у каждого frontend-разработчика, но большинство его знают и используют процентов на 30. Затипизировать пропсы в React-компоненте могут многие, но это мало что говорит об уровне знаний языка. Вот пара примеров, как можно быстро определить эксперта в TypeScript.
Пример 1:
const arr1 = [1, 2, null, 3]
const arr2 = arr1.filter((item) => item !== null)
Какой тип arr1? Ответ - (number | null)[]
Какой тип arr2? Ответ - (number | null)[]
Как нам сделать так, чтобы TypeScript понял, что мы отфильтровываем null в рантайме и вывел arr2 тип как number[] в compile-time? А если без кастинга as ?
Решение
function isNonNullable(value: T | null | undefined): value is T {
return value !== undefined && value !== null
}
const arr1 = [1, 2, null, 3]
const arr2 = arr1.filter(isNonNullable)
Пример 2:
Написать хелпер, который может из любого интерфейса достать поля определенного типа:
type Project = {
name: string
description: string
start_date: Date
end_date: Date
}
type ProjectDates = PickByType<Project, Date>
// {
// start_date: Date;
// end_date: Date;
// }
type ProjectInputFields = PickByType<Project, string>
// {
// name: string;
// description: string;
// }
Решение
type PickByType<Target, Condition> = Pick<
Target,
{ [Key in keyof Target]: Target[Key] extends Condition ? Key : never }[keyof Target]
>
Решение занимает пару строк и пару минут времени. Если кандидат не справляется - пока ничего страшного, идем дальше. Но если справляется - скорее всего перед вами настоящий технарь, который копается в технологиях глубже чем большинство. Хороший знак.
Практические задачи
Существует много хейта в сторону leetcode-задач. Основная претензия - нерелевантность реальным задачам на работе. React-разработчику не нужно знать алгоритмы и т.п. С алгоритмами история отдельная - ты их либо знаешь либо нет, и это действительно не самый лучший показатель для найма. Но если задача универсальная и не требует каких-то специфических знаний кроме знаний языка - это как раз то, что нужно для объективной оценки software-инженера. Причем, как hard, так и soft-навыков. Помимо программирования, кандидат демонстрирует навык обработки и уточнения требований к задаче. Быстро ли он сдается, если что-то не получается. Проявляет ли он раздражение при этом или самоиронию. Все это не менее важно чем скорость и корректность написанного кода.
Я обычно начинаю с задачки на логику, без программирования. Например - Какой угол составляют часовая и минутная стрелка в 15:15? Отличный способ размяться для кандидата и настроиться на практическую часть интервью. Задача совсем не про программирование, но на практике, те кто ее заваливает, так же не блещут и в следующих задачах с кодом. Далее начинаем писать код и постепенно повышаем сложность. Пользоваться гуглом в процессе разрешается.
Задача #1
Реализовать функцию reduce() из стандартной библиотеки JS.
Не должно занимать много времени. Если закапываемся на этом месте - можно досрочно завершать интервью и сэкономить всем полтора часа времени.
После успешной реализации, прошу затипизировать функцию как в стандартной библиотеке TypeScript с выводами типов аргументов и результата. Еще одна проверка на экспертность в TS. Так же не является приговором если человек не справится.
Задача #2
Реализовать функцию throttle() из lodash. Можно без третьего аргумента, чтобы сэкономить время.
Хороший знак, если программист сразу видит решение через рекурсию, а не спустя 30 минут тщетных попыток покрыть все кейсы дополнительными флагами и условиями в коде.
Задача #3
Выполнить code-review уже реализованного, адаптивного React-компонента. Найти проблемы и отрефакторить.
В отличие от предыдущих, данная задача максимально приближена к реалиям. Для меня очень важно под каким углом человек анализирует код на ревью. Если он фокусируется на code-style, названии переменных, замене if/else на тернарный оператор - это скорее тревожный звонок. Синьйор в первую очередь должен найти концептуальную ошибку в данном коде. Если просто представить как мы будем использовать этот компонент в реальном приложении, станет очевидно, что интерфейс компонента некорректный и его нужно полностью менять.
Как всегда, задача со звездочкой - затипизировать компонент как можно универсальней для compile-time на TypeScript.
System design
Опциональная секция. Имеет смысл обсуждать если практическая часть пройдена уверенно.
У frontend-разработчиков я обычно прошу спроектировать небольшое React-приложения, описать его структуру и выделить слои для разделения логики. В React-мире нет какой-то канонической архитектуры, скорей наоборот. Поэтому настоящего синьйора/архитектора определить довольно просто. Если он решает любую задачу по шаблону как в туториалах: компоненты + хуки + Redux - это точно не он. Опытный программист уже видел проекты, которые писались по такому шаблону и у него должен сработать инстинкт самосохранения. Настоящий инженер при проектировании не ищет самый короткий путь как реализовать исходные требования, т.к понимает, что это лишь отправная точка, а, в первую очередь, старается создать благоприятные условия для дальнейших изменения в проекте для себя и коллег по команде. В первую очередь он хочет спокойно спать по ночам при добавлении новой фичи в проект и не гадать, какие модули он мог случайно задеть в процессе.
Когда я собеседовал Golang-разработчиков, просил спроектировать бэкенд архитектуру для сервиса с котировками акций, в который будет ходить фронтенд для отрисовки realtime-графиков. Принцип тот же самый: по туториалу такую задачу не решить, только на опыте.
Понимание agile-процессов
Секция так же опциональная. Актуально для компаний где эти процессы есть)
Для таких компаний при найме будет полезно обсудить на берегу с кандидатом, насколько он готов играть по четким правилам и насколько он командный игрок. Есть такой тип инженеров, которые считают любые процессы лишней бюрократией и всячески пытаются их избежать. Вместо этого они хотят писать код без оценок и сроков, по принципу: когда сделаем - тогда сделаем.
Для моей компании процессы и сроки были очень важны, поэтому я прощупывал этот момент на собеседовании. Помимо матчасти про Scrum/Kanban, можно попросить рассказать детально весь цикл разработки от оценки до релиза на прод на текущем месте работы. Очень важно, чтобы горизонт разработчика не ограничивался мержем ветки в master и он понимал весь жизненный цикл разработки продукта.
Продаем кандидату нашу вакансию
Если мы дошли до этого этапа - значит все хорошо и мы скорее всего будем делать человеку офер. Теперь наша задача - повысить вероятность того, что он его примет. На самом деле мы уже многое для этого сделали: подготовились к интервью, провели его по четкому плану без заминок и неловких пауз, порешали(успешно!) вместе интересные технические задачи - это всегда дает позитивный заряд.
Осталось рассказать про вашу команду и проекты, делая фокус на том что вас выделяет на фоне остальных. Например, у вас передовые технологии: k8s / GRPC / CI/CD / e2e-тесты / screenshot-тесты / micro-frontends / module-federation и т.д - большой плюс. Если у вас по-настоящему крутые процессы - расскажите про это. Мало у кого они есть. Если у вас подобралась звездная команда - используйте это как рекламу. Люди тянутся к тем у кого можно чему-то научиться.
Но главное - вы сами на протяжении всего интервью должны быть рекламой вашей компании. Нужно показать, что вы компетентны, но не душнить. Задавать сложные вопросы, но на легкой волне, не напрягая излишне обстановку. Не стоит сидеть 3 часа с серьезным лицом и гонять человека по списку вопросов как на экзамене. Харизма, чувство юмора - все можно пустить в ход если для вас это естественно в обычной жизни. Будет лучше, если кандидат в вашем лице увидит живого человека, с которым он с удовольствием пообщался бы после интервью. А не профессора, от которого хочется убежать как только получил зачет.
Заключение
Пишите в комментариях, если интересно продолжение цикла статей. Делитесь своим опытом и подписывайтесь на канал в Telegram.

