Около года назад я задался целью получить оффер от FAANG. Как следствие, постоянной частью моей жизни стали тематические форумы, площадки и вся сопутствующая атрибутика. Спустя какое-то время я попробовал себя на собеседованиях в околоFAANGoвые компании: Lyft, Spotify, Booking и т. д, где-то успешно, где-то не очень. В это же время мне порекомендовали попробовать пройти собеседование в Тинькофф банк, который внедрил схожий процесс.
После стандартного общения с HR менеджером была получена ссылка на описание процесса собеседования. “Хм, почти что FAANG + тех. интервью по Primary Skill”, - подумал я и сказал, что готов приступать. В тот же час было назначено 2 интервью: техническое и coding, а вот 3 этап, system design, нужно было заслужить успешным прохождением первых двух. Почему именно эти 2 части являлись основополагающими, осталось неясным.
Акт первый, технический
В назначенный час я встретился со своим интервьюером. Собеседование выглядело “добротным” и стандартным в заданной проф. области, оттого местами скучным. Было много задач на ревью кода и обсуждения специфики языка, в частности:
Ревью кода. Разнообразные задачи от Spring до concurrency.
Spring до concurrency. Вопросы по Spring оказались весьма тривиальными, входящими в подборку “ТОП-25 вопросов по Spring” (скоупы бинов, виды прокси и т. д.). Можно ли такими вопросами действительно проверить понимание и опыт использования Spring? Сомнительно.
Транзакции. ACID. Уровни изоляций. Как устроена работа в Spring? Несомненно, данный топик поражает своей новизной. Почему бы не отойти от заученной статьи с Википедии (которая читается 5 минут) и стандартных вопросов как будто бы про транзакцию (а на самом деле про прокси в Спринге), не мучить Senior+ кандидата выученными статьями, а поговорить о необходимости транзакций, архитектурных подходах и сопутствующих темах? Тем более вы рекомендуете к прочтению книгу “Высоконагруженные приложения. Программирование, масштабирование, поддержка / Мартин Клеппман”, где тема БД, транзакций и прочего раскрыта очень хорошо.
Concurrency. И снова стандартные вопросы про “deadlock, synchronized, reentrantLock”, принцип “happens before” и “volatile” (хотя это JMM, знатоки, не кидайтесь тапками), как-то по верхам цепляем java.util.concurrent. Зачем-то пересказываем друг другу то, что миллион раз слышали, а на практике почти никогда не применяли. В голове крутится “зачем, почему, ведь мы можем обсудить столько всего”. “Столько всего” - это:
Базовая теория потоков (какими потоками оперирует Java, почему, есть ли альтернативы в Java или других JVM-based языках, их плюсы и минусы).
Методы поиска deadlock и livelock с различными UI тулами или без них (только терминал, только хардкор). Для кандидатов уровня ниже можно просто дать на ревью thread dump.
Если уж дошли до java.util.concurrent, то вместо вопроса, что за зверь ConcurrentHashMap, давайте посмотрим на изменение подхода к ее реализации в разных версиях JVM и поразмышляем о причинах. Также можно обсудить “диковинные” коллекции в виде зоопарка очередей и, к примеру, skip lists (заодно проверив теорию алгоритмов).
Думаю, для “бесплатного” списка тем достаточно)
JMM и т. д. Вот тут прозвучал вопрос, на котором я, признаюсь завис. “Что знаешь о JMM?” Максимально высокоуровневый вопрос, на который мозг начинает генерировать: “Что от меня хотят услышать? Стандартное определение правил из спецификации типа happens before, reordering? А может, типы мониторов, их схему переходов, цикл парковки потоков? А может, еще глубже о работе с ОС?” В общем, не смог я вспомнить, с чего начинаются статьи “JMM, топ 10 вопросов”. “Кое-что знаю, но гораздо меньше, чем Шипилев” - отшучиваюсь и решаю брать инициативу в свои руки. Быстро выдаю всё, что помню про hb, и рассказываю о том, какие проблемы решал за последние несколько лет, тем самым решив перескочить на тему Java Memory. Сразу оговариваюсь, что про heap говорить не будем, так как здесь всё уже сказано и описано, а обсудим лучше NonHeap. Рассказываю о том, почему Spring Boot application не сможет долго жить на 256 Mб оперативы и при чем здесь non-heap (на самом деле, очень советую добавить вопросы про это в интервью, так как приложений, запускающихся не в контейнерах, почти не осталось). Плавно перехожу на коварную Cassandra (как пример сервиса на Java) и ее работу с offheap, заканчиваю тем, что в великолепном докладе Андрея Паньгина всё есть и он мне очень помог. Складывается впечатление, что такого мой собеседующий не ожидал. Возникает неловкая пауза, которую я решаю прервать вопросом “Обсудим gc? Недавно подбирал оптимальные настройки для нашей конфигурации Кассандры, могу рассказать”. То ли из-за ограничений по времени, то ли не выдержав пытку Кассандрой, собеседующий завершает данный блок.
Вопрос со звездочкой. Так как перед собеседованием я прочитал подборки “Топ-50 вопросов по Java, Spring и т. д”, получаю вопрос повышенной сложности со следующими входными данными: Есть сервис, работающий с Third-party сервисом. Также данный сервис работает с реляционной базой, в частности Postgres. В какой-то момент сервис начинает тормозить. Каков алгоритм моих действий? Последовательность моих рассуждений:
Полагаю, что в моем распоряжение есть все необходимые метрики системы и окружения. Поэтому первым делом предлагаю проверить наличие пиков в графиках latency: запрос в БД, запросы к third-party сервисам, сетевые задержки. Если проблема в БД - то смотрим на количество локов и потребление CPU (потребление memory нам ничего не даст, так как в БД встроен механизм кэширования). Есть проблемы - тюним БД или оптимизируем запросы.
Интервьюер отвечает, что с латенси все в порядке, поэтому я предлагаю проверить метрики JVM, в том числе GC (могли увеличиться паузы на stop-the-world).
Переходим к вопросам о том, что же делать, если проблема в медленных ответах third-party системы. Предлагаю следующий алгоритм решения:
Письмо ответственным за систему с подробным описанием проблемы
Ограничение кол-ва запросов к данной системе с помощью rate-limiter (предлагаю отправить письмо с данной просьбой, пока поведение системы не будет исправлено). Предполагаю, что на нашей стороне будет реализована корректная обработка отклоненных запросов.
Использование сircuit-breaker на нашей стороне, дабы ограничить кол-во запросов к данной системе.
К сожалению, я не сказал того, что хотел услышать интервьюер. Как именно следует решать такие проблемы с точки зрения Тинькофф, для меня осталось загадкой. На этой грустной ноте начался второй этап собеседования.
Акт второй, coding
При подготовке к собеседованию я внимательно изучил описание процесса и выделил два важных для себя момента:
Не используйте для созвона телефон: Вы будете много кодить в онлайн-IDE, рисовать схемы и общаться с интервьюером.
В данном случае в алгоритмической секции используются облегчённые задачи по кодированию, нацеленные на умение использовать простые структуры данных, а не на эффективную реализацию алгоритмов.
Из этого я сделал вывод, что решать задачи потребуется в онлайн-IDE вроде Coderpad, а по сложности они будут ближе к easy (возможно, middle) на leetcode. Но, как говорится, мои ожидания - это мои ожидания.
В начале собеседования интервьюер сообщил, что меня ждут 2 задачи, и время я должен рассчитывать сам.
После этого мне было предложено пошарить мой монитор, чтобы решать задачу в удобной для себя IDE. К такому повороту я готов не был, поэтому, сославшись на их регламент, попросил предоставить ссылку на online-IDE. К такому повороту, как оказалось, готов не был уже интервьюер, и ему пришлось достаточно долго настраивать редактор.
Первой оказалась задача на поиск одинаковых элементов в 3 отсортированных массивах с использованием O(1) памяти. Решения я не знал, но рассуждал вслух, предлагая оптимальные по времени, но не по памяти, решения. В процессе раздумий появилось решение на основе 3 указателей, оптимальное с точки зрения времени и памяти. Решение было реализовано, код запустился (как оказалось, выбранный редактор очень медленно запускает код) и в целом задача была решена.
Вторая задача оказалась уровнем выше. Я сразу определил, что решаться она должна методом DP, и тем самым словил диссонанс с ожиданиями: “облегчённые задачи по кодированию, нацеленные на умение использовать простые структуры данных”. Не считаю, что DP задачи, требующие двумерного массива (в простом для понимания решении), можно назвать “облегчёнными”. Объяснив, как в принципе решаются такие задачи, я взял несколько минут на раздумье, но не смог составить рекуррентную формулу, честно об этом сказав. Затем мы вывели формулу вместе с интервьюером - на этом этапе я откровенно не блистал. После этого интервьюер сообщил мне, что данный этап собеседования завершен, и мы попрощались. (Сделанные выводы: стоит подтянуть задачи на DP.)
Честно говоря, мне как собеседуемому, хотелось бы видеть более стандартизированный процесс интервью без вводящих в заблуждение оценочных фраз.
Акт третий, мой любимый. System design
Приглашение на System design секцию стало для меня сюрпризом, поэтому я допустил две ошибки: выбрал не совсем удачное для себя время интервью и не уточнил, какой редактор для проектирования будет использоваться (казалось, что на первой встрече был упомянут Google Draw).
На интервью было предложено спроектировать Messenger (стандартный дизайн для FAANG собеседований). Решать задачу я собирался по удобной для себя схеме:
Сбор требований
Расчет ресурсов
HLD (High Level Design)
Обсуждение технологий
Возможно, обсуждение API, схемы БД
Обсуждение недостатков и компромиссов
Первые 2 пункта мы проскочили достаточно быстро. Я как мог боролся с неведомым прежде SketchTool и рисовал HLD. Сразу оговорил, что в мессенджерах используется WebSocket протокол, и объяснил, почему. При отправке сообщения оно должно было попадать в очередь, я предложил Kafka (предупредив, что мы будем относится с осторожностью к созданию большого количества топиков из-за ограничений на файловые дескрипторы). Оттуда сообщение направляется в Cassandra и, при необходимости, на Message Server.
В какой-то момент мы с собеседующим, казалось, полностью перестали понимать друг друга. Он настойчиво требовал изобразить на схеме, уже полной компонентов, flow с потоками данных (что для меня в скетчбуке оказалось просто невыполнимой задачей). По API я обратил внимание, что сообщения мы пересылаем по websocket, и роутиться запросы будут на основе посылаемого Payload, однако мы продолжили описывать API. По схеме данных я заострял внимание на partitionKey и важность их выбора, однако собеседующий не понимал, почему работать с большим партишеном плохо, и вообще закрадывалось подозрение, что он не хотел видеть в данном System Design BASE-системы, хотя расчеты говорили о другом.
Со своей стороны могу сказать, что прохождение данного этапа было далеко от идеала, ввиду путаницы по подключениям и генерации messageId, себя я бы оценил на 6 из 10.В конце собеседования я получил фидбэк, что мой System Design плох по perfomance и latency, так как содержит очень много компонентов и медленных сервисов вроде Kafka. Занавес. “Надо было рисовать 3 квадратика”, - подумал я, - “один клиент, другой - чат-сервис монолит, третий - vendor-specific db, вроде Oracle”.
Уже после этого интервью мне понадобилось зайти в чат приложения Тинькофф, и он сразу напомнил мне о заключительном этапе. Почему? Потому что чат постоянно терял связь с сервером по причине его недоступности. Здесь я понял, что был прав и от меня действительно требовался монолит в 3-х квадратах…
Заключение
Так почему же получилось “как всегда”? Конкретно на этапах, характерных для FAANGa, я выделил для себя несколько причин:
Собеседующие не были готовы вести такие собеседования. Они перебивали, не давали закончить мысль, вводили где-то в заблуждение.
Ни на одном этапе не был соблюден тайминг. Все этапы длились на 10-15 минут больше запланированного. (хотя на встрече с hr, было предложено ставить этапы друг за другом, но для себя я просил получасовой перерыв)
Во время интервью не было никакого сопровождения от HR, кроме начальной ссылки и назначения собеседований (к этому, конечно, тоже были вопросы, но это отдельная тема).
Не было знакомства с инструментами, которые использовались во время интервью
Хочется верить, что описание моих впечатлений окажется полезным и, возможно, поможет что-то улучшить. Мои предложения:
Заранее определиться с редактором для кодинга (если это будет online редактор, то высылать кандидату ссылку заранее, чтобы он мог поработать с редактором и настроить его под себя).
Не давать субъективных оценок уровню алгоритмических задач - слово “облегченные” может восприниматься разными кандидатами очень по-разному.
Предупреждать о том, какой именно редактор будет использоваться для System design, чтобы кандидат мог потренироваться. Все редакторы очень разные, и на своем опыте могу сказать, что привыкнув к популярным googleDraw и excilaryDraw, мгновенно переключиться на Sketch Tool было весьма тяжело.
Если вы стремитесь к распределенной архитектуре (судя по рекомендации книги “Высоконагруженные приложения. Программирование, масштабирование, поддержка / Мартин Клеппман”, это именно так), то стоит придерживаться её принципов и на System Design секции. Кроме того, в рекомендации можно добавить ссылку на книгу System Design Interview – An insider's guide (часто идёт в паре с рекомендованной вами).
Записывать этапы интервью для прояснения спорных ситуаций и получения второго мнения (если, конечно, вы не исходите из того, что собеседуемый заведомо неправ).
Если процесс интервью и вопросы являются тайной, то ввести NDA для собеседующихся.
Также отмечу, что вышеизложенный текст предназначался в первую очередь для самой компании Тинькофф, и после всех этапов я обратился к уже упомянутой инструкции и отправил данный текст на указанную там почту. На момент публикации статьи прошло примерно 2 недели - ответа пока нет.
Надеюсь, что эта статья будет полезна тем, кто собирается пройти собеседование в Тинькофф, а также компаниям, которые собираются внедрять похожие практики проведения интервью.
Надо стать геем и всё получится.