javascript

Почему я не готовлюсь к алгоритмическому интервью

  • вторник, 12 ноября 2024 г. в 00:00:03
https://habr.com/ru/articles/856904/

И не очень люблю людей, которые к нему "готовы". По моему мнению, главное на интервью - это понять как человек думает и как решает проблемы.

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

Давайте проиллюстрирую на простенькой задаче.

В JS есть функции Math.round() - округление числа к ближайшему целому и Math.floor() - округление числа к меньшему целому. Нужно написать функцию (f) округления положительных чисел к ближайшему целому, используя только Math.floor. Чтобы чуть сократить путь — сразу ставим условие, что нам нужна функция стрелка в одну строку (без создания промежуточных переменных)

Есть очень просто и красивое решение, если соискатель его знает, то всё "плохо". Придётся доставать из загашника что-то ещё. А вдруг там пусто?

Но, пусть нам повезёт, и соискатель "не подготовился". Тогда, скажем, получим:

const f = (x) => x - Math.floor(x) >= 0.5 ? Math.floor(x) + 1 : Math.floor(x)

Огонь! Соискатель знает что такое округление, понимает как получить дробную часть. Если не знает, я не против рассказать. Даже интереснее будет. Кстати, если нет скобок приоритета, как в данном выражении, и соискатель может объяснить почему, это огромный плюс. А если скобки есть, например, так:

const f = (x) => (x - Math.floor(x) < 0.5) ? Math.floor(x) : (Math.floor(x) + 1)

То тут... нет криминала. Я сам, хоть не плаваю в вопросе приоритета операторов, но часто предпочитаю написать лишнюю скобку. И быть уверенным что все сработает так, как я задумал. Всё равно prettier лишние скобки корректно уберёт. А вот если чуть накосячить, то нужные он не поставит.

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

Пробуем повысить до миддла. Задаём вопрос: «А как сократить количество вызовов функции округления?»

const f = (x) => Math.floor(x) + (x - Math.floor(x) >= 0.5) ? 1 : 0 

Ок. Тут можно порассуждать: будет ли функция работать с отрицательными числами и почему нет. Ответил? Считаем, что миддл детектед. Опять же не точно, и нам бы, в идеале, нужен сеньор, хотя бы потенциальный. Поэтому усложняем : «А как сделать тоже самое, но с одним вызовом Math.floor?» И можно зависнуть в телефончик минуты на три (ибо вроде никак — нужна промежуточная переменная).

Выждав ровно 180 секунд, как и запланировано, выдаём подсказку: «И без тернарного оператора». Да-да, это подсказка. Даём ещё пару минут, но надеемся, что соискатель ещё не догадался. И предлагаем отложить задачу, а пока решить вот такую:

Написать функцию-стрелку (f), которая принимает на вход либо 2, либо 5 (гарантированно, что ничего другого прийти не может). И возвращает: если на входе 5, то 2, если 2, то 5. Использовать оператор нельзя. Время пошло.

По прежнему нет идей? Хорошо, подсказка: "а что будет, если сложить 5 и 2?"

Не помогает, ладно, упрощаем задачу:

На вход приходит строго 0 или 1, нужно получить соответственно 1 и 0

const f = (x) => +!x

Огонь. Кандидат умеет в идиомы и понимает в конверсии типов (в js префиксный плюс, это устоявшаяся идиома для конвертации в number, кстати, можно и про неё поговорить). Но нам нужно решить эту задачу со знаком минус, то есть с операцией вычитания, на что и намекаем. Если не помогает, что уже скорее грустно, подсказывает, что х надо именно отнять. Вопрос: от чего?
И, внезапно, сверкает лампочка:

const f = (x) => 1 - x 

Возвращаемся к задаче 5/2, уже проще? 5 + 2 = 7 значит:

const f = (x) => 7 - x

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

Скрыл решение для тех, кто пока не догадался, но хочет таки сам
const f = (x) => Math.floor(x + 0.5)

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

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

Но об этом чуть позже, а пока к задаче. Пока мы её успешно решали, я получил много информации. Насколько человеку интересны все эти танцы, как он думает, как он борется с задачей: накидывает идеи, варианты или тупо сидит. Насколько у него загораются глаза. Для меня (и многих "работодателей") более интересен кандидат, который не (сразу) решил задачу, но, при получении решения, искренне восхитился (а что так можно было?), чем тот, кто скучно скажет: "ну это слишком элементарно, и в реальной жизни вряд ли понадобится".

Если честно, в реальной жизни умение решать "алгоритмические задачи" не то чтобы не понадобится, но за 30-летнюю "карьеру", у меня было только одно место работы, где чаще, чем раз в месяц приходилось решать задачи близкие к алгоритмическим. Т.е. задачи, где надо было использовать не рутинные инструменты, чтобы сделать вот такое-эдакое, что раньше не делал (и скопипастить неоткуда). И чтоб оно работало шустро. В среднем, "блистать" в алгоритмике удавалось раз в квартал, а то и реже. Притом, что я большей частью работал "на переднем крае", практически в RnD. Поэтому алгоритмическое мышление важно, но не требуется, чтобы оно было спортивно-алгоритмическим. Т.е. в реальной жизни задача, на которую на собесе выделяется полчаса, может решатся и сутки-двое и бизнес это вполне устроит. Более важно её корректно решить, предусмотрев все кейсы, где что-то может пойти не так (и написав тесты), чем решить быстро, но небрежно, перегрузив тестирование и опять же потратить ещё и своё "сэкономленное" время на правки ошибок.

Поэтому на собеседовании не надо бояться, что задача идёт туго, нужно просто планомерно искать решение: умный интервьюер этого и добивается, а глупый... Ну что-то мне говорит, что не очень хорошая идея работать в коллективе, где все прошли через фильтр глупых интервьюеров. Если мне на собеседовании попадается задача, которую я знаю, я сразу говорю: "О! А я её на собесе яндекса решал: тут надо не постесняться сразу отсортировать массив, а дальше сложность только в ...". Интервьюер может сразу перейти к запасному аэродрому, а может поговорить о задаче, попробовать усложнить условия, спросить ошибался ли я при решении и где.

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

И в реальном энтерпрайзе редко заморачиваешься, например, производительностью. Местами обосновано. Если у тебе n редко больше 10, а в среднем вообще n=1, то выбор между алгоритмами O(n log n) и в O(n3), только в том, какой легче написать, протестировать и поддерживать. Вот Microsoft со своей пузырьковой сортировкой иконок не даст соврать. Да плохой пример, но начальство любит больше того, кто за 15 минут выдаст код O(n2), чем того, кто неделю потратит на O(n log n), для списка выпадашек дропдауна. Есть области, в которых оптимизация чуть менее чем всего, необходима чуть реже чем всегда (например, игры), но 90% общего по миру кода, можно (и выгоднее) не оптимизировать. И да, это тоже часть работы, умение понимать, где надо, а где совсем нет.

И последнее (и закругляемся). Умение в алгоритмические задачи на пятерочку с плюсом, хорошо для джунов, и где-то миддлов. Видно, что человек заморачивается, прокачивает себя. И для сеньоров на позиции чистых RnD алгоритмистов - это их хлеб. А обычный сеньор, который оказывается звездой на letitcode вызывает вопросы. Когда он нашёл время на все эти задачки? И почему он хорошо помнит их решения (я вот несколько раз на собесах писал что-то по красно-черным деревьям, но дай мне задачу снова - снова буду тупить, решу, но буду тупить по ходу). У него много свободного было времени на прошлой работе? А работа? Дома? А не проще было что-то полезное пописать, не придумал свое - вон можно можно было в Линуксе до мантейнера дорасти.

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

Удачи на собесах. Обоим сторонам.