Тестовое задание для junior или middle разработчиков обычно показывает их реальный опыт и понимание предметной области, однако для senior'а тестовое это немного другое. Расскажу свою историю написания маленького тестового задания на Angular с использованием лучших практик.
С чего все началось
У нас в компании обычно жестко распределены роли между разработчиками. Каждый разработчик отвечает за свою часть проекта и ее поддерживает.
Что-то поломалось в 2 часа ночи, отличное время чтобы это исправить. А еще разбудить пару человек, а то что ты один работаешь, а остальные спят.
У каждого есть некоторые волонтерские роли. Например, кто-то устраивает корпоративы, кто-то собеседует других разработчиков, кто-то занимается закупками мебели и железа.
Я же обычно пишу ревью на тестовые задания, которые мы иногда даем разработчикам, чтобы понять их уровень, если этого не получилось сделать в ходе собеседования.
Хотя мы все против тестовых заданий, так как считаем их отталкивающей практикой, все-равно иногда появляется разработчик, который 50/50 и непонятно что с ним делать. Чаще всего мы даем тестовое задание, которое можно сделать за 3-6 часов.
У нас простенькое тестовое задание на Angular:
Создать формочку с 3-4 полями, добавить создание объектов и сделать сохранение в localStorage. Опционально добавить карту и вывести объекты на карте.
Цель тестового показать работу c RxJS, Redux, DOM, Работа с формами (Angular Forms) и желательно написать unit тесты, желательно на jest'е.
И однажды делая ревью на тестовое задание кандидата, я написал вот такой фидбек :
Плюсы
Проект запускается
Проект реализует часть тестового задания
Замечания
Не соблюдаются рекомендации оформления (src/app/components/air-routes/air-routes.component.ts:32, src/app/services/data-tickets.service.ts:22)
Нет порядка в privite/public свойствах (src/app/components/air-routes/air-routes.component.ts:14)
Нет адаптивности в верстке - 480px все поехало
Компоненты не используют ChangeDetection
Нет lazy loading'а
Нет тестов, а автосгенерированные не проходят.
Работа с нативным API (localStorage) сделана очень не умело и не обрабатывает кейсы, не говоря про реализацию самой логики.
Есть неиспользуемый код, который можно удалить
Подключен Angular Router, который не используется
При запуске проекта, на главной странице какой-то треш
Маршруты строятся не верно. Если ввести A (today) -> B (today + 1) и В (today + 1) -> A (today + 2) - то маршрута A - B - A не будет
Нет валидации на даты вылета и прилета - можно выбрать дату прилета из прошлого
Нельзя удалить маршрут
Нет работы с таймзонами
Данные в шаблоне статичны. Можно было хотя бы прелоадеры сделать с текущей даты
Неважные моменты
Нет чувства прекрасного, нет вау эффекта
Плохо названы переменные (src/app/components/table-ticket/table-ticket.component.html:12, src/app/components/air-routes/air-routes.component.ts:38)
Все стили взяты из внешней библиотеки, нет ни строчки кода SCSS
Что почитать:
Обновить знания, прочитав документацию по Angular (style-guide, routing, services, testing)
Прочитать разделы документации по Typescript, связанные с созданием типов.
Обновить знания по JavaScript, и использовать современные конструкции и функции языка
Ознокомиться с Redux в Angular (на примере Ngrx, ngsx)
Ознакомиться с unit тестированием на примере karma, jest
Ознакомиться с современными инструментами разработки Nx
И перечитав список замечаний, я подумал, что было бы круто, если бы кто-то меня отревьюил.
Не долго думая, я решил сделать небольшое тестовое задание, которое было бы показательным, чтобы его можно было бы скинуть кандидату и сказать, чего мы хотим.
Разработка тестового задания
Замечу, что у меня "ангулярность". Если вам противен Angular, то перед прочтением посоветуйтесь с вашим ведущим разработчиком, иначе это может вызвать желание миграции на Angular.
И в качестве тестового задания я решил выбрать следующее:
Разработать небольшое приложение, где пользователю показывается карта; на домах расставлены точки (пины). При клике на пин, нужно отобразить информацию о доме. Должен быть функционал добавления пина с соответствующей информацией, а также необходимо реализовать удаления пина. Данные хранить в localStorage.
Еще раз прочитав я подумал, что это можно сделать за пару часов (или дней).
Основные приложения, которые я разрабатываю на основной и любимой работе, используют решение Nx - это реализация монорепозитория для Angular и не только. Однако я еще ни разу не встречал тестовое задание, которое было бы написано с использованием Nx. И поэтому, чтобы не усложнять, я решил использовать стандартные Angular CLI для создания приложения.
Но Nx дал о себе знать, когда я начал создавать приложение. Когда я создавал приложение, Angular еще был 11 версии, а как известно в этой версии еще не было поддержки eslint'а. Пришлось перейти на eslint и добавить prettier.
Затем, увидев karma, я конечно, всплакнул и бесцеремонно удалил karma и настроил тестирование с помощью jest.
Так как Nx предполагает разработку нескольких приложений и набора библиотек, я решил создавать алиасы в TS и использовать их. Это уже не прихоть, а необходимость, так как это позволяет сделать разграничение доступа между модулями("библиотеками").
Когда я начинал разрабатывать проект, я решил не делать git flow, так как я один и пользы в этом особой нет. Но когда меня упрекнули в этом, я безвольно подчинился и ближе к завершению начал создавать ветки по функциональности и вливать их.
На настройку окружения ушло около часа, осталось еще 3.
Первые звоночки
Начинаем делать проект. И тут я попал в ловушку готовых решений. В данном случае я имею в виду, что разрабатывая тот или иной проект, есть определенный набор решений, который вы используете помимо основного фреймворка. Например, есть сервисы для работы с наборами параметров, которые обрабатывают переменные docker'а, envirionmentService - который унифицирует доступ к environment'ам в Angular и много чего еще. Но в новом проекте этого нет, и что делать с этим не понятно.Я решил перетаскивать по мере необходимости.
Но так делать не стоит. Получилось около 12 core lib, а это явно усложнение тестового задания.
После переноса части библиотек для упрощения работы, я начал с базового - создания шаблона для всего приложения, который включил в себя шапку и подвал, а также определил место вывода основного контента.
Понятно, что свой UI-kit писать не стоит, я взял за основу Angular Material. Но самый главный недостаток Material - нет четкого решения для создания сеток. Видимо разработчики решили, что проще использовать нативный CSS и создавать все через flex, но это же нужно делать.
В итоге, я решил перенести еще одно решение и создать папочку UI, где разместились: сетки, спиннер, карусель и иконки.
Концепт сеток я честно украл у bootstrap и сделал микро реализацию на Angular.
Хотя в Angular есть Angular Flex, который позволяет делать что-то аналогичное, само решение мне не нравиться и взял временами проверенный велосипед.
Создав макет пришло время реализации бизнес логики. Так как Redux наше все, я подключил Ngrx и создал RootState, который является Store.
Перенеся часть утилит из Nx, в частности DataPersistence, я добавил оператор fetch для effect'ов в Ngrx.
Так как весь проект представляет собой часть Airbnb, я создал базовые сущности, создал соответствующие state, сервисы по работе с сущностями, сервисы по работе с нативными хранилищами, фасады и manager'ы, которые подключают в себя разные сущности и отдают гибридные значения.
К этому моменту, наверное уже прошла неделя с момента начала написания тестового задания. Конечно, я писал его только вечерами, где-то по 2-3 часа перед сном, как говорится чтобы лучше спалось. Но верстки еще не было, как и много чего еще.
В этот момент я понял, что написать просто тестовое задание я уже не смогу, но нужно использовать материал по максимуму. Я решил сделать обзорное тестовое задание, в котором бы рассмотрел создания микро приложения от начала до конца, чтобы после прочтения статьи у читателя было понимание, как готовить Angular.
И тогда я открыл habr и начал писать. Однако, когда объем стал слишком большим, я решил, что это будет неправильно и решил разбить статью на несколько маленьких лаконичных статей, где каждая статья бы показывала решение той или иной задачи.
В результате у меня получился цикл из 27 статей посвященных созданию тестового приложения, которые я разместил на своем блоге на Mediume - Тестовое задание на Angular. Введение. Результат можно глянуть на гитхабе: https://github.com/fafnur/barinb.
В результате получилось следующее:
В цикл статей попал почти весь процесс разработки, начиная с установки и разработки приложения, заканчивая тестированием и деплоем.
Возможно статьи покажутся кому-то слишком пустыми, но обычно такие статьи редко читают, обычно все смотрят исходный код и пытаются понять, что и как сделано.
Где все пошло не так и как к этому относиться
Момент, когда микро приложение стало перерастать в что-то большее, я заметил не сразу. Конечно, основная проблема тут в постановке задачи, так как я больше старался показать разные аспекты, а не выполнить поставленную задачу, в частности быстро написать приложение, которое работало бы.
И тут я задумался о том, а вообще есть смысл в тестовом задании для senior'ов. Мне трудно говорить про свой опыт, так как я думаю я просто высоко оплачиваемый junior, но я решил спросить своих коллег и знакомых на этот счет.
Большинство ребят ответило, что в принципе не делает тестовые задания в РФ. Многие относятся скептически, так как github больше скажет, чем какое-то ненужное задание.
Из тех, кто делал что-то аналогичное, очень часто сталкивались с таким же результатом, что маленькое приложение перерастает в pet проект и так далее.
Забавно, что все подобные проекты заканчиваются когда появляется жена и ребенок. И с большому сожалению, многие это подтвердили.
Резюмируя все выше сказанное, можно подвести итог:
Вы можете дать тестовое задание senior'у, но шанс, что он его выполнит или выполнит его так, как вы бы этого хотели минимален. Это связано с тем, что разработчик потащит огромный пласт своих "готовых/проверенных" решений, которые в свою очередь могут слишком усложнить проект, который не будет завершен.
Большинство разработчиков, которые не умеют разделять бизнес и работу, скорее всего усложнят проект и поэтому тоже могут погрязнуть в рутине и закончить проект гораздо позже, чем требовалось.
Если вы все-таки хотите давать тестовые задания, стоит придерживаться следующих правил:
Должны быть сроки на выполнение
Задание должно быть максимально детализировано, в идеале даже сделать небольшой протитип для UI.
Явно обозначить что должно входить в тестовое задание и чего быть не должно.
Сделать акценты на те части задания, которые вам кажутся наиболее важными, чтобы разработчик делал действительно то что нужно вам, а не свое авторское видение задачи.
Надеюсь, что это поможет сэкономить время вам и тем разработчикам, которые решат выполнить тестовое задание.