Никто не любит тестовые задания: долго, дорого, не всегда показательно. Но на стажировке от тестовых не отказаться из-за большого потока желающих без портфолио и опыта работы. Несколько лет мы в Контуре проверяли бэкендеров одной большой задачей, которую придумывал и проверял один разработчик. А потом все сломалось и поэтому изменилось. Рассказываем, как не надо делать тестовое, и как теперь выглядит наш отбор на стажировку.
Почему на стажировку нельзя без тестового
Ежегодно мы получаем около 1 000 заявок на стажировку. Поговорить с каждым кандидатом не получается — на это уходит много времени и сил. Посмотреть на портфолио чаще всего тоже нельзя, потому что аудитория стажировки — студенты. Поэтому в отборе на стажировку не обойтись без тестового: с ним мы не тратим зря время кандидатов, HR’ов и собеседующих разработчиков.
Раз уж отказаться от тестового нельзя, оно должно быть интересным, занимать не очень много времени на выполнение и отражать требования компании к разработчикам. Теперь у нас шесть задач, которые проверяют базовые знания и нужные нам навыки. Но это сейчас мы такие оптимизированные и разумные, раньше было по-другому. Сначала были грабли, увольнения и затянутый отбор.
Одна голова на все процессы
В 2019 году тестовое на стажировку в Контур — одно большое задание, которое проверяло сразу несколько навыков: базовые знания программирования, чистый код, алгоритмы, структуры данных и что-нибудь еще, что мы проверяли, проходя мимо. Как решить, что именно вот этот кусок задания за чистоту кода, а этот — за структуру данных? Как сделать единообразную шкалу оценок и проверить тестовые?
Чтобы страдание было комплексным, задание придумывал один разработчик, он же проверял все тестовые. Гайдов, чек-листов, критериев проверки не было, потому что задача менялась каждый год, а весь контекст хранился в голове одного разработчика.
Задачу он придумывал долго, потому что параллельно работал над текущими тасками в проекте. Автотесты были, но ручная проверка все равно сжирала много времени.
Задача в тестовом была сложной. Ходила шутка (или не шутка), что тот, кто решит тестовое, может сразу трудоустраиваться джуниором, а не стажером.
Долго так работать не получится. И у нас не получилось.
Больше голов нет
Державший весь этот контекст разработчик уволился посреди отбора на стажировку (не из-за нее). Тогда кампанию затянули, но довели до конца.
До этого мы годами не трогали тестовое, потому что ?р?а?б?о?т?а?е?т? ?—? ?н?е? ?т?р?о?г?а?й?. Но увольнение стало поворотным моментом. Накопилось несколько других противоречий: большое тестовое сложно придумать, сложно сделать и сложно начать решать. Проверка затягивается (пока автотесты, пока код-ревью…). Басфактор: некому подхватить, если у создателя тестового завал/болезнь/увольнение. Чтобы прочувствовать боль до конца, посмотрите, как выглядело последнее мегатестовое.
Все сошлось — нужно было переделывать.
Подопытные проекты
Раскатывать изменения сразу на стажировку не стали, начали экспериментировать на проектах поменьше и стартанули со Школы промышленной разработки (Шпора). Там проблемы с тестовым были почти такие же, как у стажировки:
Слишком сложно для студентов 2-3 курсов.
Студенту трудно подступиться к такому большому заданию.
Теряется мотивация: даем часть автотестов, студент отправляет решение и даже не представляет, что оно не проходит скрытые автотесты. Одна опечатка или глупая ошибка — всё, автотесты не проходят, ты не можешь сдать задачу, а найти ошибку не получается.
К решению проблемы привлекли бывших студентов курсов — разработчиков Контура. Сформулировали, что хотим проверять, решили делать это через 6 задач (одна задача — один навык), сделали и разместили на Ulearn — это наша площадка с курсами по программированию. В ней есть все нужные для тестового инструменты: автотесты, антиплагиат, инструменты для код-ревью.
Нам все нравилось, но важнее была реакция целевой аудитории — студентов-будущих стажеров. Позвали порешать новое тестовое прошлогодних шпорунов (как целевую аудиторию, ведь они совсем недавно выпустились или продолжают учиться) и получили хорошую обратную связь. Результаты почувствовали и в бою:
Тестовые сдавали быстрее. Если раньше большую часть тестовых мы получали ближе к дедлайну, то в этот раз много решений получили в первые дни после публикации.
70 решенных тестовых и 138 тестовых с хотя бы одной задачей вместо 63, решенных в предыдущем году.
Мы признали эксперимент успешным и перешли к изменению тестового на стажировку.
Что и как оцениваем?
«Мы решили проверять у кандидатов умение писать чистый код, способность разбираться в чужом коде, навык писать код с нуля, понимание алгоритмов, знание, как искать информацию, чтобы разобраться в задаче и решить ее. Эти навыки выбрали, как часто встречающиеся в работе разработчика, плюс такие у нас представления о хорошем стажере и разработчике Контура», — рассказывает Костя Воливач, один из создателей нового тестового на C#.
Дальше продумали критерии каждого навыка. Наиболее интересное — проверка чистоты кода. «Мы попытались сформулировать критерии, исходя из принципа “код читается чаще, чем пишется”?», — рассказывает Леша Пепелев, один из создателей тестового и разработчик критериев оценки. Вот что у нас получилось:
Чистый код не врет. Чтение такого кода не превращается в детектив, где тебя пытаются ввести в заблуждение. Намерения чистого кода выражены в именах классов, методов и переменных и совпадают с фактическим поведением. Если метод называется GetNode, то он должен вернуть узел вызывающему коду, а не сложить его в поле класса. Как проверить себя? Уберите из кода тела всех методов. Можно ли по выжимке догадаться, как работает решение?
Чистый код можно читать с любого места. Если решение состоит из набора классов, то каждый из них представляет что-то цельное. Смысл отдельного класса можно увидеть, не заглядывая в другие классы. Как проверить себя? Удалите из класса все методы, оставьте один. Опишите его, отвечая на вопросы «что он такое»?, а не «что он делает»? без ссылок на удаленный код. На уровне отдельного класса удалите из класса все методы, посмотрите на свойства и поля. Если понять суть можно только по использованию, вызывайте рефакторинг.
У чистого кода явные зависимости. Читающий должен четко понимать, от чего зависит метод и в чем результат его работы. Как проверить? Спросите себя, можно ли при рефакторинге сломать код, если переставить строки местами или удалить вроде бы ненужную строку?
Лучшим решением договорились считать такое, на понимание которого ревьювер тратит меньше всего времени (после прохождения всех остальных критериев).
Добавляем контекста и боремся с формулировками
Новое тестовое придумывают два разработчика, каждый берет по три задачи. Чтобы задачи не висели в вакууме и условия воспринимались легче, мы сочиняем для каждой предысторию. Например, в тестовом-2020 есть задача с интерпретатором:
Остров Кижи появился здесь, потому что один из любимых языков Кости, автора задачи, — Kotlin. Он назван в честь острова в Спб.
Другая задача на рефакторинг родилась из плохо работающего пульта от телевизора. «?Я решил связать неработающий пульт и телик в одну задачу. Сюжет такой: пульт не работает, потому что код написан плохо, есть ошибки. Разработчик очень торопился, поэтому качество кода низкое, а ревью пропущено. Мы написали примерный код, специально его испортили и запутали»?,— рассказывает Костя Воливач.
Ревью задач проводят 10 разработчиков, они проверяют уровень сложности, формулировки и общую концепцию. Метрика такая: если миддл справляется с задачей за час, все ок, если уходит больше времени, задачу нужно пересматривать.
Самое сложное в тестовом для авторов — лирика. «В прошлом году мы поняли, что стажеры не понимают формулировки задач. Тогда мы решали вопрос вручную: пришел вопрос по формулировке — идешь в задачу и правишь текст», — вспоминает Костя. В этом году проверили формулировки заранее на программистах и на редакторах — должно стать лучше.
Тестовые проверяют 10 разработчиков. Каждый отвечает за проверку одной задачи во всех тестовых.
Что по метрикам
В 2019 году с одной большой задачей мы получили 55 тестовых. В 2020 году все шесть задач решили 63 человека, и ещё 281 кандидат решил хотя бы одну задачу. В 2019 году мы проверяли тестовые больше месяца, в 2020 году на это ушло две недели.
После всех нововведений стало легче, прогресс стал нагляднее, а значит мы можем реагировать на ход решения.
Если мало человек решили все шесть задач, спрашиваем в чатах, что останавливает остальных, делаем рассылки. Если видим, что решают многие быстро, ищем дополнительных проверяющих.
По 2021 году у нас пока нет полных данных, но мы уже видим, что скорость сдачи тестового высокая. Автотесты появились только 15 февраля, а к этому моменту у нас уже 28 человек с шестью решенными задачами.
Хотите проверить формулировки (ну и посмотреть задачи, конечно)? Набор на стажировку открыт и тестовое лежит на Ulearn. Чтобы посмотреть тестовое и начать решать, вступите в группу.
robesper
Почитал мегатестовое и немного бы его изменил. В свое время решал похожее. Там нужно было наоборот многопоточное решение. Оно добавляло изюминку)… и заодно проверку знаний потоков.
Yuliya_42 Автор
А как изменили бы?
robesper
Операция сжатия/разжатия требовательна к ресурсам процессора. Поэтому я бы предложил зачитывать файл и паралелльно проводить упаковку/распаковку. Это ускорит производительность программы, хотя и повысит потребление ресурсов. Задание при этом усложнится (причём до уровня junior, а может и middle исполнителя), но при этом станет интереснее.
Да простят меня стажёры!)