Проблемы стандартных подходов
Вопрос подготовки и проверки домашних и контрольных заданий встал перед нами сразу как только мы узнали, что будем вести Java. К тому моменту мы успели побывать в качестве студентов в разных университетах и попробовать на себе множество подходов к проверке ДЗ, например, "принеси на флешке" или "распечатай на листочке" (даже не буду утруждаться перечислением минусов этих двух). Наиболее удобным к тому времени для нас казался подход, который практиковался в АУ: студент присылает решение по электропочте и вступает с преподавателем в переписку. Однако и в этом подходе нам не все нравилось:
- Много рутины для преподавателя: решение надо перенести к себе на компьютер, запустить его, протестировать, отревьюить и написать все замечания в письме.
- Дополнительное ожидание для студента и нагрузка для преподавателя, т.к. полностью убедиться в корректности своего решения студент может лишь послав его преподавателю и дождавшись от него ответа.
Еще одним способом сдачи домашних работ в АУ было использование общего репозитория; в нем для каждого студента создавалась отдельная директория, где он выполнял домашние работы. Такой подход отчасти избавляет от рутины, но поскольку преподаватель все равно проверяет решение вручную и пишет замечания по почте, то студенту все так же приходится ждать ответа, чтобы понять, что в решении что-то не так.
Немного подумав, мы решили, что связка "VCS + общедоступный CI-сервер + инструмент для ревью кода" избавит нас от всех вышеперчисленных проблем, а использование сторонних сервисов избавит еще и от необходимости все это настраивать.
Организация работы
Репозиторий было решено организовать следующим образом: для каждого задания завести отдельную ветку, которая содержит README с описанием того, что надо сделать, а также проект Maven с костяком решения и тестами к нему. Студент в начале семестра делает форк репозитория и в дальнейшем просто переключается на нужную ветку, вносит изменения, коммитит и отправляет pull request. PR автоматически собирается и тестируется; если тесты не проходятся, то студенту требуется доделать работу; если же все хорошо, то преподаватель проверяет код и оставляет замечания или закрывает PR и ставит оценку.
В отличие от подхода с одним репозиторием и по директории на каждого студента, такая организация избавляет от возможных проблем при слиянии изменений, позволяет держать репозиторий в чистоте, а также защищает от вандализма, хотя, к счастью, с этим прецедентов в АУ пока не было.
Подбор сервисов
С VCS-сервисом все было просто и понятно: Github. Исторически так сложилось, что и у нас, и у большинства студентов были аккаунты именно там; это стало ключевым доводом "за". Кроме того, там же было решено делать ревью кода и оставлять замечания.
С сервисом CI все обстояло немного сложнее. Изначально мы решили использовать Travis CI и до некоторых пор он нас всем устраивал. Однако со временем наши требования изменились: кроме открытых тестов, доступных прямо из репозитория с заданием, нам захотелось сделать еще и несколько закрытых — для того, чтобы студенты самостоятельно подумали над различными тонкостями и граничными случаями. Мы создали закрытый репозиторий, изменили билд так, чтобы этот репозиторий добавлялся как submodule в основной, и добавили зашифрованных переменных с именем пользователя и паролем, чтобы Travis мог склонировать закрытый репозиторий. Все было хорошо ровно до того момента, пока один из студентов не попробовал сделать pull request. Оказалось, что зашифрованные переменные недоступны из билдов для PR и мы это не проверили. Беглый поиск по оставшимся CI-сервисам вывел нас на Semaphore CI. В отличие от Travis, он поддерживает загрузку секретных SSH ключей, которые можно использовать в билде для доступа к закрытым репозиториям, а это именно то, что нам было нужно.
Подводные камни и минусы
Первой проблемой, с которой мы столкнулись, оказался, как ни странно, сам Git. У ребят не всегда получалось отправить свои решения на Github. Причина этого была в том, что после обновления своего форка и перехода на новую ветку в качестве remote в ней был выставлен основной репозиторий, а не форк. Об этой тонкости стоит упоминать отдельно.
Второй проблемой стало отсутствие правил именования коммитов и PR. В итоге уже после первой домашки мы получили ворох PR с названиями вида "fix", "1st hw", "моя домашка" и т.п. Все это дополнительно осложнялось тем, что определить студента по имени пользователя было почти невозможно, потому что профиль был заполнен далеко не у всех. Для последующих заданий мы, конечно, ввели строгие правила, но в первый раз пришлось попотеть.
Основным минусом данного подхода является то, что не на все задания можно написать осмысленные тесты. Например, одно из заданий на дженерики подразумевало написание своей functional java. Количество кода в этом задании было минимально, а основная его прелесть заключалась в том, чтобы придумать правильные сигнатуры для функций. Для того чтобы его качественно протестировать, пришлось бы придумывать сложные иерархии и проверять разные хитрые случаи; на это бы ушло больше времени, чем на проверку работ вручную. Также к заданиям, на которые писать тесты сложно и затратно, можно отнести задания на многопоточность.
Довольно много людей также причисляют к минусам доступность чужих решений – кто захочет писать ДЗ сам, если у соседа уже все готово и даже сдано. Лично я не считаю это минусом, потому что тот, кто хочет списать, все равно найдет способ это сделать.
Выводы и планы на будущее
Опыт применения такого подхода можно считать положительным. Несмотря на некоторые проблемы и неровности в начале, к середине-концу семестра все утряслось и заработало как надо. Нам было удобно проверять решения, и надеюсь, что ребятам было удобно их сдавать. Во всяком случае, по результатам семестра, недовольство таким способом сдачи ДЗ в моей группе из десяти человек выразил только один.
Логичным развитием данного подхода станет добавление других полезных сервисов, например, автоматической проверки стиля или статического анализа кода. Также было бы очень удобно научить Github автоматически назначать ревьюера для PR. И вообще, нет предела совершенству.
Комментарии (10)
NickKolok
20.02.2016 17:41К сожалению, такой подход работает только для хорошо мотивированных студентов, к тому же знакомых с гитом.
Нечто подобное я пытался организовать в рамках производственной практики на матфаке Воронежского госуниверситета:
https://github.com/nickkolok/chas-ege/pulls
Что выяснилось:
- В группе оказалась девушка, которая официально изучает немецкий. Смотреть на то, как она все сообщения переводит через Google Translate, было жутковато, требовать знание английского — нереально.
- Подскажите, а есть ли какой-нибудь способ автоматически давать по рукам за концевые пробелы в пулл-реквестах и гибко проверять отступы?
- Можно поручать code review студентам, если задачи не совпадают. И им полезно, и мне нервы-время экономит (а в основном находят ошибки с отступами, типографикой и "белиберду"). Потом, конечно, всё смотрю сам.
dancingrobot84
20.02.2016 19:36+1(2) Насчет пробелов и отступов, для Java могу посоветовать checkstyle и его плагины для популярных сборщиков. Для Javascript (если я правильно понял из репозитория, вам интересен именно он) можно либо прогонять eslint перед тестами, либо воспользоваться готовым сервисом, например, https://houndci.com.
(3) Интересное предложение. Если поручить им еще и тесты писать, а оценки выставлять по степени покрытия, то не жизнь, а сказка будет :)NickKolok
21.02.2016 00:55(2.1) Да, про eslint знаю, спасибо, вот только там полно легаси-кода, который еслинтовать не надо. Но тема "рефакторинг" у нас тоже есть.
(2.2) Кстати, реально ли заставить Semaphore CI (спасибо за наводку, он реально прост в обращении) проверять каждый входящий пуллреквест? Или это только травис умеет?
(3) Веду у первого курса плюсы (меня поставили со второго семестра), сочиняю для них лабы. Даже программу слегка поменял, ускоренно пройдя функции, чтоб заставить их писать проостенькие юнит-тесты. Написал код, который в строке инвертирует регистр согласных — вынеси в функцию и покрой тестами!
mva
21.02.2016 20:37git config core.whitespace (см. справку) — скорее всего то, что вы хотите по поводу пробелов на концах строк :)
iDoka
Так и не увидел какой инструментарий был выбран для code review?
Zlobober
На гитхабе есть встроенный инструмент код-ревью для пулл-реквестов.
iDoka
Наверное, мы разные вещи называем термином code review
Zlobober
Наверное, называем. В моем представлении, которое не противоречит приведенному вами определению в Википедии, на гитхабе есть инструмент для код-ревью: клик (секция collaborative code review). А вы о чем?
iDoka
Судя по описанию секции collaborative code review, это больше тул ревьюирования диффов. Непонятно доступна ли фича отправлять на ревью коммиты?
ozkriff
Чем создание PR не «отправлять на ревью коммиты»?