Задачи – очень хитрый инструмент, который позволяет оценить не только знания человека, но и его целеустремленность, умение нестандартно мыслить. Тут важно понять, хочет ли человек развиваться в этой сфере и интересно ли ему получать новые знания.
Мы не любим оценивать людей и их способности простыми плюсами и минусами, потому что это как черное/белое, которое не отражает важные оттенки реальности. Поэтому и задачи не оцениваем «правильно/неправильно».
В качестве примера мы попросили преподавателя Школы разработки интерфейсов компании «Яндекс» продемонстрировать собственный ход мыслей в решении одной из тестовых задач прошлых лет. К слову, если задания кажутся сложными – есть еще 7 дней до окончания приема заявок, чтобы углубить свои знания и успешно поступить в ШРИ.
Задача из анкеты для поступления в 2013 году
Автор решения: Илья Довбан, руководитель группы поисковых интерфейсов в минском офисе «Яндекса».
Вы — пилот грузового межгалактического корабля. Вашей работой является перевозка грузов с одной планету на другую. Грузоподъемность вашего корабля ограничена, поэтому за один рейс вы можете перевезти не более N кг полезного груза. Ваш корабль умеет сообщать свое состояние (местоположение и степень загруженности), а также летать в любую точку пространства или на любую планету. Каждая планета может содержать на себе груз, который может быть погружен на корабль или выгружен обратно на планету.
Задание:
В файле task.js дан интерфейс корабля и планеты. Эти интерфейсы не являются завершенными и скорее всего потребуют доработки. Напишите недостающий код.
Пример использования:
Перевоз 1000т груза с планеты B на планету A.
Решение:
На самом деле, в задаче уже сформулировано более половины решения: есть первоначально готовый интерфейс и есть почти написанные тесты (вызовы методов с ожидаемыми результатами работы). Последним, кстати, грех не воспользоваться при решении задачи.
Итак, начнем со стандартных штук. Форк репозитория с задачей и коммит про всякие инфраструктурные вещи. В данном случае вполне можно обойтись тестовым фреймворком. Я для тестов решил использовать Jasmine, поскольку его проще всего подключать к маленьким проектам.
Идем на сайт Jasmine BDD, скачиваем свежую версию, добавляем в проект тестраннер, пустой файл для тестов, подключаем все зависимости. Подготовка выполнена, можно приступать.
Самым первым шагом, конечно же, стоит внести наш «почти тест», который для удобства тут же разделяется на осмысленные блоки. Запускаем тесты и, вполне ожидаемо, видим, что все горит красным. Неписанный закон тест-ориентированной разработки запрещает коммитать с красными тестами. Поэтому пока что все проверки придется закомментировать. (коммит)
Теперь приступим к озеленению первого блока, в котором выполняется инициализация и проверка статуса. Раскомментируем первый блок, реализуем простейшие конструкторы и начинаем работать с методом report(). Особо сложной логики пока добавлять не надо, просто строка с реальными данными, в формате, который ожидает тест. Проверяем, убеждаемся, что в тестах все зеленое — можно делать коммит.
Вторым шагом проверяем перемещение корабля. Опять таки раскомментируем тестовый блок и начинаем стремиться к зеленому. Реализуем простейший необходимый метод перемещения и беремся за единственный способ проверки успешного перемещения — сообщение о статусе. Тут приходится исправлять уже написанную логику и сразу становится очевидной польза наших тестов: мы моментально видим, не поломалась ли уже написанная функциональность. Сама правка достаточно тривиальна: часть строки про местоположение корабля мы заменяем на проверку «а есть ли снаружи планета» и добавляем другой вариант сообщения. Проверяем, что в тестах все хорошо, оформляем коммит.
Приступаем к погрузке корабля. Опять-таки, тесты, достаточно простой метод про погрузку и правка сообщений о статусах у планеты и корабля. Так же, как и раньше, заменяем часть строки условием и двумя вариантами сообщения. Все здорово, тесты зеленые, можно коммитать, но… сейчас метод report() у корабля выглядит слишком сложно и запутанно. Надо бы добавить читабельности. Долго задерживаться на рефакторинге пока не буду, просто возьму второй пришедший в голову способ доопределения строки с каждым условием. Вроде выглядит получше. Снова тесты, проверяем, что ничего не поломалось, коммит готов.
По аналогии реализуем последний блок тестируемой функциональности про разгрузку корабля. Теми же шагами добиваемся зеленых тестов и ради единообразия оформляем метод report() у планеты в том же стиле, что и у корабля. (коммит)
Мы реализовали всю проверяемую функциональность, но в интерфейсе осталось еще несколько нереализованных методов. Естественно, их мы тоже будем покрывать тестами. Вот только в наш интеграционный сценарий они уже не очень вписываются. Пора перегруппировать блоки с тестами. Для начала, разнесем все тесты в две категории: проверка корабля и проверка планеты. Затем стоило бы сделать эти категории абсолютно независимыми. Потому при тестировании планеты используем «сферический идеальный корабль» и наоборот. Это заодно позволит более атомарно тестировать конкретные операции внутри методов. (коммит)
Теперь можно закрыть последние оставшиеся функции про чтение данных. Пишем тесты, реализуем методы… кстати, можно заодно перейти на них и в методах про погрузку-разгрузку. Проверяем, что все работает, коммитаем.
Следующим шагом хочется добавить проверки на крайние случаи: попытка погрузить то, чего нет или перегрузить сверх нормы корабль. Добавляем новые тесты, добавляем проверки, проверяем — все готово.
Вроде бы теперь все выглядит неплохо. Но любой код можно править и улучшать до бесконечности, внося новую функциональность, оптимизируя, повышая читабельность… Главное в этом деле – вовремя остановиться. Я считаю, что решение вполне достаточное, можно оформлять пулл-реквест и отправлять ссылку на него всем заинтересованным.
На самом деле, остался еще один последний штрих: надо причесать весь код синтаксическими и кодстайл-анализаторами. Пару блох JSHint должен найти. А если и не найдет — тем спокойнее.
Релоцировались? Теперь вы можете комментировать без верификации аккаунта.