Разработка
Как пройти кодинг интервью со мной
За последние 10 лет я провел более 400 кодинг-интервью. Это эквивалентно двум рабочим месяцам, в течение которых я наблюдал за тем, как незнакомые люди пытаются решить одну и ту же горстку задач по программированию. Некоторые из моих потенциальных коллег решали эти задачи без проблем, но у других возникали проблемы по схожим, легко устранимым причинам. Я хотел бы дать им более качественную обратную связь, но из-за юридических и временных ограничений система так не работает.
Поэтому вместо индивидуального совета я написал эту шпаргалку, содержащую 22 совета о том, как пройти собеседование по программированию со мной. Эти советы не заменят мастерства и практики, но они помогут вам успокоить нервы, избежать глупых ошибок и продемонстрировать максимум своих возможностей. Большинство советов легко выполнимы, а их совокупность позволит увеличить количество пройденных собеседований.
Перед собеседованием
1. Если вы предварительно изучаете вопрос в Google, удалите следы этого
Вы можете использовать Google для поиска вопросов, которые обычно задают в моей компании перед собеседованием. Это, конечно, противоречит духу компании, но я не уверен, насколько вы обязаны поддерживать целостность процесса собеседования в моей компании. Многие люди так поступают, и я полагаю, что это обычно очень полезно. Тем не менее, если я замечу, что вы это делаете, я буду вынужден наказать вас.
Если вы проводите собеседование на том же компьютере, на котором искали вопрос, не забудьте закрыть вкладки и удалить историю браузера перед началом собеседования. Я проводил собеседование с несколькими людьми, которые оставили открытой вкладку с вопросами. Интересно, что все они показали довольно низкие результаты.
2. Сделайте базовую программу и убедитесь, что вы можете ее запустить
Если вы используете свой ноутбук или компьютер, создайте базовую программу Hello World и убедитесь, что вы можете ее запустить. Записывайте свое решение в этот файл. Это позволит вам не тратить время в начале интервью на ковыряние в неработающей среде.
Я проводил собеседование с несколькими людьми, которые использовали ноутбук, принадлежащий их нынешней компании, но потом понимали, что компьютер был очень кастомизирован, и они не знали, как использовать его для написания и запуска даже базовой программы. Они обходили эту проблему, находя простую часть в кодовой базе своей компании и редактировали ее, чтобы ответить на поставленный вопрос. Это стоило им времени и стресса, выглядело некрасиво и, несомненно, нарушало их трудовой договор.
Представление
3. Сократите личное вступление
Обычно в задачу технического интервьюера не входит оценка вашего опыта и целей. Я могу начать собеседование с вопроса: «Меня зовут Роб, я работаю над тем-то и тем-то, а как насчет вас?», но это всего лишь средство растопить лед. Ответьте лаконично: «Меня зовут Сара, я работаю в команде по инфраструктуре в Badger corp. Наша работа заключается в том, чтобы убедиться, что наши серверы надежны, безопасны и просты в управлении». Бывало, что люди отвечали по несколько минут, ничего не добиваясь и тратя время и энергию.
4. Спросите, сколько времени у вас есть для ответа на вопрос
Спросите, сколько времени у вас есть для ответа на вопрос, чтобы соответствующим образом распорядиться своим временем. Я должен говорить об этом и так, без дополнительного вопроса, но иногда забываю, а интервьюируемые забывают спросить.
Когда вы получаете задачу
Когда вы получаете вопрос, я думаю, полезно иметь повторяющийся сценарий для проверки понимания того, что вас просят сделать, и для получения всех дополнительных метаданных, которые вам нужны. Я не думаю, что это особенно важно, но это легко реализовать. Я бы предложил:
- Кратко переформулируйте вопрос
- Задайте пару уточняющих вопросов
- Спросите, как вас будут оценивать
- Набросайте решение, которое работает, по крайней мере, для базового случая
Несколько дополнительных деталей:
5. Кратко переформулируйте вопрос
Я либо описываю вопрос, либо присылаю вам его письменный вариант. Как только вы решите, что поняли его, кратко переформулируйте его:
«Итак, задача состоит в том, чтобы вернуть все тройки чисел из входного списка, которые дают в сумме 0. Это правильно?».
Это позволит интервьюеру поправить вас, если вы что-то не так поняли, и, возможно, поможет установить взаимопонимание.
Возможно также, что я одобряю такую переформулировку вопроса только потому, что она показывает, что вы читали те же книги о том, что это хорошая привычка, что и я.
6. Задайте пару уточняющих вопросов
Как только вы поняли суть проблемы, попробуйте задать пару уточняющих вопросов. Это придаст вам осмысленный вид и, возможно, даже поможет ответить на вопрос. Два готовых варианта:
- Могу ли я предположить, что входные данные будут достоверными?
- Какой наибольший размер входных данных мы можем ожидать?
7. Спросите, как вас оценивают
Цель любого кодинг-интервью — написать хороший код в приличном темпе, но детали могут быть разными.
Как далеко вы должны продвинуться?
Некоторые собеседования состоят из нескольких частей, а некоторые намеренно содержат больше частей, чем каждый может успеть за отведенное время. Спросите, как далеко вы должны продвинуться, чтобы иметь возможность планировать заранее.
Для интервьюера важен эффективный код, чистый код или и то, и другое?
Некоторые интервьюеры ищут эффективный код, некоторые — чистый. Большинство, вероятно, ищет и то, и другое. Спросите их, что их волнует, чтобы вы могли сосредоточиться на правильных вещах.
Нужно ли писать тесты?
Простые модульные тесты помогут вам ответить на большинство вопросов (см. ниже), но некоторые интервьюеры могут не захотеть их писать, или некоторые вопросы могут быть плохо поддающимися тестированию (например, те, которые используют внешние зависимости, такие как HTTP-запросы). В этом случае лучше уточнить.
8. Набросайте решение, которое работает, по крайней мере, для базового случая
Начните с составления программы, используя слова или псевдокод. Не начинайте с написания реального кода. Даже если вы знаете, что на шаге 1 будет прочитан входной файл, читайте его только после того, как вы примерно знаете, что будете делать после этого.
Это, вероятно, поможет вам привести в порядок собственные мысли, а также позволит доброжелательному интервьюеру заранее исправить любые серьезные заблуждения или, по крайней мере, понять, откуда они взялись. Чем больше вы скажете и сделаете, тем больше баллов даст вам интервьюер, если ваш код не будет работать полностью.
Отладка
9. Часто запускайте свой код
После того как вы начали писать код, запускайте его как можно чаще. Некоторые люди начинают собеседования, на которые отводится 30 минут, с того, что пишут код в течение 15 минут, а затем проводят еще 15 минут, утопая в ошибках и неверных предположениях, которые обнаруживаются только сейчас. Чтобы избежать этого, часто запускайте свою программу. Распечатайте последнее состояние и убедитесь, что оно выглядит примерно так, как надо.
Если вы пишете 40 минут подряд, а потом прогоняете код один раз, и он работает с первого раза — ничего страшного, вы все равно сдадите экзамен. Но частое выполнение кода дает вам страховку на случай, если что-то пойдет не так. Это облегчает частичную оценку за частичное выполнение работы и, возможно, помогает быстрее итерироваться и решать проблемы.
10. Используйте гипотезы для отладки
Ваш код не всегда будет работать с первого раза. Когда он не работает, постарайтесь выдвинуть конкретные гипотезы о причинах этого. Попробуйте сказать, например:
Моя гипотеза заключается в том, что я неправильно фильтрую список. Чтобы проверить это, я собираюсь распечатать содержимое списка после фильтра, и теоретически в нем должно быть 5 элементов. На самом деле в нем действительно 5 элементов, так что проблема не может заключаться в фильтре. В таком случае проблема должна возникнуть после этой строки. В этой части кода я меньше всего уверен, поэтому добавлю еще несколько операторов печати. Теперь…
Гипотезы делают отладку методичной и более удобной. Они полезны и в реальной жизни, но сложнее иметь хорошие привычки, когда за этим никто не наблюдает.
11. Распространенные тривиальные ошибки
Люди часто сбиваются с пути из-за одних и тех же банальных ошибок. Три наиболее распространенные из них:
- Забывают сохранять файлы, поэтому продолжают работать со старой версией своего кода
- Пытаются прочитать входной файл из неправильного места, часто из-за неправильного указания относительных путей. Если есть сомнения, используйте полный абсолютный путь к файлу (например, /Users/rob/interview/data/input.csv вместо ../data/input.csv). Это неэлегантно, но простительно и сложнее запутаться.
- Путаются в том, мутирует ли метод свои входные данные или возвращают новый вывод. Вот в чем разница:
# ---- MUTATING ---- # CORRECT # sort() sorts the list by mutating it in-place inp1 = [3,7,1,8] inp1.sort() print(inp1) # => [1,3,7,8] # WRONG # sort() doesn't return anything, so using its return value is pointless inp2 = [3,7,1,8] out2 = inp2.sort() print(out2) # => None # ---- NON-MUTATING ---- # CORRECT # sorted() sorts the list by returning a new list, so we have to use its # return value inp3 = [4,8,2,9] out3 = sorted(inp3) print(out3) # => [2,4,8,9] # WRONG # sorted() doesn't mutate the input list, so using the same input variable # will not do what you want inp4 = [4,8,2,9] sorted(inp4) print(inp4) # => [4,8,2,9]
12. Просьба о помощи
Это крайняя мера, но если у вас совсем нет идей, то вы можете попросить о помощи. Я в любом случае подтолкну вас, если это покажется единственным выходом, но если вы уже знаете, что застряли, то лучше сказать об этом сейчас и сэкономить минуту-другую.
Обращение за помощью не означает, что вы потерпели неудачу. Возможно, вы хорошо справились с отладкой. Я могу забыть о том, что это произошло. Вы можете использовать сэкономленное время, чтобы произвести на меня впечатление в другом месте.
Разговор
13. Не ругайте языки, библиотеки и вообще что-либо
Некоторые люди при ошибках обвиняют свои чрезвычайно популярные инструменты, предположительно пытаясь сохранить лицо и терпя неудачу. Они говорят: «О, JavaScript, почему ты делаешь такие вещи?» или «Это просто одна из многих вещей, которые мне не нравятся в стандартных библиотеках Ruby». Возможно, они правы, но звучат они как плаксивые шуты.
14. Говорите так много, как только можете
Описывайте, что вы думаете и делаете, как можно чаще. Это поможет мне понять вашу работу и отдать должное вашему мыслительному процессу, даже если вы допускаете ошибки. Если вы решите вопрос идеально, не сказав ни слова, вы все равно сдадите экзамен, но комментирование дает вам страховку на случай, если что-то пойдет не так, и часто помогает вам работать лучше.
Написание кода
15. Не определяйте много функций или классов, если вы не уверены, что это хорошая идея
Функции, классы и другие формы абстракции навязывают программе структуру. Если вы поняли истинную природу решаемой вами проблемы, то абстракция может сделать ваш код более компактным, читаемым и удобным для сопровождения. Но если вы неправильно поняли суть проблемы, то абстракция может навязать неправильную структуру, заставив остальную часть кода неловко обтекать ее.
Если у вас нет полной уверенности в том, что блок кода должен быть извлечен в метод или класс, оставьте его как есть, снабдив комментарием TODO следующего содержания: TODO: вероятно извлечь это в метод. Это показывает, что вы думаете о структуре и абстракции, не обязывая вас ни к чему.
«Не абстрагируйтесь слишком рано» — хороший совет для реального мира, но он особенно важен на собеседовании. Издержки выбора неправильной абстракции выше, чем обычно, поскольку у вас нет времени на итерации. Еще хуже то, что вероятность выбора неправильного подхода выше, чем обычно, поскольку вы размышляете над проблемой всего несколько минут.
Еще хуже то, что хорошие программисты расходятся во мнениях относительно правильных абстракций. Полезная и логичная граница в вашем понимании может оказаться для меня ненужной сложностью. Я могу спросить о ваших решениях во время собеседования, дав вам возможность объяснить их, но могу и не спросить. Даже если я это сделаю, я могу не согласиться с вашими обоснованиями, и я могу быть совершенно не прав. Я начал проводить собеседования с кандидатами старшего возраста, имея всего 3 года профессионального опыта. Я уверен, что я забраковал хороших инженеров по плохим причинам, и я уверен, что я делаю это и сегодня. Если вы избегаете абстракций, то вы избегаете разногласий, в которых вы можете только проиграть, даже если вы правы. Напротив, трудно не согласиться со словами: «Я бы, наверное, превратил это в функцию позже, когда закончу остальную часть программы».
К сожалению, абстракция кажется вычурной, и многие интервьюеры не могут удержаться от того, чтобы не выглядеть умными. Слишком часто вместо этого они получают клубок перегруженной грязи, который замедляет их продвижение, ничего не дает и выглядит уродливо. Вы должны быстро заметить, где абстракция может быть уместна, но не спешить ее реализовывать.
16. Используйте TODO
Начните с того, чтобы ваше решение работало для базового случая, поскольку это, вероятно, главное, по чему вас будут оценивать. Большинство второстепенных проблем, с которыми вы столкнетесь в процессе работы, лучше решить позже, включая валидацию, обработку ошибок, краевые случаи и косметические исправления. Не беспокойтесь о них пока, а вместо этого пишите комментарии, описывающие работу, которую еще предстоит выполнить, например TODO: не хардкодить это значени.
После решения базового случая можно просмотреть все TODO. Можно удалить те, которые стали неактуальными, и отполировать те, которые еще актуальны. К этому моменту у вас будет еще 15 минут понимания проблемы, и вы сможете принять более правильное решение. Если вы не успеете решить их все, то тем самым вы покажете, что знаете, что нужно сделать, что позволит вам получить хотя бы частичную оценку.
Некоторые примеры:
-
TODO: обработать пустой ввода
-
TODO: проверить, что все числа в списке положительные
-
TODO: придумать более удачное имя переменной
-
TODO: согласовать эту логику с предыдущим блоком
-
TODO: обработать исключения
-
TODO: навести порядок
-
TODO: не надо жестко кодировать это значение
Тестирование
17. Написание тестов
Напишите базовые тесты, которые помогут вам проверить ваш код. Ваша программа должна выводить что-то вроде Pass,Pass,Pass, если тесты проходят, и Pass,Pass,Fail, если один из них не проходит.
# Good $ python3 interview_good.py Pass Pass Fail - expected: [3,9,2], got: [3,9,3]
Не распечатывайте возвращаемое значение программы и не проверяйте его вручную (например, [1,4,5] с последующим «о, да, похоже на то»). На глаз легко ошибиться, особенно если у вас несколько тестовых примеров.
# Bad $ python interview_bad.py [1,4,5] [2] [3,9,3]
18. Не используйте фреймворк для тестирования, если это не требуется или если вы не уверены в нем
Фреймворки тестирования хороши для создания удобных модульных тестов, но они требуют установки и настройки, что может легко привести к ошибкам и отнять много времени.
На собеседовании все, что вам нужно, — это простой способ убедиться в том, что ваша маленькая программа ведет себя правильно. Этого можно легко добиться с помощью простого кода, например:
actual1 = my_function([1,3,5]) expected1 = [2,4,6] if actual1 == expected1: print("Pass") else: print(f"Fail - expected: {expected1}, got: {actual1}")
Можно упаковать это в простой метод assert_equal, но я бы не стал заморачиваться. Небольшое повторение — это нормально. Вы даже можете сказать «в реальной жизни я бы использовал pytest», если чувствуете себя неловко.
Если вам действительно достаточно комфортно работать с конкретным фреймворком тестирования, чтобы использовать его на собеседовании, тогда вперед. Напишите пример теста для программы Hello World из Совета 2 и убедитесь, что вы можете запустить его заранее.
19. Если тест пройден, выведите pass
Если вы используете свой собственный базовый механизм тестирования, выведите на экран сообщение о прохождении теста. Если вместо этого вы продолжите работу молча, то, если ваша программа корректна, она выполнится и завершится, ничего не выдав. Однако это может произойти и в том случае, если программа завершается раньше времени по какой-то ошибочной причине. Означает ли следующее, что ваш код работает?
$ python3 interview_bad.py $
Вывод pass при прохождении теста означает, что вы знаете, что ваша программа выполнилась правильно. Этот вывод определенно означает, что ваш код работает:
$ python3 interview_good.py Pass Pass Pass $
20. Если все тесты проходят с первого раза, попробуйте сделать так, чтобы они не прошли
Если все тесты проходят с первого раза, то, скорее всего, у вас сломана система тестирования, а не вы гений. Добавьте в код ошибку и убедитесь, что некоторые тесты не работают. Если они не пройдут, значит, что-то не так с вашими тестами, а также, возможно, и с вашим кодом.
21. Не занимайтесь TDD в полной мере, если только вы не считаете его действительно полезным
TDD (test-driven development) — это практика написания сначала тестов, а затем кода, который проходит эти тесты. Некоторые присягают ей в верности, я же считаю ее трудоемкой и бесполезной. По моему опыту, когда на собеседовании кто-то пытается использовать TDD в полном объеме, это обычно занимает много дополнительного времени и не приносит никакой пользы. Если вы действительно предпочитаете работать таким образом, то действуйте, но не делайте этого, чтобы произвести на меня впечатление.
Если вы не слышали о TDD раньше, то не волнуйтесь и не изучайте его, по крайней мере, для моего интервью.
22. Сохраняйте свои тесты
Некоторые люди пишут один тестовый пример и изменяют его, когда хотят проверить другой входной сигнал. Это означает, что у них нет возможности проверить все другие входы, которые они пробовали за одно выполнение. Это приводит к ошибкам и регрессиям, а также к тому, что никто из нас не может сказать, работает ли программа для всех случаев или только для того, который проверялся последним.
Не модифицируйте тестовые примеры; напишите новый тест для новых входных данных, чтобы можно было протестировать их все сразу.
Итоги
Вот как пройти собеседование со мной. Пишите чистый код, берегите силы для того, что важно, и немного покажите себя, чтобы я заметил ваши хорошие стороны. У других интервьюеров будет свое мнение. Разные компании ищут разные вещи, и даже разные люди в одной и той же компании ищут разные вещи, несмотря на усилия руководства по стандартизации.
Но даже если у других людей могут быть другие приоритеты, а собеседования — это полумера, я все равно считаю, что советы, приведенные в этой заметке, — это универсальные хорошие привычки, которые помогут вам пройти кодинг-интервью. Удачи вам, и дайте мне знать, как вы справляетесь!