Yandex ШРИ Екатеринбург. Разбор тестового задания. Критерии оценки?

в 23:17, , рубрики: javacript, javascript, Yandex, разработка, тестовое задание, метки: , ,

image

В заметке будет приведен краткий обзор задания из анкеты Екатеринбургской Yandex школы разработчиков интерфейсов 2013. Мне бы хотелось остановиться на некоторых его тонкостях и предложить критерии его оценки.

Данная заметка из серии – «Выбора тестового задания для разработчиков. Критерии оценки». Она является подготовкой почвы для разговора с будущим разработчиком.

Замечу, что оригинальное задание должно быть выполнено на JavaScript, но, не смотря на это, данную заметку можно рассматривать без привязки к языку.

Задание

Напишите алгоритм карточной игры в «Пьяницу» на JavaScript. Интерфейс и возможности игры мы оставляем на ваше усмотрение и фантазию. В качестве ответа на вопрос пришлите ссылку на ваш код на jsfiddle.net или на github.com.

Правила игры

Происхождение игры в «Пьяницу» неизвестно. Есть мнение, что свое название она приобрела из-за простых правил и еще потому, что победа в игре зависит исключительно от везения. Играть в «Пьяницу» очень просто. На старте колода из 52 карт тасуется и делится между всеми игроками поровну. Далее каждый игрок кладет свою стопку карт перед собой «рубашкой» вверх. Игроки одновременно переворачивают верхнюю карту. Тот, у кого карта оказывается больше по достоинству, забирает все открытые карты себе и кладет их под свою стопку. Самой большой картой в «Пьянице» считается туз, самой маленькой — двойка.

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

Требования и критерии оценки

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

На мой взгляд, самыми важными критериями оценки качества кода является:

  • полнота выполнения задания
  • простота и понятность кода (читаемость)
  • легкость внесения изменений (расширяемость, продуманность архитектуры, качество декомпозиции)

Начнем разбираться по порядку.

Полнота выполнения задачи

В данной игре есть тонкие моменты, на которые стоит обратить внимание. Естественно, они должны обрабатываться корректно.

  1. Во время спора у одного из игроков могут кончиться карты.
  2. В игре может быть несколько спорных ситуаций подряд.
  3. Кол-во игроков, участвующих в споре может уменьшиться (например, изначально спор был между тремя игроками, после выполнения следующего хода спор будет продолжен, но уже только между двумя игроками).
  4. Во время спора, у всех спорящих игроков могут закончиться карты (в споре не будет победителя!)
  5. В игре вообще может не быть победителя (пожалуй, самая маловероятная ситуация, желающие могут посчитать ее вероятность).

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

Пятый случай я бы пометил двумя звездочками.

Читаемость кода

Под читаемостью я больше понимаю не следование стайлгайду конкретного языка, а правильность названия переменных и функций и отделение логических блоков. Так же понятно, что в коде не должно быть глубокой вложенности конструкций. Все это более – менее фундаментальные правила (фундаментальные – в смысле что относятся они не к конкретному языку и принятым в нем соглашениям)

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

Расширяемость

Легкость внесения изменений

Данный пункт, прежде всего, предполагает хорошую декомпозицию задачи. Выделение логических частей решения.

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

Приведем пример простых изменений:

  • Изменилось кол-во игральных карт (например, стало 36).
  • Кол-во игроков не должно быть фиксировано (зашито в коде), играть могут хоть 13 игроков одновременно.
  • Изменились правила игры – в игре появилось правило, что «2-ка бьет Туза».
  • Добавилось правило игры: «Если в споре нет победителя (у участников закончились карты), то спор продолжается среди всех игроков имеющих карты для начала нового спора» или «Если в споре нет победителя, то все спорные карты выигрывает самый правый / левый / случайно выбранный игрок»
  • После 20-ти игровых раундов каждый участник перемешивает свою колоду.
  • Выигранные карты складываются наверх/под низ колоды, а выкладываются на стол сверху/снизу/случайно выбираются из середины колоды. Ну, или все выигранные карты перемешивается и кладутся под низ колоды (аналог того, как мы складываем карты в жизни — мы не задумываемся о порядке сбора выигранных карт)
  • Другие интересные ситуации …

В идеале, мы должны будем поправить одну – две функции. Ну никак не перепиливать всю игру.

Отделение логики игры от ее визуализации

  • Хорошим плюсом является выделение игрового ядра. Понятно, что «игровая логика» должна быть отделена от «логики представления игры» (визуализации игрового процесса).
  • В частности, для JS характерно то, что игровая логика должна (при нормальном разделении) работать и на node.js.
  • Недопустимо смешивание кода отвечающего за внешнее представление игры и игровой логики. Я бы посчитал это грубой ошибкой.

Давайте рассмотрим на примере схемы то, как должна быть выполнена начальная декомпозиция задачи:

image

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

  • Отмечу так же то, что во VIEW желательно не допускать ничего связанного с шаблонами, особенно кусков HTML`я.
  • Можно оценивать то, насколько решение соответствует приведенной схеме.
Логика ядра

В задании упор делается на логику работы игры – это видно из его формулировки. И это правильно, поскольку это самая главная часть работы, от ее архитектуры зависит весь проект.

Поговорим немного об архитектуре ядра.

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

Давайте попробуем понять, что такое игра в «наших» (программистских) терминах. Игра – это последовательность раундов (ходов), каждый из которых как-то изменяет ее состояние. Зная состояние игры визуализировать сам процесс не сложно.

У меня, после этих рассуждений, в голову приходит модель конечного автомата. Ну, или более формально – конечный автомат с памятью (магазинный автомат).

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

Попробую представить в виде схемы процесс работы приложения (игры) и то, как она взаимодействует с ядром:

image

Названия для состояния игры я бы выбрал исходя из результата раунда, то есть выделил бы следующие названия для состояний:

  • Начало
  • Карты выиграл какой-то игрок
  • Раунд закончился спором
  • Раунд закончился победой игрока — игра закончена
  • Раунд закончился спором, но у спорщиков нет больше карт
  • Раунд закончился спором, но карт нет ни у кого – победителя нет, игра закончена
  • Такие названия очень хорошо показывают то, что можно визуализировать и то, на каком состоянии сейчас остановилась игра.

Так же, можно выделить основные сущности для данной игры: Карта, Колода (стопка) карт, Игра.

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

Пожалуй, это все основные критерии, по которым я бы оценивал работу.

Итог

Заметка получилась немного сумбурной, но я постарался изложить некоторые критерии оценки работы, немного коснулся того, как бы это реализовал я.

С первого взгляда задание кажется глупым и тривиальным, но при более глубоком рассмотрении в нем видны тонкие моменты.

Оффтоп

Можно посмотреть на результаты выполнения задания в сети, они легко гуглятся, среди них есть интересные. Особенно любопытные, могут, применив свои СИ способность, узнать победителей. Мне было интересно посмотреть как одну и ту же задачу решили разные люди.

А вообще, было бы интересно узнать, по каким критериям работы оценивали в Яндексе.

Автор: pahaz

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js