Собеседование в Яндекс: театр абсурда :/
Напомню, что в той статье я рассказывал, каким я вижу идеальное собеседование и что я нашёл компанию, которая так и делает — и я туда прошёл, хотя это был адский отбор. Я, довольный как слон, везде отметил, что я не ищу работу, отовсюду удалился и стал работать работу.
Как вы думаете, что делают рекрутеры, когда видят «Alexandr, NOT OPEN FOR WORK»? Правильно, пишут «Алексей, рассматриваете вариант работать в X?» Я обычно игнорирую это, но тут мне предложили попытать счастья с Яндекс.Лавкой, и я не смог пройти мимо — интересно было, смогу ли я устроиться куда-нибудь, когда введут великий российский файерволл. К тому же за последние 3 года я проходил только два интервью, и мне показалось, что я не в теме, что нынче требуется индустрии. Блин, я оказался и вправду не в теме. И вы, скорей всего, тоже — об этом и статья.
Короче, я согласился — буду продавать дошики и похмелье!

Мне назначили дату интервью, и также прислали методичку, чтобы я понимал, что меня ждёт и как готовиться. Чтобы ничего не заспойлерить, я замазал квадратиками важную информацию.

Вы тоже заметили «вопросы на C++» в методичке для питониста? Не то чтобы я знал C++, но в институте проходили, авось что-нибудь да вспомню на интервью.


Тут что-то написано про leetcode, но я человек ответственный, поэтому к интервью не готовлюсь. Это кстати я не шуткую, реально: если вы ответственный человек, то вы, когда предстаёте перед компанией, отвечаете за то, что вы заявляете как ваши умения. Можно выучить типовые вопросы и даже казаться умнее и опытнее, чем есть, но по факту это переобучение на тестовых заданиях/вопросах. Ребята из ml поймут. Поэтому я гол как сокол и чист как стёклышко или что там ещё блин, если что-то знаю — скажу, что-то не знаю — скажу что не знаю. Таким образом работодатель знает, что он покупает и сколько ещё нужно вложить в меня средств на обучение. Все счастливы.
Интервью 1
Так вот, назначили мне собеседование, и в назначенный час я был в зуме. Сразу скажу, что все — и рекрутер, и интервьюеры — вежливые и приятные в общении люди, тут я подкопаться не могу, ну разве что иногда они слишком корректные: спрашивают, ничего, если будет стажёр-наблюдатель и если они будут делать заметки в ходе интервью. На какой-то из итераций мне даже стало интересно, что будет, если я скажу «нет, нельзя», но именно тогда меня не спросили, так что предлагаю вам проверить самим.
Мне кинули ссылку на Яндекс.Блокнот (это я его так называю, вообще он Яндекс.Код и живёт тут) — там можно вместе писать текст и включать подсветку синтаксиса. Запускать там, естественно, ничего нельзя, потому что это уже реализовано в coderpad, а он недостоин Яндекса. Ну ок, мне на самом деле проще, потому что написать код и написать хотя бы запускаемый код — это очень разные вещи. Минус — нельзя прогнать тесты и вообще тут как битва самураев: ваша правда против правды рекрутера, один доказывает, почему работает, другой — почему нет.
Итак, о чём вас спросит Яндекс на интервью? Выберите один правильный вариант:
2) текущие проекты
3) как вы будете решать вот эту бизнес-задачу
4) как решить вот эту алгоритмическую задачу без стандартной библиотеки
Именно так! Так давайте решим эту алгоритмическую задачу. Помните, у нас нет collections.Counter , itertools.groupby, set.intersection , вообще случилась война и стандартная библиотека питона погибла, оставив после себя int , bool , for , if и while . Ну ок, хотят проверить знание каких-то базовых вещей.
Задача 1
Даны два массива: [1, 2, 3, 2, 0] и [5, 1, 2, 7, 3, 2]
Надо вернуть [1, 2, 2, 3] (порядок неважен)
Фактически нам нужно вернуть пересечение множеств, но с повторением элементов. Не включая мозг, я начал сразу кидать что-то вроде
common = set(a).intersection(set(b)) # найдём общие элементы for el in common: occurs = min(a.count(el), b.count(el)) # и посчитаем, сколько они встречаются
Но меня осадили — у нас война, поэтому никаких intersection , только хардкор. После нескольких итераций и намёков интервьюера я родил вот это:
def common_elements(a, b): b_dict = defaultdict(int) # defaultdict выжил :) for el in b: b_dict[el] += 1 # я считаю все элементы из b, т.е. типа collections.Counter result = [] for el in a: count = b_dict[el] if count > 0: # если какой-то элемент из a встречается в b result.append(a) # то это успех b_dict[a] -= 1 # и я "вынимаю" его из b, т.е. уменьшаю его количество на 1 return result
Внимательные читатели намекнули, что на строчках 11 и 12 нужно использовать el , а не a , но на интервью и так прокатило 🙂
Тут же меня спросили, какова сложность алгоритма — ок, норм, это нужно знать, потому что в реальном программировании мне это потребовалось целых 0 раз. Ответил.
После этого задания (и впоследствии) я увидел, что хоть они и принимают рабочие решения, у них есть эталонные, к которым они вас подталкивают, особенно если сложность вашего решения больше сложности эталона. Не то чтобы прям только эталон принимают, но знайте, что он есть.
Кстати, как вы наверно догадываетесь, есть большая разница между решением, написанным в обычной рабочей атмосфере, и решением, написанным на собеседовании в яндекс.блокнотике с интервьюером на связи и ограничением по времени. Здесь и далее я привожу те решения, которые сообразил на интервью, какими бы ужасными они не были. Можно ли написать лучше? Да, в каждой из задач можно лучше.
Задача 2
Ладно, лоу-левел алгоритмическая муть позади, давайте теперь нормальную задачу, распарсить там что-нибудь или накидать архитектуру высоконагруженного прило.
Дана строка (возможно, пустая), состоящая из букв A-Z: AAAABBBCCXYZDDDDEEEFFFAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBB
Нужно написать функцию RLE, которая на выходе даст строку вида: A4B3C2XYZD4E3F3A6B28
И сгенерирует ошибку, если на вход пришла невалидная строка.
Пояснения: Если символ встречается 1 раз, он остается без изменений; Если символ повторяется более 1 раза, к нему добавляется количество повторений.
Ну ок, хотят проверить знание каких-то базовых вещей.
Вроде просто: for grouper, items in groupby(string) . А, да, у нас была война. Ничего нет.
def convert(s: str) -> str: result: List[str] = [] last_sym = None # последний символ, что мы видели count = 0 # и сколько мы его видели # мы будем идти по строке и записывать в result при смене символа for sym in (list(s) + [None]): # последний None искусственно триггерит посленюю смену символа if last_sym and sym != last_sym: # если случилась смена символа if count == 1: result.append(last_sym) else: result.append(last_sym + str(count)) # начнаем запоминать новый символ count = 1 last_sym = sym else: # символ просто повторился count += 1 # ну ок, запомнили что символ видели на 1 раз больше return ''.join(result)
Не помню точно, но с вероятностью 3 сигма я продолбал граничные условия — это я делать люблю. Помните, тут нельзя ничего запускать, вместо этого тут принято запускать интервьюера, который интерпретирует ваш код прям в голове и говорит какие случаи не работают, чтобы вы могли пропатчить код.
Так, давайте может что-то другое?
Задача 3
Дан список интов, повторяющихся элементов в списке нет. Нужно преобразовать это множество в строку, сворачивая соседние по числовому ряду числа в диапазоны. Примеры:
[1,4,5,2,3,9,8,11,0] => «0-5,8-9,11»
[1,4,3,2] => «1-4»
[1,4] => «1,4»
Так блин, серьёзно? Я наверно очень мутный тип, если две предыдущие задачи не показали мой скилл на этом классе задач.
Ну ок, хотят проверить знание каких-то базовых вещей.
def repr(group_start, group_end) -> str: # это просто правильно печатает группу if last_group_start == last_group_end: return str(last_group_end) return f'-' def squeeze(numbers) -> str: if not numbers: # граничный случай return '' numbers_ = sorted(numbers) # сначала располагаем по порядку groups = [] # тут будем хранить группы last_group_start = None last_group_end = None for n in numbers_: # это первая итерация, просто говорим, что группа началась и закончилась if last_group_end is None: last_group_start = n last_group_end = n # если предыдущая группа отличается от текущего числа на 1, # то это число входит в группу, то есть становится концом группы elif last_group_end == n-1: last_group_end = n # иначе мы понимаем, что группа закончилась, # мы её запоминаем и начинаем новую else: groups.append(repr(last_group_start, last_group_end)) last_group_start = n last_group_end = n else: # посленюю группу придётся обработать вручную groups.append(repr(last_group_start, last_group_end)) return ','.join(groups)
На этом интервью закончилось, и я стал ждать вестей от рекрутера.
Через пару часов мне сказали, что всё отлично и меня ждут на следующих интервью — 2 штуки подряд — задачи на написание кода. Так, минуточку, а что было до этого — написание говнокода? Ладно, там видно будет. Уж точно что-то новенькое, следующий этап всё-таки.
Интервью 2
В назначенный час я бахнул кофейку и встретился в зуме с новым рекрутером. Интервью #2 началось.
Задача 4
Я, признаюсь, был готов ко всему, но не к этому:
Дан массив из нулей и единиц. Нужно определить, какой максимальный по длине подинтервал единиц можно получить, удалив ровно один элемент массива.
[1, 1, 0]
Ну ок, хотят проверить знание каких-то базовых вещей. Вот такой ужас у меня вышел:
# пример: [0, 0, 1, 1, 0, 1, 1, 0] def max_ones_length(lst: List[int]) -> int: max_ones_length = 0 # тут мы хотим получить сгруппированные 0 или 1 и их количество: subranges = [] # [(0, 2), (1, 2), (0, 1), (1, 2), (0, 1)] last_el = None # последний элемент, который мы просмотрели # идём по элементам списка for el in lst + [0]: # [0] - это ручной триггер для обработки последнего элемента if last_el != el: # если произошла смена 0 на 1 или наоборот if el == 0: # если это была смена 1 на 0 # пример: subranges == [(0, 2), (1, 2), (0, 1), (1, 2)] # у нас произошла смена 1 на 0, до смены единица шла 2 раза # (см последний элемент subranges) - проверяем, вдруг это # максимальная длина try: last_ones_length = subranges[-1][1] max_ones_length = max(last_ones_length, max_ones_length) except IndexError: pass # а может если мы удалим один ноль между элементами 1 и 3, # то получится более длинная последовательность единиц? try: gap_length = subranges[-2][1] if gap_length == 1: combined_ones_length = subranges[-1][1] + subranges[-3][1] max_ones_length = max(combined_ones_length, max_ones_length) except IndexError: pass # добавляем новый счётчик последовательности в subranges subranges.append((el, 1)) else: # увеличиваем счётчик последней последовательности на 1 subranges[-1] = (el, subranges[-1][1]+1]) last_el = el # костыль, граничное условие if len(subranges) == 2 and subranges[1][1] == 1: return subranges[0][1] - 1 return max_ones_length
Ну что, Яндекс, ты доволен? Ты доволен?! Кто король алгоритмов?! Я король алгоритмов! Давай, удиви меня.

Задача 5
Даны даты заезда и отъезда каждого гостя. Для каждого гостя дата заезда строго раньше даты отъезда (то есть каждый гость останавливается хотя бы на одну ночь). В пределах одного дня считается, что сначала старые гости выезжают, а затем въезжают новые. Найти максимальное число постояльцев, которые одновременно проживали в гостинице (считаем, что измерение количества постояльцев происходит в конце дня).
sample = [ (1, 2), (1, 3), (2, 4), (2, 3), ]
Отлично, тут уже начинает появляться мир — ну там люди, отели, вдруг даже этот код реально где-то когда-то может пригодиться. Я прям вижу, как с каждой задачей будут появляться дороги, поезда, реки, горы и моря, металл, электричество, сервера и датацентры и блин задачи, которые будут работать в дата-центрах и серверах, ну хоть где-нибудь!
Ну ок, хотят проверить знание каких-то базовых вещей.
from collections import defaultdict def max_num_guests(guests: List[tuple]) -> int: res = 0 # для каждого дня посчитаем, сколько приехало и сколько отъехало arriving = defaultdict(int) leaving = defaultdict(int) for guest in guests: # O(n) arriving[guest[0]] += 1 leaving[guest[1]] += 1 current = 0 # едем по дням в порядке увеличения, добавлем приехавших и убавляем уехавших, # считаем сколько стало for day in sorted(set(arriving.keys()).union(set(leaving.keys()))): # O(n*log(n)) + O(n) current -= leaving[day] current += arriving[day] if current > res: res = current return res
Не без подсказки интервьюера, но я написал это, и теперь менеджер, наверно, может эффективно узнать важную инфу. Круто. Пора прыгать на следующее собеседование (да, они шли одно за другим).
Интервью 3
Новый интервьюер; можно наблюдателя; можно писать заметки; да, я знаю, как работает ваш яндекс.блокнот лучше вас уже, давайте наконец
Задача 6
Sample Input [«eat», «tea», «tan», «ate», «nat», «bat»]
Sample Output [ [«ate», «eat», «tea»], [«nat», «tan»], [«bat»] ]Т.е. сгруппировать слова по «общим буквам».
Смутное чувство дежавю посетило меня. Нет, показалось наверно. Ну ок, хотят проверить знание каких-то базовых вещей.
Эта задача простая, наверно хотят удостовериться, что пока я разруливал дела в отеле, я не забыл, как пользоваться словарём. Не лишено смысла! Давайте накидаем что-нибудь простое.
def group_words(words: List[str]) -> List[List[str]]: groups = defaultdict(list) for word in words: # O(n) key = sorted(word) groups[key].append(word) return [sorted(words) for words in groups.values()] # O(n*log(n))
Тут меня спросили «а какая сложность у сортировки», и я воспользовался лайфхаком. Дело в том, что все собеседования проводятся разными людьми, и они вообще не знают ваш контекст — например, о чём я говорил в предыдущих сериях и, например, кхм, сколько алгоритмических задач я прорешал до этого. На прошлом собеседовании меня спросили, какая сложность у сортировки, я не знал и мне сказали — и на этом собеседовании я уже ответил.
Задача 7
Слияние отрезков:
Вход: [1, 3] [100, 200] [2, 4]
Выход: [1, 4] [100, 200]
Честно говоря, где-то тут мне уже стало плевать на собеседование, Яндекс и все эти алгоритмы, и в реале я бы уже просто послал всех в /dev/null, но мне хотелось знать, что в конце всего этого, ведь конец должен быть? Будет задача, где я завалюсь, и это кончится. Что-то вроде эвтаназии, но в интервью.
Ну ок, хотят проверить знание каких-то базовых вещей.
def merge(ranges: List[Tuple[int, int]]) -> List[Tuple[int, int]]: if not ranges: return [] result_ranges = [] last_range = None # последний отрезок, что мы видели for rng in sorted(ranges): # обязательно сортируем if not last_range: last_range = rng continue # если начало текущего отрезка меньше конца предыдущего if rng[0]
Задача 8
Время собеседования подходит к концу, но всё-таки можно ещё поболтать про кодинг и поспрашивать практические вопросы, например по Django или SqlAlchemy:
Дан массив точек с целочисленными координатами (x, y). Определить, существует ли вертикальная прямая, делящая точки на 2 симметричных относительно этой прямой множества. Note: Для удобства точку можно представлять не как массив [x, y], а как объект
Ну ок, хотят проверить знание каких-то базовых вещей.
Тут я как всегда пошёл куда-то не туда и написал вот что:
from statistics import mean def is_vertical_symmetry(points: List[Point]) -> bool: # сначала найдём вертикальную прямую в середине всех точек x_center = mean(p.x for p in points) # тут будем хранить точки, для которых пока не нашли пары: unmatched_points = defaultdict(int) for point in points: if point.x == x_center: # если точка на прямой, то она сама себе пара continue # создадим "брата" - точку, которая симметрична текущей относительно вертикальной прямой brother = Point( x = x_center * 2 - point.x, y = point.y, ) # если этот брат есть в unmatched_points, то достаём его оттуда и говорим, что текущая точка сматчилась if unmatched_points[brother]: unmatched_points[brother] -= 1 # иначе добавляем эту точку в не-сматченные else: unmatched_points[point] += 1 return not any(unmatched_points.values())
Здесь я прям видел, как интервьюер ожидал что-то другое, а получил меня. Ну бывает. Я тоже, знаете, ожидал собеседование.
Так, третье собеседование пройдено, и эти садисты сказали, что я прошёл дальше. Ну вот за что?

Интервью 4
Честно говоря, вот тут я потерялся, потому что я всё жду, когда начнётся собеседование, ну, человеческое собеседование имеется в виду, а пока вместо этого я превращаюсь в алгоритмэна.
По собственным ощущениям я добрался до какого-то мини-босса и на предстоящем интервью у меня должна была пройти какая-то битва на более общие вопросы. А рекрутер мне пишет: знаете, Яндекс настоятельно советует потренироваться на задачках с leetcode. А там опять алгоритмы. Ох, не к добру это.
Ну тут уж я сломился и решил таки глянуть, что там за задачки, раз мне так настойчиво намекают. Вообще там есть сложные, и над ними было прикольно подумать и порешать в уме, но я так и не понял, как это поможет в интервью. Задачек слишком много и, что более важно, они, блин, разные, и решив одну, я не решаю класс задач - я решаю одну задачу. Соответственно либо я решаю их все и зачем мне тогда ваш Яндекс после такого, либо. короче, я опять не готовился. Ответственный человек, помните?
Кстати, где-то в этот момент я узнал, что я юзаю что-то вроде тора, но для собеседований: я общаюсь с рекрутером, мой рекрутер общается с рекрутером Яндекса, а рекрутер Яндекса общается с собеседователями, а может цепочка ещё больше. Меня это поразило прям: вы меня тут дерёте за O(n^2) в решениях, так может я у вас посчитаю длину цепочки от кандидата до собственно интервьюера и спрошу "а можно оптимальнее?!"
Итак, началась четвёртое (да, ей-Богу) интервью. Интервьюер спрашивает, на каком языке я буду решать задачки. На йоптаскрипте, разумеется. Кстати, по косвенным признакам я понял, что интервьюер больше в C, чем в питон, и это тоже здорово. Итак: после того как компания решила нанять сеньор питон разраба за 200к и сношала его 3 часа на долбанных задачках, она отправляет на собеседование сишника и спрашивает, на каком языке кандидат будет сношаться с долбанными задачками. Л - логика!
Итак, вот задачка от мини-босса:
Задание 9
Даны две строки.
Написать функцию, которая вернёт True, если из первой строки можно получить вторую, совершив не более 1 изменения (== удаление / замена символа).
Погодите, да это же. Ну ок, хотят проверить знание каких-то базовых вещей. Сссссуууу. пер.
Если вы хотите решить задачу не так, как хотел интервьюер, то смотрите:
def no_more_than_one_change(string1: str, string2: str) -> bool: # string1: a b c d # string2: a b c max_length = max(len(string1), len(string2)) # наибольшая длина строк diff = abs(len(string1) - len(string2)) # разница в длине строк # дополняем строки до максимальной длины при помощи zip_longest, # то есть на место "недостающих" элементов ставим None, и строки # теперь одинаковой длины; # ----> # string1: a b c d # string2: a b c None # идём слева направо по обеим строкам и сравниваем символы, # находим индекс, при котором строки начинают отличаться: change_left = None for i, (char1, char2) in enumerate(zip_longest(string1, string2)): # O(n) if char1 != char2: change_left = i # в нашем примере будет 3 break else: # если мы такой индекс не нашли, то строки просто совпадают return True # теперь делаем то же, но идём справа налево: # string1: a b c d # string2: None a b c #
Внимательный читатель может заметить, что, по-моему, это даже на приведённом примере не работает 🙂 , хотя пофиксить несложно. Так или иначе, вот такие вещи как я написал лично мне тяжело гонять в голове, и интервьюеру тоже; интервьюер принял это как решение, прогнав несколько тестов в уме. Если хотите возвести это в абсолют, то пишите сразу на brainfucke и с умным видом объясняйте, почему оно будет работать. А вообще я просто тонко намекаю, что всё-таки компилятор/интерпретатор под рукой нужен.
Задание 10
Осталось совсем немного времени, и вот в довершение пара реально сложных заданий на понимание многопоточности и gil в python:
Дан список интов и число-цель. Нужно найти такой range, чтобы сумма его элементов давала число-цель.
elements = [1, -3, 4, 5]
target = 9
result = range(2, 4) # because elements[2] + elements[3] == target
А теперь все вместе хором: НУ ОК, ХОТЯТ ПРОВЕРИТЬ ЗНАНИЕ КАКИХ-ТО БАЗОВЫХ ВЕЩЕЙ. Вы восхитительны. Спасибо.
Здесь я уже не успевал по времени и озвучил идею: мы бежим по списку и сохраняем в память значения сумм для всех range до этого элемета. Иными словами, для каждого элемента мы пробуем делать ranges, которые кончаются на этом элементе, и смотрим на их сумму элементов.
[1, -3, 5, 6, 2, 3, 5] ^____[range(0,1)=1] [1, -3, 5, 6, 2, 3, 5] ^___[range(0,2)=range(0,1)-3=-2, range(1,2)=-3] [1, -3, 5, 6, 2, 3, 5] ^___[range(0,3)=range(0,2)+5=3, range(1,3)=range(1,2)+5=2, range(2,3)=5]
Не угадал, конечно - "а можно чтобы быстрее?". Но тут, к счастью, время вышло, и мой мозг не успел придумать ничего лучше.
>> Сейчас я нахожусь здесь
Прелесть ситуации в том, что я ещё не получил фидбек, то есть я кандидат Шрёдингера - я и прошёл (формально я все задачи решил), и не прошёл (== не всё угадал, где-то баги), и суперпозиция сколлапсирует, когда ответ пройдёт через всю цепочку рекрутеров ко мне. А пока я полностью беспристрастен, ведь 1) меня не отшили, то есть это не пост обиженного на компанию человека, и 2) мне плевать на результат, потому что мне и на текущей работе офигенно.
К чему всё это
Вообще это просто так тупо, что забавно, и я не мог с вами не поделиться. Никак не связанные люди тестируют меня на одном и том же типе задач, который максимально оторван от реальности, всё это длится много часов, сложность задач неупорядочена, проверяется всё в голове и никакого фидбека.
Сколько вопросов, блин, можно спросить про http, rest, django orm, sql, python, stdlib, docker, multithreading/multiprocessing/async, да про что угодно - что вы там в лавке делаете? - спросите про похмелье, но зачем 4 часа алгоритмов? Что это показывет - что я устойчив к тупости? Честно говоря, я уже не уверен.
Может кому-то пригодится разбор задачек, ну вдруг вы любитель такого, хотя я уже говорил о качестве решений 🙂
А если вам нужен вывод, то вот несколько, берите любой:
- Тестировать кандидатов нужно на реальных задачах, а не синтетических
- Нужно уважать время кандидатов
- Кто-то в яндексе пересмотрел "день сурка"
- Знаете, когда целое не равно сумме частей? Вот тут так же: люди тебя собеседуют хорошие и встречи приятные, а в целом всё гавно.
- Открыто новое достижение: ругательство "да пошёл ты в яндекс!"
- Большие компании ай-яй-яй
- Какой-то чувак написал смешную статью
И да, если вы ищете работу на питоне - залетайте к нам. У нас не Яндекс.
Мой канал в телеграме: Блог погромиста.
Сказ про то, как я устраивалась на работу в Яндекс
Чтобы два раза сегодня не вставать, напишу еще один пост пожалуй.
Как вы уже знаете, дорогие мои читатели, некоторое время назад я приняла волевое решение уйти с текущей своей работы, и найти новую. Зачем, спросите вы (или не спросите)? Да все как у всех. Как говорится, назрела необходимость. Подробности - на собеседовании, приглашаете - наверно, рассказываю, не приглашаете - не рассказываю уж точно:)
В разгар событий, когда я уже сдавала дела, подытоживала результаты и собирала манатки, чтобы пуститься в свободное плавание, на небезызвестном сайте по поиску работы появилась интересная вакансия - "Менеджер по работе с клиентами". Город - Ростов-на-Дону, работодатель - Яндекс. Протерев глазоньки и удивившись, я поискала информацию. Оказалось, что да, так и есть - в наш город приходит Яндекс, открывает свой офис и набирает сотрудников в штат. Сестра мужа по этому поводу пошутила - "Ты в Москву не едешь, так Москва приехала к тебе". И правда, ну как тут не возлагать надежды? Интересная компания, лидирующая среди поисковых систем, с хорошими продуктами для рекламы. Ценность Яндекса, как работодателя, нет смысла описывать, как и бессмысленно писать про нужность Директа. Те, кто понимает хоть немного в рекламе в сети, это и так знают, а те, кто не понимают - думаю, что не читают этот пост.
"Это мой шанс!" - подумала я, и закинула невод. То есть, отправила отклик на вакансию. Через три дня волнительного ожидания, мой отклик был отклонен. "Ну уж нет!" - разозлилась я, и откликнулась на еще одну вакансию, сопроводив ее специальным письмом в духе "Как я хочу у вас работать", которая там успела за это время появится - "менеджер по работе с агетствами".
Пока работодатель думал, я наводила справки. Выяснила, что на самом сайте Яндекса тоже есть эти вакансии, и там, чтобы откликнуться, надо пройти тестовое задание. Я уж было начала заполнять ответы, но решила подождать, что же будет с моим откликом.
К моему удивлению и радости, на отклик ответили "приглашением". Но это не было приглашением на собеседование, как можно было подумать. Пригласили меня пройти то самое тестовое задание, над которым я уже начала размышлять. Собравшись с мыслями, я написала ответы на вопросы на сайте, что неожиданно заняло у меня часа три, которые пролетели, как пятнадцать минут. Достала из закромов свое резюме трехгодичной давности, сдула с него пыль, и приложила к ответам. Перекрестившись, плюнув три раза через левое плечо и постучав по деревянному столу я нажала кнопку "отправить" и затаила дыхание.
Прошла пара дней, и на почту ко мне пришло письмо (ураааа!) с предложением пройти собеседование по телефону.
По телефону мне собеседоваться еще ни разу не приходилось. Что будут спрашивать, что нужно отвечать - я не представляла себе, поэтому решила почитать справку Яндекса, чтобы получше понимать продукт. Само собеседование по телефону прошло неплохо, насколько я могла судить - вопросы были по делу, скорее для того, чтобы посмотреть, как я мыслю, чем как я знаю продукты Яндекса. Приятная девушка-эйчар сообщила, что обсудит мои результаты с руководством и свяжется со мной.
Прошло еще немного времени, и мне пришло письмо (ураааа еще раз!), что меня приглашают на личное интервью с руководителем ростовского офиса. На собеседование я летела, как на крыльях! Интересно было то, что оно проходило в кафе, как мне объяснили, офис снят пока временный ("и, видимо, недостойный", подумала я). Это собеседование также прошло хорошо, вопросы были также по делу, отвечала я на них вполне неплохо (по-моему). В целом, впечатления о компании, работе сложились самые положительные. Условия труда меня повергли немного в шок (в хорошем смысле), так как они были очень и очень достойные (я не знаю, предоставляет ли хоть одна ростовская компания такие?).
Собеседование приближалось к концу, милая девушка-руководитель сказала, что будет меня рекомендовать. "Куда?" - спросила я. И вот тут оказалось, что это - ого! - не последний этап. (А я уже раскатала губу))) Оказывается, нужно пройти еще одно собеседование, решающее, с руководителем региональных офисов. Огого.
Вот тут я заволновалась. Потому что до этого момента я как-то не до конца осознавала, наверно, следующее - отбор не просто серьезный, а очень серьезный. И еще - берут всего трех человек в первый "набор". А сколько же претендентов.
По моим разведданным, которые могут оказаться неточными, на последний, пятый этап, прошло около 10 человек. Получается, что среди них конкурс - примерно по три человека на место.
С другой стороны, получилось следующее: я не знала, что будут спрашивать и по каким критериям будет отбор. Кто мои соперники. Так получилось, что кто еще один человек - я знала) А остальные.
Пришло время решающего собеседования. Я так не хотела опоздать, что приехала на целый час раньше)) Бродила по ветру, решила сходить в супермаркет, купила яйца, чесночные булочки и чак-чак. И со всей этой провизией мне стало почему-то спокойно и я двинулась на собеседование.
"Полтора часа ада - и я на свободе!" - примерно это я чувствовала, когда вышла. Подробности я рассказывать не буду, но в целом, ощущения были такие, как будто я - двоечница на экзамене. Все было совсем не так, как можно было себе представить, вопросы были неожиданными и трудными. Мне показалось странным, что меня спрашивали то, что, по-моему, мне должны были наоборот рассказывать. Обдумав позже, я пришла к выводу, что дело отчасти в том, что спрашивали меня не про продукт, а про продажи. То есть про то, чем я не занималась никогда. То есть все со мной все нормально, я не дура)
Не удалось избежать стандартных и идиотских вопросов - "каковы ваши жизненные цели", "где вы видите себя через 3, 5 лет". Зато меня ни разу (!) не спросили, замужем ли я, нет ли у меня детей, не планирую ли я этих самых детей заводить сейчас. Ростовские работодатели считают своим долгом это узнать, а ну как я к ним устроюсь - и буду развращать сотрудников? Или, еще хуже, устроюсь - и сразу сбегу в декрет.
В целом, итоговое собеседование расставило все на свои места. В команду в ростовский офис нужны продажники - люди, способные совершать холодные звонки, способные влезть в голову, вцепиться и не отпустить, такие ушлые-преушлые ребята, продажники до мозга костей. Получилось, что они не подходят мне, а я - им. В общем, я не расстроилась ни капельки, когда получила отказ по почте, с объяснением, что мне "не хватает опыта активных продаж". Оно-то понятно - им нужны люди, которые сразу могут прийти к ним на работу и продавать-продавать-продавать, а не те, которые знают продукт, которые могут помочь клиенту, объяснить, спланировать, но которых надо продажам сначала научить.
В общем, опыт был интересный. Я нисколько не жалею, что попробовала! 🙂 Спасибо сотрудникам компании, которые потратили на меня несметное количество времени.
А, ну еще хочу сказать, что в конце собеседования я задавала разные вопросы о стратегии Яндекса в регионах, о Гугле и конкуретной борьбе и получила очень интересные ответы)) Буду следить за развитием Яндекса в Ростове-на-Дону, и очень хотела бы посмотреть офис, когда его отремонтируют. Ожидается нечто фееричное, такое нельзя пропустить)
А я продолжаю пока отдыхать дальше. Высыпаться по утрам, неспешно почитывать новости и попивать чаек, пока большинство из вас в поте лица трудится над очередной задачей. Пока все будет так, а дальше. видно будет дальше.
Как я проходил собеседование в яндекс
Находит меня хеадхантерша из другой страны и предлагает попробовать пройти собеседование в Яндекс. Работы почти нет, зарплаты, судя по рассылкам, там большие. Немножко не тот профиль вообще, но в частности в требуемой теме полгода опыта есть. Сказала, что там задачи решать.
Интервьюер почти ничего не спросил, выдал ссылку на общий вебовский редактор, где первым заданием было написать структуру односвязного списка с данными. А затем было предложено написать функцию, где на входе два таких списка, а на выходе один, отсортированный по данным из первых двух и без всякого копирования.
Реализованная задумка скорее всего получалась бы такой:
struct list < struct list* next; int my; >; list* joint(list* a, list* b) < list fst = < a >; list scd = < b >; list trd = ; list* res = &trd; while (fst.next || scd.next) < int ref = 0; list* dst = 0; bool flg = 0; for (list* src = fst.next? &fst:&scd; src->next; src = src->next->next || flg? src->next : (flg = 1, &scd) ) < if (src->next->my > ref) < ref = src->next->my; dst = src; > > res->next = dst->next; dst->next = res->next->next; res = res->next; > return trd.next; >
Сразу скажу, что писать так нельзя (или можно для себя, какой-нибудь тест).
Вкратце было так: мне дан какой-то неудобный вебовский редактор, с подсказками и подсветками не в тему. Плюс переговариваюсь я на маке и там не программирую. Много опечаток, раздражаюсь.
Интуитивно хочу поменьше писать и поместить все в два цикла (из соображений сложности алгоритма).
Смастерив тот вложенный for(для двух списков разом), я выдаю замечание, что суть задачи неадекватна предложенной форме исполнения. На что получаю ответ, что он, опытный мастер, наблюдая за моими руками, никакой осмысленности в моем черновом коде не видит. И предлагает на этом завершиться.
Выбесило, но что есть, то есть. Над задачей стоило подумать прежде, чем начать что-то писать. Там все просто, этот for надо дублировать для каждого из списков, пренебрегая тем, что дублируется и тело цикла один к одному. В процессе дальнейшего кодирования, возможно, я бы это увидел, но это сослагательное наклонение.
Правда, остаются вопросы.
Человек из Яндекса не может прочесть код с оператором “запятая”? В чем глубокий смысл требовать написать код в крайне неестественных условиях (без компилятора и в неиспользованном ранее редакторе)? Не предложив изначально оценить трудоемкость, не давая время на дизайн в минимальной форме? Я вот играю в блиц на класс ниже, чем в обычные шахматы — в Яндекс нужны скорострелы?
Короче, кто туда собирается, должен иметь эти вещи ввиду. Хорошо оплачиваемые работы всегда с каким-нибудь подвохом, им выбраковывать много кандидатов надо 🙂
PS: 29.12 Не могу отвечать в комментах, в свое впемя был забанен (за программисткий разбор писания:), разбанили — статья в неделю, коммент в день(даже на свою статью). Не суть.
Откликаюсь под катом:
про код как надо
Разговор у многих выходит на требования, где додумываются дополнительные. Но фактически в таких оказиях требование одно — время. Я даже узнал здесь (и соглашусь), что не обязательно, что бы работало (но себе к сожалению при собеседовании ставил).
Да, практически трое спросили некий код «как надо». Тоже надо понимать, что правильных кодов не бывает, код зависит от требований. Интервьюер не ставил и не мог ставить цели читабельности с таким временем, с таким подходом и инструментарием. Форумская общественность ставит — я уже писал про запатченный bool-ем for, который интервюер не понял. Разлагаю его на два цикла + читаемые имена.
Не сильно тестированный вариант:
struct list < struct list* next; int my_number; >; list* joint(list* a, list* b) < list pseudo_headers[] = < , , >; // trick: first element of array is [pseudo]header of result list list* res_ptr = &pseudo_headers[0]; while (pseudo_headers[1].next || pseudo_headers[2].next) < list* ahead_max; int cur_max_data = 0; for (int i = 1; i < sizeof(pseudo_headers)/sizeof(pseudo_headers[0]); i++) < for (list* ahead = &pseudo_headers[i]; ahead->next; ahead = ahead->next) < if (ahead->next->my_number >= cur_max_data) < cur_max_data = ahead->next->my_number; ahead_max = ahead; > > > res_ptr->next = ahead_max->next; ahead_max->next = res_ptr->next->next; res_ptr = res_ptr->next; > return pseudo_headers[0].next; >
К сожалению, не доступен сервер mySQL
Евгений Сугробов: Однажды я схантил человека прямо в такси
Евгений Сугробов два года руководил подбором сотрудников в Яндекс.Такси. Он рассказал Инсайту, как можно захантить человека прямо в такси и переманить кантри-менеджера у конкурентов.

Нас читают более 10 000 ваших коллег!
Подпишитесь на рассылку Хантфлоу
Два раза в месяц мы будем присылать вам свежие статьи, полезные кейсы, подкасты, анонсы событий и интервью со звездами HR
Что представлял из себя Яндекс.Такси, когда вы пришли туда работать?
В Яндекс.Такси я пришел в декабре 2015 года. Там работали 50 человек, сервис работал в трех городах России, а в финансовой отчетности «большого» Яндекса нас и видно‑то особо не было. Но бизнес показывал прекрасные темпы роста, и руководство Яндекса видело в такси большие перспективы.
Я начал подбор людей в сервисы Яндекс.Такси и Яндекс.Вертикали, имея в подчинении одного сотрудника. На тот момент было открыто 8 вакансий, ими я и занялся в первую очередь, одновременно подбирая команду рекрутеров.
С чего вы начали рекрутинг?
Сначала планировалось открыть сервис Яндекс.Такси в шести городах и посмотреть на результаты. Они оказались столь впечатляющими, что следующая планка была значительно выше: 60 городов за год. Параллельно мы искали разработчиков, маркетологов и с нуля строили b2b-направление сервиса. В результате Яндекс.Такси в 2016 году начал работать более чем в 70 городах России и нескольких странах СНГ, количество поездок выросло более чем на 500 %, а капитализация превысила миллиард долларов.
А какие требования предъявляются к сотрудникам Яндекс.Такси?
Мы искали людей с высокими когнитивными способностями, нестандартным мышлением, способных отвечать за развитие всего бизнеса в выделенном регионе, выстроить бизнес-процесс в штаб-квартире или запустить новый продукт.
По сути, мы искали именно бизнесменов. Оказалось, что под наши требования подходят немногие. Иногда мы брали, например, менеджера по развитию из телекома или человека, который имел маленький бизнес, но при этом делал интересные вещи и побеждал соперников в высококонкурентной среде. Это были люди, которые умели быстро, гибко, нестандартно мыслить, работать в условиях неопределённости. Именно они возглавили подразделения Яндекс.Такси в разных городах и странах.
Где и как вы искали сотрудников? Какой был алгоритм действий при рекрутинге?
Каждый новый город, где открывался сервис, требовал закрытия нескольких вакансий. Нужных людей искали в Линкедине и на Фейсбуке. Вели переговоры с менеджерами из FMCG-компаний, телеком-компаний, стартаперов и сотрудников из разного большого бизнеса. Писали им в социальных сетях или звонили.
Изначально мы пытались подбирать сити-менеджеров в регионах по скайпу, но что парадоксально, такой подход затягивал процесс. Скайп-интервью ровным слоем размазывались по календарю, а количество открытых вакансий росло в геометрической прогрессии.
Рост бизнеса давал серьезную нагрузку на все подразделения: операционное, маркетинг, разработку и продажи. Иногда мы даже рекрутеров набирать не успевали.
Тогда, чтобы не терять в качестве подбора, мы изменили тактику: перешли от монолитной архитектуры рекрутмента к микросервисной: рекрутмент разделился на IT и гуманитарный блоки (позднее появилось и отдельное направление массового найма), а для общения с сити- или кантри-менеджерами сотрудники начали ездить в командировки, где на местах за 2 дня назначали подряд по 10–12 собеседований и за 30 человеко-часов выбирали лучших кандидатов.
Примерно 5–6 человек выходили на следующий этап, дальше менеджмент выбирал максимально подходящего сотрудника. Каждый кандидат проходил через следующие этапы:
- Звонок по телефону/короткий скайп;
- Очное собеседование с HR;
- Скайп-собеседование с менеджером;
- Скайп-собеседование с директором.
Классическая воронка выглядела так: 25–5–2–1.
Как вы хантили из других компаний?
Мы создавали списки компаний-доноров и компаний-конкурентов. Мы хорошо знали, кто за что отвечает в этих организациях, находили нужных людей, предлагали им встретиться и пообщаться. Так мы хантили не только в России, но и в СНГ и Европе.
А были нестандартные способы хантинга?
Однажды я схантил человека в такси. Дело было так: мы были в командировке в одном из южных регионов, где требовалось найти регионального менеджера Яндекс.Такси. С кандидатами не везло, мы с коллегами сидели уставшие и потухшие: из 14 кандидатов, отсмотренных за день, более-менее подходил только один, а общий уровень оставлял желать лучшего.
Впереди был еще один день собеседований. Я заказал такси в отель, решив, что если и завтра ни один из кандидатов не подойдет, билеты можно сдавать: мы не можем вернуться в Москву с пустыми руками.
Выйдя из офиса, я с удивлением обнаружил, что за мной приехала машина люкс-класса. Водитель не был похож на обычного таксиста. По фразам и словам, которые он использовал в общении, было заметно, что это человек с высоким уровнем интеллекта и явно из бизнеса. Мы разговорились, и оказалось, что он раньше был топ-менеджером в Москве, занимался ритейлом, в том числе международными проектами. Но потом решил, что хочет с семьей уехать туда, где потеплее.
Филиал компании, в котором ему предложили место, в этом регионе оказался убыточным. Он провел оптимизацию бизнеса, оценку, написал две стратегии — развития и сворачивания. В результате акционеры выбрали последнее. Он успешно осуществил сворачивание, получил «золотой парашют». А пока размышлял, что делать дальше, решил поработать в такси, просто чтобы не закисать дома. Выслушав эту историю, я связался с коллегой, и она забронировала нам время на следующий день. Все прошло успешно, и этот человек по сей день успешно работает в компании.
Другая история о том, как мы схантили кантри-менеджера у конкурентов. В одном из регионов СНГ, где конкурент стартовал раньше нас, мы наблюдали за работой их кантри-менеджера. Он был весьма силен. Наши ребята достали его номер телефона, я позвонил и предложил встретиться. Сначала человек отказывался, не шел на контакт, и мне потребовалось две недели постоянных созвонов и обсуждений, чтобы вытащить его в Москву. Мы купили билеты, забронировали хорошую гостиницу. После знакомства с нашей командой сомнений у человека не осталось.
Чем команда Яндекс.Такси так крута?
Людьми, в первую очередь. Количеством умных людей на квадратный метр. Тем, что эти люди не боятся принимать решения, не бояться пробовать, они строят гипотезы и проверяют их на практике. С одной стороны, они очень быстрые и гибкие, с другой стороны, у них железобетонный, математический, научный подход к бизнесу. И на стыке этих двух вещей получается делать действительно потрясающие вещи в компании.
Как вы привлекли таких людей в команду?
Яндекс.Такси — это формирующаяся на глазах, новая для всего мира индустрия. Мы никого не копируем и идем нога в ногу с мировыми игроками. В мире существует всего три серьезные технологические компании на рынке такси. Это Didi (Китай), UBER (США) — и Яндекс. Технологии Яндекса, алгоритмы, команда, — всё это позволило не догонять, а идти параллельным курсом. Конечно, UBER с их штатом программистов в чем‑то опережает, но некоторые продуктовые, технологические решения у Яндекса впереди планеты всей.
Например, мы реализовали функцию «альтернативная точка посадки». Это когда пользователь вызывает такси, и приложение предлагает другую ближайшую точку посадки, которая удешевит поездку. В результате нагрузка на бэкенд увеличилась в 20 раз.
Как удалось так быстро вырасти и не развалить корпоративную культуру?
Это в первую очередь большая заслуга менеджмента. У нас было три принципа подхода к найму людей. Первое — это качество подбора: мы не идем на компромисс (хотя иногда очень хотелось). То есть если нам надо нанять человека с конкретными знаниями, навыками и личностными качествами, мы не будем нанимать тех, кто не подходит, лишь бы закрыть вакансию.
Второе — это подход от человека, а не от вакансии. Мы нашли крутого человека и смотрим, куда мы его можем применить, так как возможностей для реализации в Яндекс.Такси очень много.
А третье — это полная погруженность эйчаров и рекрутеров в бизнес. Они знают стратегию и тактику компании, положение дел, финансы. Понимают подноготную этого бизнеса, знают, о чем этот бизнес и какие фундаментальные задачи он решает.
Они могут ответить на вопрос, почему, например, UBER стоит столько денег. Почему мы не пузырь, как алгоритмы распределения заказов влияют на экономику бизнеса и зачем нужна система динамического ценообразования. Это результат слаженной работы менеджмента, линейных руководителей и рекрутеров.
Менеджмент сохраняет корпоративную культуру и задает общий тон, темп и правила игры, делится информацией. А рекрутеры подбирают людей, которые вписываются в корпоративную культуру и соответствуют портрету сотрудника Яндекс.Такси. Те, кто не попадает под эти требования, просто не сможет хорошо работать в таких условиях.
На каком этапе и почему вы решили уйти после таких крутых результатов?
Когда в августе 2017-го я увольнялся с позиции Talent Acquisition Partner, в моем подразделении работало уже более 15 человек, команда Яндекс.Такси превысила отметку в 700 человек, сервис работал более чем в 100 городах России, а капитализация составила миллиарды долларов. Мы как команда рекрутеров занимались исключительно сервисом Такси. Мне же хотелось расширить свой функционал, круг компетенций. Поэтому я перешел в развивающийся IT-проект, где отвечаю за весь HR.