В

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

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

Однако меня всегда сбивало с толку одно: я знаю горстку невероятно талантливых людей, которые пишут высококачественный код для невероятно сложных вещей на работе, но регулярно терпят неудачу в самых элементарных технических заданиях на дом. Что дает? Должно быть что-то, из-за чего они плохо справляются с техническими заданиями, что никак не влияет на их профессиональный уровень.

Пересмотрев некоторые из своих предыдущих переживаний, я наконец сформулировал теорию о том, что это за «что-то» и как этого избежать.

Но имейте в виду: ни одна дискуссия такого рода не применима повсеместно и не может быть беспристрастной; Я говорю о том, что я лично наблюдал и испытал (также известный как моя собственная предвзятость).

Основы в стороне

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

  • Функционально правильно, у вас нет (или, по крайней мере, очень мало) багов.
  • Хорошие автоматические тесты.
  • Код выразительный, легко читаемый, хорошо структурированный и идиоматический для языка.
  • Приложение можно запустить/установить через командную строку.
  • Включен файл readme, рассказывающий рецензенту, как запустить эту штуку.
  • Некоторые комментарии, разбросанные по всему коду, никогда не помешают.

На мой взгляд, первые три обязательны для любого уровня. «Строгость» того, как они будут оцениваться, иногда будет зависеть от уровня позиции, но они будут оцениваться почти всегда.

Установив это, давайте начнем изучать более тонкую тему: как кто-то получает отказ в домашнем техническом тесте, даже если он соответствует всем критериям, перечисленным здесь?

Подробности в описании проблемы

«Они никогда не очищают свой пользовательский пул объектов и используют глобальный мьютекс. Для меня это НЕТ».

Нет двух одинаковых позиций. Например, даже внутри одной компании одна команда определяет инженера по бэкенду как «человека, который тесно сотрудничает с бизнес-аналитиками и разрабатывает ориентированные на пользователя API», а другая — как «людей, которые могут профилировать, устанавливать и настраивать реляционные база данных на голом железе»; там довольно широкий диапазон компетенций.

Чтобы сделать это еще более запутанным, разные компании и команды обычно ищут сочетание навыков: «должен быть очень опытным в работе с устаревшим кодом, также должен иметь представление о распределенных системах, знание k8s приятно иметь».

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

Я считаю, что это сделано не просто так: разные люди будут по-разному оценивать себя. Чрезмерно точное описание работы может заставить некоторых людей фильтровать себя и просто не откликнуться, даже если они могли бы быть хорошими кандидатами. Расширяя описание работы, компания по найму «оставляет за собой право» устанавливать планку приемлемой глубины знаний и оценивать ее в процессе собеседования.

Конкретно, в одной из команд, в которых я работал, большую часть времени мы тратили на работу с сумасшедшим количеством трафика. Вы забудете очистить кеш в памяти, и через несколько секунд у вас закончится куча, или вы «запишете что-то в базу данных» при запуске сервера и быстро поймете, что у вас есть 800 серверов, пытающихся заблокировать одну и ту же строку БД, ты понял.

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

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

Не имеет значения, использовали ли вы какие-нибудь умные приемы оптимизации производительности, пока ваше приложение блокирует глобальный мьютекс и эффективно является однопоточным. Спецификация явная: «параллелизм», а не какая-то «производительность» абстрактно.

Фальшивость решаемой «проблемы»

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

  • Какие части действительно важны, а какие не имеют значения.
  • Какова цена ошибки в конкретном пути кода.
  • Сколько трафика мы ожидаем получить при выпуске (например, вас, вероятно, не очень беспокоит масштаб, если вы можете загрузить весь набор данных из файла JSON).

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

«Внимательно прочитайте спецификацию» здесь не главное.

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

Вы не кодируете реальный продукт; весь контекст о результатах был либо уже сообщен вам, либо содержится в спецификации. Вы должны быть очень обеспокоены масштабируемостью, если можете загрузить весь набор данных из файла JSON, но в спецификации сказано, что «файл JSON должен эмулировать MongoDB».

Осознав это, я почувствовал себя очень глупо и смутился за свое прошлое:

«Это хороший код! Почему, черт возьми, это было отклонено? Они сосредоточились на случайных неважных вещах вместо того, чтобы смотреть на х».

Нет, не сделали, дурак!

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

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

Анекдот 1: Но он работает очень быстро… (провал)

«Подключитесь к следующему стороннемупровайдеру обменных курсов, используя эти учетные данные, не сообщайте их никому … Реализуйте свою службу с помощью платформы x и представьте результаты на HTML-странице, которая отображается, когда пользователь попадает на сервер по следующему пути…»

Было довольно странно, что в задании меня просили сделать пользовательский интерфейс; позиция была для бэкэнд-разработчика, а не для полного стека. Кроме того, что с упором на то, чтобы не делиться учетными данными для поставщика обменного курса? Услуга стоит около 5$ в месяц. Возможно, кандидат в прошлом использовал эту услугу для личного проекта или что-то в этом роде? Зачем вообще платить за этот тип услуги для использования в техническом тесте вместо отправки файла JSON (объем данных был незначительным)?

Ни одна из этих деталей не казалась достаточно важной. Что действительно казалось важным, так это то, что фреймворк, который они хотели, чтобы я использовал, был построен поверх Netty (реактивный/неблокирующий-io), и в то время я буквально читал «Netty в действии».

Мое использование future/promises было безупречным; Я даже интегрировал несколько слоев неблокирующих кешей. Мой код делал то, что должен был, работал очень быстро, и мой профилировщик не показывал пауз в потоке ввода-вывода. Отправим его!

Приходит обратная связь: отказ

  • Сохранены учетные данные для службы обменного курса в текстовом файле конфигурации (незашифрованном).
  • Не удалось учесть сбои или перебои в работе поставщика обменного курса.
  • Общается с интерфейсом через http вместо https.

Ой!

Обычно я бы не стал зацикливаться на защите учетных данных для стороннего сервиса только для чтения, который стоит 5 долларов в месяц. Но в задании мне было особо сказано не делиться ими, то есть относиться к ним как к конфиденциальной информации высокой ценности.

В профессиональных условиях мои сервисы защищены от Интернета своего рода шлюзом, который обрабатывает завершение TLS, поэтому HTTP будет в самый раз. Но в задании мне было конкретно сказано обслуживать и взаимодействовать с html-страницей, к которой обращается конечный пользователь, что бьет вас в лоб фразой «это открыто для общедоступной сети, используйте https», если вы действительно перестанете думать об этом.

Стыдно, но, на мой взгляд, заслуженно.

Анекдот 2. Слишком много декодеров (победа)

«Используя предоставленные файлы обменного курса, внедрите библиотеку, которая будет использоваться для конвертации определенного количества валютав другую. Преобразование может выполняться как отдельными парами, так и массово. Пожалуйста, используйте следующий репозиторий github для отправки кода и сообщите нам, когда закончите».

Давайте разберем это:

  • Очевидно, что арифметика с плавающей запятой здесь не поможет, но даже с выделенным типом данных мне нужно обеспечить желаемую точность. Какова соответствующая точность, не уточняется.
  • Предоставленные файлы обменных курсов представлены в трех различных форматах: XML, JSON и каком-то богом забытом пользовательском формате, который использует специальные символы в качестве разделителей пар.
  • Обычно я бы предположил, что «оптом» означает список входных данных. Зачем им запрашивать цикл for, который вызывает метод для преобразования отдельных пар?
  • Репозиторий Github, репозиторий github… большинство заданий (насколько мне известно) требуют почтовый индекс с кодом, отправленным по электронной почте.
  • Интересно, почему было использовано слово «библиотека» вместо «приложение» или «инструмент».

Проведя несколько часов, переворачивая спецификацию со всех сторон, я пришел к следующим выводам:

  • Полоса, кажется, использует точность 2 десятичных знаков; если это хорошо для них, это хорошо для меня. Проблема в том, что мой ввод имеет неопределенное количество десятичных знаков, и, судя по тому, что мне говорит Интернет, когда дело доходит до банков, «0,333 * 2» должно быть «0,67» в 2dp. Так что я потратил кучу времени на чтение банковских правил и переборщил с тестами для моей логики преобразования.
  • Я предполагаю, что файлы такие беспорядочные, потому что они хотят, чтобы я видел абстрактные «беспорядочные входные данные» из потока приложения. Я разрабатываю интерфейс своего декодера и прячу особенности каждого формата в конкретной реализации.
  • Неясно, означает ли «масса» сотни, миллионы или пары. В рабочей обстановке у меня было бы хорошее предположение, но не здесь. Я выбираю наихудший сценарий и реализую две конечные точки, одна из которых хранит результат вычислений в памяти, а другая использует схему контрольных точек, которая периодически сбрасывает результаты в файл (в случае, если вызывающий объект выходит из строя, он не должен перезапускать вычисление с нуля). .
  • Конечно! Во время предварительного отбора мне сказали, что эта компания занимается непрерывной интеграцией и доставкой. Они дали мне репозиторий github, чтобы проверить мою дисциплину git (сообщения о фиксации, тестовое покрытие отправленного кода, компилируется ли каждая фиксация и т. д.)
  • Библиотека… библиотека. Я предполагаю, что каждый вызывающий должен иметь возможность настроить, сколько потоков и сколько кучи доступно для этой библиотеки. Вы бы не хотели, чтобы какая-то библиотека случайных преобразований занимала все доступные потоки вашего критически важного для бизнеса приложения.

К счастью, обратная связь по этому заданию была доставлена ​​лично, поэтому я действительно мог спросить, верно ли мое обоснование. Вот что я узнал:

  • Их не заботило, сколько именно знаков после запятой я использовал, пока я думал об этом. Однако они действительно оценили обширное тестовое покрытие наиболее важной части приложения.
  • Файлы были беспорядочными, чтобы отбить у меня охоту запускать интеграционные тесты с «текстом в качестве входных данных». Они хотели видеть моки для провайдеров обменных курсов в тестах и ​​дизайн кода, позволяющий легко «перекачивать источники данных из файлов, например, в реляционную базу данных».
  • Навальный список входов. Моя схема контрольных точек была оценена, но в конечном итоге не потребовалась, это был отвлекающий маневр. Почему это было включено в спецификацию, мне до сих пор непонятно.
  • Я получил несколько серьезных баллов за дисциплину git. Я стараюсь поддерживать чистоту своих коммитов в командной среде, но когда я взламываю что-то на стороне, где я единственный участник, я обычно этого не делаю. Пуля увернулась туда.
  • Библиотека, еще один отвлекающий маневр. Они хотели посмотреть, добавлю ли я документы в свои интерфейсы, инструктирующие пользователя, как использовать мои общедоступные методы. Что я и сделал, за что получил похвалу, но конфигурация с максимальным использованием ресурсов была расценена как «чрезмерно спроектированная».

«Несколько чрезмерно продуманное, но в целом очень хорошо выполненное задание».

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

Закрытие

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

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

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

В некоторых вы потерпите неудачу, в некоторых преуспеете.

Важно понять механику и вместо того, чтобы по умолчанию «они сосредоточились на неправильных вещах при оценке» (что иногда верно), спросить себя, «возможно, вы сосредоточились на неправильных вещах при ее реализации».

Не верьте людям в интернете, цитирующим меня.

Альберт Эйнштейн