Ранее в нашем блоге мы рассказывали о квизе для C++ разработчиков. С момента запуска мы тщательно собирали обратную связь. Часть из неё касалась ошибок в работе квиза, которые мы естественно решили исправить.


0985_fix_the_quiz_ru/image1.png


Для тех, кто пока не знает о каком квизе идёт речь, расскажем кратко: мы отобрали несколько ошибок, найденных нашим анализатором в Open Source проектах. Участнику предоставляются 10 случайных фрагментов кода, в которых нужно найти и отметить ошибку. На каждый фрагмент выделено 60 секунд.


Вы можете почитать о квизе подробнее в заметке или пройти его.


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


Мы обработали комментарии с нескольких площадок, где разместили информацию о квизе, включая Habr, соцсети, тематические форумы и сайты. По итогу выделили 2 момента, требующие исправления. С первым столкнулись многие, прошедшие квиз – мы собрали немало комментариев по поводу способа выделения и подсчёта ошибок. Вторая же ошибка не была так распространена, о ней был лишь один комментарий. Ирония в том, что мы сознательно её допустили. Но обо всё по порядку.


Ошибка 1. А как попасть в правильный ответ?


Изначально механика квиза предоставляла возможность множественного выбора ответа (т. е. нескольких элементов). В примере ниже ошибкой является clip->GetSequence.


0985_fix_the_quiz_ru/image2.png


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


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


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


Было



Стало



Недавно мы подводили итоги двухмесячной работы квиза и рассказали о том, как почти 2 000 разработчиков в сумме заработали 3,5 балла из 10. Не исключаем, что способ подсчёта отчасти мог повлиять на итоговый результат.


Ошибка 2. Наш мини-фейл


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


  • при загрузке задания таймер обнулялся и запускался заново;
  • далее таймер запускался от 60 до 0 и каждый тик проходил проверку: если таймер === 0, то ставим флаг "время закончилось", но т. к. в начале таймер обнулялся, то проверка на ноль проходила сразу.

Если объяснить просто, то:


открывается задание -> таймер обнуляется -> сразу проходит проверка на === 0 и выдаётся "время истекло".


А должно было работать так:


открывается задание -> таймер обнуляется -> таймер запускает отсчёт -> через 60 секунд проходит проверка на === 0 и выдаётся "время истекло".


Чтобы не тратить время мы решили поставить таймер от 60 до 1. После этого таймер спокойно обнулялся, а флаг "время закончилось" ставился при проверке "если таймер === 1".


Решение не изящное, но быстрое. Мы были уверены, что никто не станет косплеить героев боевиков 90-х и нажимать "Отвечаю" на последней секунде. Но, если разработчику кажется, что всё будет работать именно так, как он задумал, – найдётся тот, кто "споткнётся о костыль")


2 месяца мы со спокойной душой не думали об этой ошибке. Пока в одном из комментариев нам не прилетел скриншот:


0985_fix_the_quiz_ru/image3.png


Получается, что, пообещав 60 секунд на ответ, мы на самом деле давали участникам 59 секунд. Что ж, ошибку признали, поправили и теперь каждый участник может со спокойной душой нажимать кнопку ответа на последней секунде. Но лучше, конечно, не затягивать, если ответ вы нашли быстрее.


Этот опыт в очередной раз доказал, как важна обратная связь и работа с ней.

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


И не забывайте, что каждому прошедшему квиз доступен промокод на 30-дневную лицензию PVS-Studio.


Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Alexey Sarkisov. The feedback for our C++ quiz and why it matters.

Комментарии (8)


  1. xi-tauw
    31.08.2022 16:29

    Спойлер из теста по шарпам

    pageNumber > 0 всегда истинно, соответственно, я хотел указать на dead code.


    1. al_sarkisov Автор
      31.08.2022 17:15

      Действительно, в некотором роде это логично). Но мы исходили из того, что нужно указывать именно на допущенную ошибку. Мёртвый код в данном случае является скорее следствием ошибки, а ошибка предполагается в условии.


  1. datacompboy
    31.08.2022 17:32

    в тесте про LANG_USER_DEFAULT наверное надо принимать оба упоминания за ошибку? :)


    1. al_sarkisov Автор
      01.09.2022 14:01

      Мы рассматривали данный вариант, но всё же пришли к выводу, что ошибка состоит именно в использовании поля. Его объявление, очевидно, ошибкой не является.


      1. datacompboy
        01.09.2022 15:06
        +2

        Я подумал что ошибка -- определение её ниже использования. Ну ничего, я сам уверен что я прав =))


  1. a-tk
    01.09.2022 10:27

    Ещё один спойлер из теста по шарпам с вопросом о разметке ответов.
    Здесь ошибка проявится именно при итерировании.
    Здесь ошибка проявится именно при итерировании.


    1. al_sarkisov Автор
      01.09.2022 11:44

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


      В то же время понятна ваша позиция :). Увы, тяжеловато сделать квиз так, чтобы понимание "ошибок" совпало вообще у всех людей. К примеру, кто-то вообще может посчитать, что беда именно в объявлении namedLifecycleParticipantCollection. В любом случае, главное, что вы сами знаете, что ответили правильно)


      1. a-tk
        01.09.2022 12:35

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