Сценарий найма на работу и проведения собеседования разработчика/руководителя группы в наш проект


Вступление

Смысл этой заметки в том, чтобы не забыть все те глубины и скрытые смыслы, которые были выявлены в результате проведения интервью разработчиков на протяжении нескольких лет. Записано по памяти в 2016 году примерно через 2 года после проведения последнего собеседования. То есть что-то могло потерять свою актуальность, что-то могло забыться. Диалоги и их ветвления приведены не полностью, а так чтобы в нужный момент при необходимости всплыть в моей памяти.

Вакансия это junior, senior, team-lead/заместитель руководителя отдела с опытом разработки на php. Собеседования C#-разработчиков, а так же frontend-разработчиков здесь не затрагиваются.

Статистика:

  • Просмотрено резюме: около 1000
  • Проведено собеседований: более 100
  • Взято на работу: около 30
  • Отказалось от оффера из тех, кого было прям реально очень хотелось взять: пара человек
  • Уволено: пара человек

Статистику восстановил по памяти и поиском по почте так что за достоверность не ручаюсь, но порядки точно верные.

Как кандидат превращается в сотрудника. Этапы:

  1. Знакомство с резюме кандидата;
  2. Собеседование с HR;
  3. Собеседование со мной;
  4. Собеседование со службой безопасности;
  5. Собеседование с руководителем департамента.

Обычно в один день проходят этапы 2 + 3 + 4. То есть в офис успешному кандидату приходится приезжать два раза. Если в один день не удалось совместить 2 + 3 и 4, то будет совмещено 4 + 5.

Как кандидат превращается в сотрудника. Знания и информация:

  1. Резюме по email;
  2. Вопросы по email (опционально);
  3. Звонок/email о встрече;
  4. Технический тест (опционально);
  5. Технические вопросы;
  6. Приглашение на работу.

Дальше рассмотрим более детально в том числе с описанием скрытого смысла каждого из вопросов.

Знакомство с резюме кандидата

Ничего особенного. HR находит по своим каналам резюме кандидатов. Присылает их. Я насколько можно оперативно обрабатываю и посылаю ответы:

  1. Кандидат очень интересен, приглашаем как можно скорее;
  2. Кандидат интересный, но по резюме есть вопросы которые хорошо бы задать по email;
  3. Резюме не дает представления, но есть шанс, задаем стандартные вопросы;
  4. Кандидат не подходит, но стоит вернуться к нему через пару лет;
  5. Кандидат не подходит совсем.

Очень важно сопровождать свои ответы и решения комментариями на всех этапах. HR занесет это в базу данных и тогда будет легче вспомнить почему год назад ты решил этому кандидату даже не дать шанс ответить на вопросы по email. 🙂

По пункту "2" — по договоренности с HR если кандидат не отвечает на вопросы по email в течение пары дней, то с ним связываются чтобы уточнить про вопросы и пригласить на встречу. Очевидно кандидат не сидит на месте, ходит по другим собеседованиям и в ситуации когда работодатель всеми силами пытается найти работника нет смысла сидеть и ждать, нужно быть активным.

Стек  вопросов которые отправляет HR по email следующий.

Основные вопросы:

  1. Приходилось ли работать с высоконагруженными web-проектами? Если да, то опишите основные на ваш взгляд характеристики этого проекта.
  2. Знакомы ли с шаблонами проектирования (design patterns-GoF)?
  3. Как вы считаете, какой у вас уровень владения PHP по 10-балльной шкале.
  4. Занимались ли написанием unit-тестов? Если да, то какое покрытие тестами считаете необходимым?
  5. Оцените свой самый большой web-проект.
  6. Сколько было написано своих собственных классов для исключений в самом большом web-проекте.
  7. Перечислите 5 вещей с которыми вы еще не работали, но было бы интересно изучить и поработать.

Вариации этих вопросов:

  1. Вам приходилось работать с высоконагруженными web-проектами.  Опишите основные на ваш взгляд характеристики этого проекта.
  2. Какие именно шаблоны проектирования приходилось использовать (design patterns-GoF)?

Дополнительные вопросы:

  1. Каким образом осуществляется поиск "узких мест". TOP5 самых эффективных оптимизаций, которые были использованы.
  2. Какие из перечисленных языков программирования и технологий были применены в коммерческих проектах.
  3. Что бы вы ни за что не стали хранить в memcache?

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

Вопросы задаются примерно 75% кандидатов.  Без этих вопросов они просто отсеивались бы по плохому резюме. Но не все умеют составлять хорошее резюме. А так у человека появляется шанс показать свои навыки общения, умение вникнуть в вопросы некоторые из которых специально составлены нечетко, показать свои аналитические способности и умение разбираться и вникать в эти нечетко поставленные мини-задания. Это потом будет большим плюсом при работе над общими задачами. 

Самые интересные вопросы это 1 и 5. Специально не даются критерии. Идеально если кандидат сам их придумывает и присылает несколько вариантов с уточняющим вопросом возможно имелась ввиду какая-то другая характеристика. Хуже если человек отвечает на все остальные вопросы, а на этот пишет "Как оценить?".

Например проект в вопросе 5 можно оценить десятком разных способов, вот самые очевидные из них: ********

У меня нет матрицы где я бы ставил "+" или "-" за каждый названный вариант, имеет значение то, как кандидат пытается решить поставленную ему задачу и пытается ли. Безусловно тут нужно учитывать то, что у кандидата есть другие собеседования, а скорее всего и пока еще основная работа и у него может не быть времени или желания ответить на вопрос подробно и развернуто. Поэтому решение о продолжении общения принимается на уровне интуиции.

Однако если резюме человека было плохим, на вопросы получены ответы типа: "1. нет; 2. нет; 3. 9; 4. нет; 5. как оценить?; 6. 0; …", то такому кандидату отказывают на этом этапе.

Если видно отсутствие опыта, но при этом видны заинтересованность, аналитические способности, то кандидат будет или отложен на "через год" или в случае профильного вуза/специальности или интересного опыта он может быть приглашен. Да, да, приглашен не смотря на то, что скорее всего он не подойдет. По той простой причине, что мы не в вакууме и те, кто сейчас закончил вуз и пока мало что знает, через 3 года могут стать уже вполне себе профи и то, в какую область web-разработки он пойдет, на кого будет ориентироваться, имеет огромное значение. Я сейчас потрачу 2 часа времени, кандидат уйдет с пониманием того, что он не знает совсем, в чем он сильный, над чем именно нужно поработать, и через 2 года придет к нам сформировавшимся специалистом, а не будет тухнуть эти два года в какой-нибудь веб-студии где будет методом copy-paste делать сайты-визитки. Ну или есть шанс, что он окажется настолько подающим надежды, что мы его возьмем не смотря на отсутствие опыта.

Собеседование с HR

За все время было только несколько собеседований с HR на которых я присутствовал, поэтому ничего интересного тут сказать не могу. У каждого HR свои наборы вопросов по которым они дополняют портрет кандидата. Обычно в завершение своей части HR  оставляет кандидату листик с техническим тестовым заданием и оставляет кандидата одного, чтобы не давить присутствием. В это время созванивается со мной чтобы описать кандидата, рассказать как прошла эта часть общения.

Через 10-15 минут HR забирает тестовое задание, сверяется с табличкой ответов и снова созванивается со мной, чтобы обсудить насколько хорошо кандидат справился с тестом. В 95% и если кандидат показал в целом вменяемость, ответы на тест ничего не решают. Я лично сам не люблю, когда меня заставляют на собеседовании отвечать на какие-то вопросы в виде теста. Однако тест позволяет отсеять какое-то количество совсем-совсем-совсем нулевых кандидатов, которые тем не менее на вопросы по email ответили неплохо.

Собеседование со мной

Захожу, представляюсь, без озвучивания должности, сообщаю что это техническая часть собеседования, предлагаю перейти на "ты". На столе обычно лежат листики с резюме кандидата с пометками от HR и тест с пометками от HR о совпадении ответов с заранее присланными. Говорю: "так, это у нас тест", и делаю на пару секунд паузу, чтобы кандидат мог высказать или показать свое отношение к тесту. Если реакция требует комментария и разрядки атмосферы, то сообщаю что я сам ненавижу тесты и смысл теста на самом деле совсем в другом, но что к этому мы еще вернемся.

После этого разом вываливаю на кандидата серию вопросов примерно так: "Расскажите о себе, чем занимаетесь, на какой версии php начинали писать и на какой пишете сейчас и вообще нравится ли вам php как язык, что хорошего и самое интересное что в нем плохого, чего не хватает!?".

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

Были кандидаты, которые из двух одновременно заданных вопросов могли ответить только на первый, совершенно забывая про связанный второй. Важно вывалить сразу, чтобы посмотреть на какой из вопросов человек начнет отвечать первым. Это может быть первый, это может быть самый каверзный, это может быть самый легкий или самый сложный и т.д. и все это будет иметь значение при принятии решения. Ведь цель этого собеседования не только понять насколько знания кандидата соответствуют требованиям, но и оценить его как личность, попытаться увидеть сильные и слабые стороны, раскрыть его и понять как он будет работать если уже завтра выйдет в офис. И конечно, заинтересовать его в работе именно у нас. Поэтому все общение построено в максимально дружелюбной атмосфере не смотря на такие "выпады". 

Если кандидат в процессе ответа забыл какой-то из вопросов, то я его напоминаю.

Рассмотрим каждый из вопросов подробнее и о смысле который за ними кроется.

"Чем занимаетесь и о себе"

Общий вопрос который передает инициативу в руки соискателя. Дает шанс рассказать о себе так как кандидат это уже делал ни один раз. Послушать его заготовленную и отполированную историю. 

"Версия  php"

Вопрос с продолжением и двойным дном как и большинство всех вопросов, которые будут задаваться дальше. Тут интересно понять насколько давно кандидат начал пользоваться языком и достаточно ли актуальная версия php используется им сейчас. Если не актуальная, то почему. Почему не мигрировали. Кто принимает решения. "Злые админы" или "бизнес"? Почему не попробовал в личном проекте более новую. Знает ли что появилось и что теряет из-за отсутствия перехода. Следит ли за версиями вообще. Знает ли что появилось в той версии, которой пользуется. Все ли возможности этой версии применяет и т.д.

Если выпадает возможность, то говорим более детально о некоторых возможностях языка. А именно.

Namespaces

Для чего они были придуманы. Какую проблему они решают и решают ли они ее в реальности. Были ли примеры решения проблемы до их появления.

Хочу услышать мнение про стандартизацию именования, про то что в PEAR или других библиотеках были префиксы имен классов, про то что есть use для упрощенного написания. Про боль рефакторинга даже в современных IDE т.к. через cut/paste код уже нельзя перенести в дугой файл. Про наличие соглашения в текущей команде по тому как именно они используются. Плавно затронуть наличие code-style. 

Анонимные функции

Пользуется или нет, в чем разница между тем что было раньше и что появилось в 5.3.

Хочу услышать что знает про передачу аргументов через use, а не только как параметр функции. Увидеть понимание во что превращает эта конструкция (в отдельный класс). Если нужно, то даю наводящую задачу: "Есть массив с числами, вам нужно обязательно с использованием array_filter отобрать только те значения, который больше N. Сама N это не константа, а в метод где у вас будет вызов array_filter приходит как аргумент". Ожидаю что кандидату это поможет вспомнить про use. Вне зависимости от этого предлагаю решить на php 5.2 когда такой возможности еще не было. Если кандидат теряется, то предлагаю найти любое решение, пусть некрасивое и ужасное. Цепочка вариантов от худшего к лучшему: ********

Позднее статическое связывание, генераторы и т.д.

Обычно пропускаем. Если только кандидат сам не назвал, тогда очень быстро обсуждаем суть и идем дальше.

"Нравится как язык и какие минусы"

Один из трех ключевых вопросов всего собеседования. Если кандидат чувствует себя неуверенно и стесняется или не понимает, что я подразумеваю под минусами, то говорю, что это что-то что заставило вас потерять время на дебагинг того, что вы думали будет работать. Или что-то из-за чего постоянно приходится запускать help и т.д. Говорю сейчас или позднее ключевую фразу "Код нужно писать так, чтобы минимизировать его неправильное использования. Хороший код — это который сложно использовать неправильно." в данном случае в контексте того что в php слишком много нелогичностей и нестыковок.

Выписывать их тут смысла нет, чем больше кандидат назовет вещей, тем лучше. Отсутствие таких минусов скорее всего говорит о слишком маленьком практическом прикладном опыте работы с языком. Отсутствие опыта сравнения с другими языками тоже не является плюсом т.к. плохо если человек знает только один язык и это php (есть же JavaScript в конце-концов).

Плюсы тоже должны быть названы, потому что если только одни минусы и нет плюсов, то возникает вопрос почему соискатель вообще на нем пишет тогда. 🙂 

Давайте более детально поговорим о самом php

Иногда первая часть вопроса занимает достаточно времени поэтому не все что будет идти ниже задается в обязательном порядке, про что-то я могу забыть спросить (я прихожу с листиком-подсказкой но не заглядываю в нее чтобы поддерживать живое общение, а не быть роботом читающим по бумажке).

"В тесте вы сказали что == быстрее/медленнее === … почему? И кстати какой вариант в своем коде вы используете чаще? "

Холиварный вопрос, который позволяет на такой незначительной теме очень много понять о кандидате: глубине его знаний в плане того, как происходит работа с переменными, что есть типы и приведение типов и что приведение типов не бесплатная операция, супер-круто если есть понимание про то как это сделано в php.

Во сколько раз одна операция тяжелее другой. В 2 раза, в 5, в 100? Ожидаю услышать, что зависит от того, что будет сравниваться и что === не медленнее. Разбираем детали. Если кандидат не понимает или настаивает на неправильном ответе без обоснования, то в качестве подсказки предлагаю сказать сколько будет неких базовых операция сделано интерпретатором php при выполнении двух сравнений.

123 === '123'

123 == '123'

Ожидаю услышать, что во втором случае будет кастинг строки в число, а не обратно. Что в первом будут сравнены типы и т.к. они отличаются то сравнения значений не будет. Во втором случае будет кастинг или услышать про zval (идеальный вариант, за все время не больше 5 кандидатов его назвали). Услышать что кастинг строки в число не такая элементарная операция и ее алгоритмическая сложность зависит от длины строки. Предлагаю на пальцах придумать алгоритм перевода строки с цифрами в целое число. Красота алгоритма значения не имеет. Если кандидат не может сообразить, то даю от балды число с 7+ цифрами на бумажке и прошу назвать его типа "тридцать три миллиарда пятьсот один". Если эта "подсказка" не помогает, то говорю что "ну ладно, мы слишком задержались на этой задаче, давайте дальше".

"Отсылка к тесту на первые два задания"

Очень быстро мимолетом говорю правильно или нет был дан ответ и почему. Если неправильно, то говорю что это вообще не важно. По ситуации делаю замечание, что тест устарел. Внимательно наблюдаю за реакцией кандидата.

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

"Назовите все "ключевые слова" которые можно использовать при описании метода класса"

Ожидаю услышать все уровни видимости в php плюс static, final, abstract. Предлагаю расширить список языков и назвать что-нибудь из других типа C++/Java/C# если такие модификаторы или языки известны. 

Задаю дополнительный вопрос "хватает ли этих уровней видимости вам и может быть в других языках встречались с другими". В идеале ожидаю услышать, что не хватает уровня видимости внутри namespace аналог которому есть в Java/C#.

Элементарный мимолетный вопрос в продолжение "В чем разница между public/protected/private методами". Если кандидат не отвечает на этот вопрос и провалил обсуждение быстрее/медленнее, то скорее всего я задам еще пару-тройку вопросов и закончу собеседование. 

"Можно ли объявить конструктор класса как protected? Имеет ли это смысл и как тогда создать экземпляр такого класса? "

Очередной элементарный вопрос на который к несчастью много неправильных ответов. Обычно вне зависимости от ответа на нем не останавливаемся и идем дальше.

"Задача A на создание экземпляра класса с наследованием"

Даю заранее напечатанную бумажку с двумя классами. Объясняю условия и прошу рассказать в каком порядке происходит по мнению кандидата создание экземпляра класса. Если, а чаще всего это так, рассказ неточный, то на ходу добавляю echo $this->… в код на бумажке в разные места, зачеркиваю конструктор и спрашиваю что будет выведено.

Задаю дополнительный вопрос "Понятие виртуального метода. В чем разница. В php какие методы виртуальные? " с вариацией "Знакомо ли понятие виртуального конструктора и в чем состоит проблема". Если кандидат показывает, что знает, то запускаю идентификацию свой-чужой на классическом примере кода на C++ где в одном случае метод виртуальный, в другом не виртуальный и к чему это приводит. Рассказываю историю из жизни про то как я на себе прочувствовал отсутствие виртуальности у конструкторов в C++. Мимолетом замечаю, что в этом понимании в php есть только конструктор по умолчанию, а метод __construct не просто так считается магическим как __get/__set и фактически это инициализатор.

"Задача B мозговой штурм по поиску различных решений"

Даю задачу с заранее напечатанного листика суть которой сводится к тому что нужно назвать как можно больше разных вариантов вывода массива на экран в php. Сопровождаю это красивой легендой что вы находитесь в тылу врага, перед вами консоль, вы понимаете что это php и секретные данные находятся в массиве $a — это просто набор цифр, вам нужно чтобы они оказались просто на экране в любом виде. То есть нужно написать функцию которую вы вызовите и которая на вход принимает массив $a и выводит. Но php очень сильно "урезанный" и тех методов которые вы будете называть скорее всего в нем нет. Но каждый названный вариант будет засчитываться положительно. И есть один вариант который вам нельзя будет запретить.

Ожидаю услышать в ответ на это всевозможные способы вывода на экран начиная с printr_r и var_dump, продолжая самописными циклами и вызовами итерирующих функций типа звучавшей ранее array_filter, заканчивая экзотическими типа сгенерить Expection и увидеть в распечатке stack trace. За все время собеседований накопилось порядка 18 разных вариантов: ********

Мега-круто если человек не просто назовет идеальный вариант, но и скажет сокровенную фразу, что ********. Если идеальный вариант не называется, то шутливо предлагаю в фоновом режиме подумать над решением, а пока перейдем к другому вопросу.

"ООП: ключевые понятия своими словами. Объяснить нам как для junior developer. "

Переходим к более общим вопросам. Прошу назвать основные понятия ООП так как про это пишут в книжках. Сначала просто перечислить, не рассказывая про суть. А потом прошу объяснить их своими словами, не заученными определениями что они означают на пальцах, словно как для junior developer. В роли junior буду я и я буду задавать свои глупые встречные вопросы если мне что-то будет не понятно.

Инкапсуляция. Выслушиваю объяснение. Задаю вопрос: я написал код и переживаю что он не соответствует одному из принципов ООП и из-за этого он не "тру"-ООП. Как мне убедиться так этой или не так. Если не получается, то спрашиваю как мне явно нарушить этот принцип. Что сделать и как так написать код, который его нарушает.

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

Наследование. Выслушиваю объяснение. Очень часто кандидаты при объяснении используют слово "наследует". Обращаю внимание на то что получилась рекурсия и прошу объяснить без этого слова.

Задаю вопрос: я как junior правильно ли понимаю что если у меня есть класс A в котором есть методы m1 и m2 и я хочу создать наследника класс B, то ключевое слово extends и то что делает за нас php при этом я бы мог заменить на copy-paste методов m1 и m2. А с помощью хуков на git, например, сделал так, чтобы эти методы при изменении в классе A копировались бы в класс B. А для разработчиков напишу прямо вверху в комментарии, что класс B унаследован от класса A. И что так даже получится удобнее: можно расширять поведение метода добавляя код в середину метода в классе B. Для чего в классическом наследовании придется дробить метод класса A на два.

Обычно тут все смеются с одной стороны находчивости с другой стороны рукожопности этого junior. Но в итоге правильно схватывают суть вопроса далеко не все. Приходится какое-то время пытать: чего же в таком "наследовании" не хватает. Конечно я ожидаю услышать, что не хватает связи между классом A и B которая будет понятна интерпретатору. Как примеры: ********

Полиморфизм. Самое сложное для объяснения junior. Обычно называется пример, который сложно пощупать и понять. Предлагаю перейти на фигуры и метод вычисления площади. Я ожидаю пример типа есть фигура, есть круг и есть квадрат. В фигуре определен метод площадь который умеет ее считать для любой фигуры, но для круга и квадрата метод переопределен на более эффективный по школьным формулам. Вот с этой частью справляются почти все. Хотя некоторые не говорят про то, что в базовом классе метод тоже определен, хотя это и не принципиально, но упрощает понимание т.к. разница очень тонкая. И вот в тот момент когда мы работает с массивом фигур (!) часть из которых фигуры, часть круги и квадраты и не зная что за объект дергаем метод вычисления площади, то интерпретатор за нас решает что если это круг, то будет вызван метод Circle->square, а не Figure->square. Как вариация более понятная php-разработчикам это когда в метод передается через "тайпхинтинг" фигура, а в реальности передаются круги и квадраты.

Если эта деталь опускается, то упираюсь и настаиваю на том, что ничего удивительного, что если у нас есть круг и мы хотим посчитать площадь, то метод вызовется у круга, а не квадрата. То есть суть полиморфизма в том где находится условный "switch-case" в коде или внутри интерпретатора/компилятора. 

В идеале ожидаю услышать замечание, что полиморфизмов есть несколько типов и полиморфизм наследования лишь один из них.

"public vs private + final"

Иногда задаю этот вопрос после задачи A. Смысл в том, что при написании члена класса руки кандидата напишут private или protected который не нужен снаружи? Это еще один из ключевых вопросов т.к. он позволяет раскачивать кандидата в разные стороны.

Я ожидаю осознанной позиции не важно это будет private или protected. Если ее нет, то предлагаю подумать и занять.

А дальше я встаю в оппозицию этому мнению! Если человек выбрал protected, то напоминаю про принцип, что по умолчанию все должно быть закрытым и открываться по мере необходимости. Мол осознанно ли этот принцип нарушается или нет. Известен ли он кандидату. Если человек выбрал private, то тоже говорю про принцип чтобы оценить кругозор. И на примере объясняю почему это плохо в реальном проекте и для использования, например, $logger  в наследнике придется менять сигнатуру родительского класса на пустом месте только потому, что при написании его $logger был закрыт как private. Если человек настаивает, то привожу еще примеры. Что на самом деле $logger был передан через конструктор такой вот dependency injection. А значит им управляет наследник и может при желании передать все что захочет своему родителю, так зачем мы от него прячем то что он в нас передал? Что никто не помешает при написании наследника сохранить его тогда в $logger1 и дергать его, но это же некрасиво. Или не дай бог он напишет в классе-наследнике private $logger тем самым php создаст нам два члена класса с одним именем один из которых будет использоваться в контексте наследника, а другой в контексте родителя. И спасет нас только то, что это будет один объект из-за того что они передаются по ссылке. А если это будет массив, да еще и изменяемый классом то мы будем работать с разными переменными в зависимости от того в родителе или наследнике определен/переопределен метод?

И как только он меняет позицию я прошу придумать пример когда не смотря ни на что — все равно имеет смысл делать private. Тут не столь важно как человек ответит и сможет ли он в такой ситуации придумать решение, важно как происходит борьба и отстаивание своих позиций, есть ли они. Умеет ли находить аргументы, спокойно ли реагирует?

Идеально если при этом всем человек дает на завершающий вопрос вариант: выкладка библиотеки в open source или передача в использование так, что Refactoring->Rename уже не дотянется до всех потребителей и нам помимо публичного интерфейса класса придется поддерживать protected интерфейс библиотеки ведь никто не запретит унаследовать от чужого класса. Более того иногда это может быть хорошей практикой вместо прямого использования чужих классов у себя.

Тут прицепом идет вопрос про final для классов или методов. Рассуждения аналогичные и завершающий вопрос такой же: в каком случае есть смысл делать final. Тут я ожидаю услышать вариации на тему внутреннего продуманного API через наследование. Как пример метод HttpRequestHandler->handle который объявлен как final, но внутри него идут вызовы abstract методов которые можно/нужно переопределить в наследниках чтобы менять поведение. 

"Задача про поиск в массиве"

Раз уж мы вернулись к коду, то предлагаю вспомнить массив который мы пытались вывести на экран. Интересуюсь с улыбкой удалось ли в фоновом режиме найти тот самый идеальный ответ на задачу. Если ответ найти не удалось, а конечно это так ибо при таком разговоре никакого фона на подумать быть не может, то говорю, что ничего страшного и давайте мы просто оставим вам это задание на дом. Уверен, что как только вы выйдете из этой комнаты все ответы сразу же сами появятся в голове. 

Новая задача заключается в том, что вам тимлид поставил следующий task в Jira: есть массив с числами, не вложенный, плоский. Нужно написать функцию, которая получает массив $a на вход и переменную $b и вернет true, если  она в массиве есть и false, если ее в массиве нет. Задача в Jira оценена им в 1 час, и сейчас он недоступен 2 часа т.к. ушел на собеседование, задать вопросы вы не можете, но задачу сделать нужно. Как будете ее решать.

Это очередная задача с двойным дном, на проверку того, как кандидат работает с неточными входными данными. Будет он пытаться понять того, кто ему ставил задачу или нет. Очевидно что в задаче не хватает чего-то важного. То есть здесь я ожидаю получить от кандидата некое взвешенное дерево разных вариантов почему такая задача могла появиться и какие от него ожидаются решения. Особенно с учетом оценки задачи в 1 час. То есть очевидно это не просто return in_array($b, $a);

Подталкиваю кандидата при необходимости к тому почему это не может быть in_array, или почему все-таки может быть in_array (callback-итерфейс, фильтраторы и т.д.).

В итоге приходит к тому что дело должно быть в эффективности поиска. Говорим про алгоритмическую сложность in_array и прямого перебора. И в случае с числами какие знания о массиве могли бы нам упростить задачу. Тут две основных ветки: изначально сортированный массив или поиск в одном массиве разных значений много раз.

Выбираем отсортированный массив. Жду ответа что искать нужно бинарным поиском. Проверяю понимание логарифмической зависимости на примере сколько нужно итераций для поиска в массиве из 100 элементов и из 1000 элементов. Идеально тут если человек знает степени 2. Очень хорошо если зная что для 10 это будет 7 находит для для 1000 это будет не заново деля 1000 пополам и т.д., а умножая 100 на два и так далее. Но даже если посчитал на пальцах — тоже нормально, мы же не математика ищем 😉

И дальше перехожу ко второй части проблемы. Говорю что да, в задаче было забыто, что речь про сортированные массивы и необходимость отдельной функции эффективного поиска в нем. Так вот вы написали супер-эффективный поиск элемента в сортированном массиве. Но если туда передать несортированный массив, то функция будет скорее всего ошибаться. И вам нужно защитить эту написанную вами функцию super_in_array от того, что другие разработчики смогут ее неправильно использовать. Будут передавать туда несортированный массив. Как защититься без потере эффективности этой функции на production? Говорю что это мозговой штурм и можно называть любые даже глупые варианты. Я каждый вариант буду оценивать и говорить +5% или +20% к защите и наша задача набрать как можно больше, а в идеале приблизиться к 100%.

Ожидаю услышать две линии защиты. 

1.Метаданные/знание

Что метод будет переименован, что разработчик расскажет всем на пятиминутке, что есть такой метод и туда можно передавать только отсортированные массивы, что у метода будет phpdoc который говорит про это и т.д….

2.Код

Что в коде будет проверка граничных условий на каждой итерации, что будет проверка первого и последнего элементов на возрастание, что можно добавить проверку log(count($a), 2) случайных элементов в массиве.

Еще важный момент в реакции, которая будет у кода, если массив окажется не отсортированным. Я ожидаю что это будет exception, а не попытка сортировки с поиском в нем (в этом случае задаю вопрос про алгоритмическую сложность самого эффективного алгоритма сортировки) или переход на in_array. Хотя тут есть варианты с логированием, но тут уже без контекста использования метода нельзя об этом рассуждать.

И в идеале получаю ко всему предложенному и ответ про использование механизма assert, который позволяет делать любые проверки в debug режиме и которые не будут выполняться в prod режиме.

"Что такое join, какие виды знает"

Переходим к базам данных. Совсем по-быстрому. Обычно не знают full outer join. Если при объяснении рисовали табличку того, что получается при разных join, то показываю что такое full outer join.

Спрашиваю насколько монструозные запросы приходилось писать самому, сколько там было join, in, exists, подзапросов. Это подводка к вопросу: а теперь оно тормозит, ну как тормозит, медленно работает допустим 1 секунду, но этот запрос на главной странице вашего проекта. Как будете ускорять? Иногда если время позволяет говорю что это главная страница проекта где у вас выводятся 10 последних постов join автор поста, count подзапрос на количество комментариев к посту и count подзапрос на дату последнего комментария поста. И предлагаю решить любым способом эту задачу, ну кроме варианта вместо реляционный базы данных использовать Redis, например.

Ожидаю что в первую очередь будет назван просмотр плана запроса, анализ наличия и использования индексов. Выяснение что же именно тормозит в запросе и когда я подвожу к тому что это те самые count то сценарий может пойти по нескольким путям.

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

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

Если назвал базу и триггеры, то предлагаю придумать вариант, когда он заходит в такую базу, бац, а создать триггер не получится. Почему это может быть? Ожидаю ответ,  что ********.

Когда говорим про приложение, то очень важно будет ли это делать в транзакциях или нет. Опять же вокруг транзакций дилог строится на том что из-за поддержания счетчика иногда транзакция вся откатывается (0.1% случаев). Заставит ли это отказаться от транзакций или нет. В общем получается очень интересная беседа приближенная к реальной практике.

"Отсылка к тесту на задачу про null"

Прошу рассказать что такое null, какие особенности работы с ним. Часто бывает что у кандидатов нет понимания что это такое. Задаю вопрос: "У вас есть табличка в колонка с и половина там null, а половина числа. Как вы напишете запрос чтобы выбрать те записи которые null". Дальше в зависимости от ответа на вопрос и задачу немного по-разному строю диалог, но обычно даю четкое определение что такое null с точки зрения математической логики и СУБД. А именно: "У нас есть двоичная логика когда есть true и false и больше ничего нет. А есть нечеткая логика когда есть true, false и неопределенность. Так вот null это и есть та самая неопределенность и обычный операторы как бы не умеют с ним работать они просто не понимаю что перед ними. Поэтому был добавлен is null". Иногда делаю акцент, что это не отсутствие значения, а неизвестное нам значение (которое может оказаться чем угодно). Прошу заново ответить на вопросы теста, но только усложняю и прошу не просто отметить вариант в котором ответ null, а написать true, false, null в зависимости от того какой ответ будет, и прошу попытаться использовать только что полученное знание.

Если кандидат напряжен, то говорю что когда я придумал это задание и показал нашим DBA, они не ответили правильно и что я сам на собеседования ходил с бумажкой с ответами (показываю бумажку в которую никогда не смотрю) пока не придумал как наглядно представить что такое null. Если не напряжен, но было много неправильных ответов, то тоже это рассказываю. 🙂

После чего говорю про то как нужно представлять себе null чтобы перестать с ним путаться. И что в задаче в тесте есть пункт f на который я сам до сих пор отлично зная про null наступаю периодически. Я говорю, что нужно представить null как ********. … Вы ответите "не знаю". Это и есть null.

И так проходим по каждому пункту задачи. Все соглашаются с тем, что предложенный вариант интерпретации null очень лаконичный и понятный. Отмечаем наличие искры в глазах кандидата от того, что он наконец-то реально понял про null. 🙂 

"Отсылка к тесту на задачу про выгрузку из базы"

Снова включая воображение кандидату рассказывая что он "фрилансит" и что заказчику нужен запрос для его базы данных утром, а сейчас поздняя ночь, заказчик спит и задать вопросы ему нельзя. Но тот запрос, который предложил кандидат за очень короткое время на тест, не учитывает ряд вещей, который если бы он смог выполнить запрос на базе данных заказчика — он бы конечно увидел и понял.

Очень часто задачу оставляю как домашнее задание вместе с выводом содержимого массива, если в ней кандидат назвал слишком мало вариантов или не назвал целые классы решений.

От кандидата я ожидаю что он покажет понимание что: ********

Все это подается в форме диалога с подсказками и попытками переключить кандидата в максимально возможный аналитический режим.

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

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

"Задача C про парсинг валют"

Завершаем на этом общение по базам данных и берем последнюю задачу с заготовленной бумажки. На ней буквально 5 строчек чистого php-кода в которых мы читаем удаленно xml-файл с сайта ЦБ РФ с курсами валют, получаем DOM в котором лезем в нужные NodeList и формируем ассоциативный массив и его возвращаем.

Это задание снабжается легендой, что вам нужно написать класс или функцию которая начнет использоваться остальными ребятами в проекте и прямо сейчас уже есть два тикета которые ждут этого справочника. Первый будет выводить на главной странице вашего нагруженного проекта курсы валют USD, EUR и т.д., а второму нужен текущий курс чтобы начать принимать средства на рублевый счет в долларах и делать конвертацию по текущему курсу. Что вы за 10 минут написали такой вот proof of concept и теперь, наверное, вы хотите его как-то улучшить, чтобы отдать в использование тем двум внутренним заказчикам. Поменять внутри, интерфейс прошу пока не трогать.

Цель этой задачи, в первую очередь, посмотреть каким образом кандидат будет работать с ошибками. Знает ли про Exception. Подходят ли они для использования тут. Вообще что такое исключения, как с ними бороться. Насколько активно использует исключения. В чем плюсы и минусы. Как жить в мире без исключений? Сколько и каких ошибок он будет генерировать и будет ли внутри этого метода. Предложит ли в итоге поменять сигнатуру метода, чтобы написать более предсказуемый код.

Фактически это тест на умение легко выражать свои мысли и решение задач в виде некой библиотеки или набора API-методов. Понимание того, где должна проходить граница и стоит ли все тащить в одно место. Например, нужно ли в этом методе делать кеширование или оно должно быть снаружи и должно ли вообще оно быть. Если разработчик не говорит про Exception, то привожу в пример junior developer который не проверит код ошибки и значение и при зачислении на счет 1000$ в базу запишется 0, т.к. конкретно в этот момент времени сайт ЦБ РФ лежит и мы вернули null/false/0. Приводу пример администратора Яндекс.Почты код которого проверял наличие письма в файловой системе и базе и в случае отсутствия записи в базе удалял файл. Но коннект к базе на dev и prod контуре отличался и поэтому на проде из-за невозможности подключиться к базе метод возвращал всегда false. Хорошо что вовремя заметили повальное удаление файлов.

"Отсылка к тесту на задачу про ошибку в коде"

Если кандидат нервно реагирует на эту задачу — очень хороший сигнал. Говорю что я сам не знал бы, что будет выведено на экран, если бы не запустил этот код и рассказываю истинную причину почему такая задача появилась в тесте. Она для того чтобы отсеивать людей, которым нравится такой код и нравится жонглировать нюансами php.

Быстро перевожу разговор в плоскость что именно плохого в этом коде и предлагаю улучшить. Ожидаю в ответ, конечно, услышать про нечитаемость, про уход от one-liners.

"Отсылка к тесту на задачу с foreach"

Это обычно завершающий вопрос. Тут очень интересно посмотреть на то как человек после выноса мозга с null в базе посмотрит на null в этом php-коде. Ожидаю что скажет что тут null и в базе данных, конечно, разные сущности. По самой задаче прошу поработать интерпретатором php и сказать что он будет делать. Замечаю, что  эта задача возвращает нас в самое начало беседы когда я спрашивал про минусы php. Вот эта задача на знание его нюансов. 

Конечно я не ожидаю того, что человек найдет правильный ответ на эту задачу. Я бы не нашел. Тем более что тут два нюанса. Но очень интересно услышать размышления кандидата, особенно по сравнению с null. Будет ли кандидат в контексте задачи вспоминать про == vs ==== которые обсуждали ранее. Какой из трех возможных вариантов будет назван. 

Рассказываю, что я сам работаю с php больше 10 лет и на момент успешной работы с ним на тот момент времени больше 6 лет наткнулся на особенность массивов и == vs ====, которая как раз в этой задачке. И я потерял на этом несколько часов в попытке понять почему одно не равно другому. Открыл документацию и там красными буквами описано это поведение numeric-ключей массива.

"Задача про распределение фоток по серверам"

Формулируется задача очень просто: вы делаете некий хостинг для фоточек,  у вас 10 серверов с дисками по 3TB. Вам нужно распределять фотографии по серверам равномерно. Как будете это делать.

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

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

"Механизм сессий, как работает. Если отключить cookies, то как информация передается с одной страницы на другую."

Этот вопрос обычно задается только если человек сильно плавает и не показывает глубоких знаний. Просто чтобы оценить вообще насколько человек в курсе того как происходит общение по протоколу http между браузером и сервером.

# Собеседование со службой безопасности

Не могу раскрывать все детали т.к. на этих собеседованиях с кандидатами не присутствовал. А из своего собеседования мало что помню, кроме ярких вопросов типа "Есть ли у вас связи с криминальным миром" и "Как часто вы пьете алкоголь".  🙂

# Собеседование с руководителем департамента

Это финальный этап после чего сотруднику делается "оффер". Или не делается.  После него происходит обмен впечатлениями между всеми, кто общался с кандидатом. На самом собеседовании задается ряд общих вопросов и серия задач на сообразительность. Нет, не про люки. 🙂 

Заключение

Я сознательно не стал включать задачи из теста, а только обрисовал их в общих чертах, чтобы эта заметка не стала совсем уж инструкцией для будущих кандидатов. За звездочками (на самом деле это encrypted блок текста в Evernote и он заменяется на них при синхронизации Evernote и WordPress) я скрыл ответы.

Приходите на собеседование — узнаете и задачи и ответы, иначе будет неинтересно. 😉 

Нашли ошибку? Выделите и нажмите Ctrl+Enter.

Оставьте комментарий

Войти с помощью: 

Ваш e-mail не будет опубликован. Обязательные поля помечены *