Привет! Меня зовут Ксюша, я работаю бэкенд-разработчиком на C# в Контуре. В весеннем семестре я провела курс по функциональному программированию на Haskell для студентов 3 и 4 курса направления ФИИТ (фундаментальная информатика и информационные технологии) в УрФУ и хочу поделиться своим опытом организации и проведения курса.
С чего всё началось
Как же так вышло, что я пошла рассказывать студентам про монады и трансформеры (не те, которые Attention is all you need!)?

Я сама училась на ФИИТе, и курс по функциональному программированию (ФП) у нас был обязательным, но в наш год не нашли преподавателей, поэтому мы изучали его самостоятельно.
Мне ФП выворачивало мозг! Особенно меня удивил подход с лямбда-калькулятором. Попробуйте проверить число на то, что оно 0, имея только лямбды в распоряжении. А это мы еще про рекурсию не говорили.
isZero = \n.(n (\x.false) true)
И почему вообще булевы значения — это тоже какие-то функции? В общем, мне было это очень интересно, но много материала я не поняла в момент прохождения или плохо научилась применять. Мне помнится, что я поплыла на теме трансформеров и продвинутых монад. Очень хотелось разобраться в концепциях функционального программирования поподробнее, а какой лучший способ разобраться в чем-либо? Объяснить это другому человеку! Вот я и решила преподавать.
Что представляет из себя курс
«Введение в функциональное программирование» — это курс в формате перевернутого класса: дома студенты смотрят лекции и решают задачи на платформе ulearn, а потом подключаются на семинар с преподавателем, на котором более подробно разбирается пройденная тема.
Курс знакомит слушателей с концепциями, лежащими под ФП, и тем, как это реализовано в Haskell. Вот полный список тем:
Знакомство с Haskell
Списки
Лямбда-исчисление
Алгебраические типы данных
Типы и полиморфизм в лямбда-исчислении
Ленивые вычисления
Эффекты и монады
Практикум
Классы типов
Структуры данных
Остальные монады
Трансформеры
Тестирование в Haskell
Type-level programming
Пример веб-приложения
Например, вот какую задачу я давала студентам по теме «Трансформеры»: нужно написать функцию, которая проверит, скомпрометирован ли пароль. Звучит просто, не так ведь?
Однако задача подразумевает чтение базы скомпрометированных паролей (база для простоты является текстовым файлом), а также запись в лог о результате проверки. Все еще звучит просто? Загвоздка в том, что функциональное программирование оперирует чистыми функциями — функциями без сайд-эффектов. А как же тогда нам вообще работать с вводом и выводом? Чтобы дойти до того, чтобы в одной функции осуществить чтение и запись, понадобился почти весь семестр и много изученных концепций из мира функциональщины :)
Так что курс нужен не для обучения промышленной разработке, а для расширения кругозора и общего развития. Чтобы не заучить, как сделать функцию с чтением и записью, а понять, почему она выглядит так, как выглядит, а упростить нельзя.
Математику уже затем учить надо, что она ум в порядок приводит.
(с) Ломоносов М.В.
Здесь что-то похожее — понимание концепций поможет писать код более креативно, выходя за рамки обычного мышления. Если говорить более прагматично, то во время курса можно словить ценное ощущение того, что ты наконец-то понял, откуда и как появились вещи, которыми ты пользовался на постоянке — LINQ, дженерики, а также куууча монад с разным синтаксисом под свой случай (привет, таски!).
Грабли
Для меня это был первый опыт организации курса и полноценного преподавания. Основы ФП убрали из обязательной программы, но так как лекции были предзаписаны, а материалы для подготовки к семинарам выложены на той же платформе, то мне было с чего начинать.
Тем не менее я понимала, что курс проводится в пилотном режиме. Идея преподавать родилась у меня в конце календарного года, а в феврале уже начиналась учеба. Мы понимали, что это семестр, на котором мы наступим на разные грабли. О них в основном и пойдет речь дальше)
Спрос оказался больше
Сначала нужно было привлечь студентов на курс. Я написала анонс, добавила мемов про ФП, но была уверена, что придет на курс максимум человек 15-20, поэтому не ограничила набор на курс. Ну и чем же это обернулось? На курсе 60 человек и один преподаватель!

Ну… не все так плохо. Я знала, что на семинары будет ходить гораздо меньше людей, поэтому за проведение пар не особо волновалась, но вот с домашками была беда. Проверять даже 15 работ в неделю — достаточно тяжело, а это плюсом к тому, что надо самой вспомнить и/или изучить материал (мы же помним, что я пошла преподавать, чтобы разобраться в теме) и подготовиться к паре.
Мне повезло, потому что мои бывшие однокурсники согласились помогать проверять домашки. Спасибо им! Без них я бы не вывезла уже на второй неделе. В итоге мы разделили студентов примерно поровну и должны были проверять примерно по 15 работ каждый. Но здесь все прошло не так хорошо, как хотелось бы — в середине семестра ребят догнали разные важные вещи. У кого-то это был запланированный отпуск, у кого-то — организация контеста для отбора на стажировку.
Еще добавлю, что в середине семестра была тема с объемной домашней работой. Вникать в такие работы было тяжело. Ревью на отвали делать совсем не хочется. Как результат, с середины семестра домашки у многих студентов проверялись очень медленно.
Это был основной минус курса, который отметили студенты. Вывод, который мы сделали: в следующий раз ограничиваем количество проверяемых работ в неделю 10 штуками на человека, следовательно, набор ограничиваем 10 \* количество преподавателей. Скорее всего, нас снова будет четверо, поэтому набор будет 40 человек.
Спешное начало курса
Т. к. курс стартанул достаточно быстро, то тестового прогона у нас не было. Да и зачем, казалось мне, ведь ровно на этой же платформе, студенты 3-4 года назад сдавали задачи. И все было нормально!
Конечно же, и тут меня ждал сюрприз, а именно — неработающая тестирующая система!

В первый раз, когда в чат студент прислал скриншот с серым сообщением от сервера, оказалось, что у ulearn прилегли гитлаб-раннеры, которые и проверяют решения студентов.

Ну тут все просто — ждем, когда разработчики ulearn все пофиксят на своей стороне и спокойно ждем, благо дедлайны можно и немного сдвинуть.
Когда мне написали то же самое в другой день, я уже была на опыте и знала, что буду делать — переложу ответственность на разработчиков ulearn! Но не тут-то было…
Неполадки в первый раз были при сдаче задачи на хаскеле, а вот во второй раз — при сдаче задачи по лямбда-исчислению, для которого мы используем mikrokosmos. Как работает тестирующая система: у задачи есть Dockerfile, из которого собирается образ для тестирования. В нашем случае нужно было установить haskell и mikrokosmos, потому что он написан на haskell. Далее в рабочую директорию копируется решение студента и прогоняются тесты. Вот только образ с микрокосмосом перестал собираться… Оказалось, что используемый образ хаскеля для сборки микрокосмоса устарел и теперь не устанавливается. Ну легко, просто поднимаем версию хаскеля, да и все. Так я и сделала и получила ошибки при компиляции микрокосмоса. В хаскеле сломана обратная совместимость (тред на stackoverflow с такой же проблемой), а значит нужно поднять и версию микрокосмоса. Заходим на страницу этого космического калькулятора, а там последняя версия 0.8.0. А она-то под старую версию и заточена!

В этот момент я уже совсем было расстроилась: несмотря на то, что локально решения все еще можно было проверить, т.к. был собранный образ на Dockerhub, нужно было бы придумывать, как проверить решения студентов -- перед ревью еще запускать локальный прогон, или временно забить на задачу, или подредактировать регламент курса?
Но внимательный пользователь, а таким оказался Женя, который тоже проверял домашки, зайдет еще дополнительно на гитхаб и увидит, что последняя версия все-таки 0.8.1 и есть Issue для поднятия версии ?

Вот так вот, поигравшись с версиями, у меня получилось пересобрать образ, и студенты смогли сдать задачи на платформе.
Finita la commedia, друзья
Почему так произошло?
Во-первых, я не проверила работоспособность курса, точнее даже не подумала об этом. Впредь буду умнее и предусмотрительнее. Во-вторых, команда ulearn за полгода до запуска курса переустанавливала образы и уже тогда увидела, что образ больше не собирается, но они не нашли, кому об этой проблеме рассказать.
Домашки делают нейросети
Еще одна проблема, с которой мы столкнулись — использование GPT. Чрезмерное использование GPT. Ооооочень много работ списаны, причем есть и те, которые списаны достаточно неумело — такие работы сразу видно. На ulearn есть система антиплагиата, но все-таки списать можно так, что антиплагиат не сработает.
Я понимаю, что использование нейросеток неизбежно, поэтому одной из задач, которые нужно будет решить до следующей весны — как адаптировать задачи под их использование? У нас есть несколько идей, как это сделать, но пока они не проработаны.
Если у вас есть опыт адаптации курса под GPT или идеи того, как это сделать, то буду рада, если вы поделитесь ими в комментариях!
Что получилось хорошо
Что-то я про то, что не получилось… А что же получилось?
Первые несколько пар мы со студентами работали в общем зале, пытались обсуждать материал и решать небольшие задачки. Но в онлайне люди разговаривали не особо активно, а мне хотелось, чтобы больше людей были вовлечены в процесс.
Поэтому я внедрила механику с работой в сессионных залах — даю студентам задачки на подумать, но не рокет-сайенс. Они работают над ними в группах по 3-4 человека, а потом мы все собираемся в общем зале, чтобы обсудить решения.
Может быть, у кого-то получилось изящно реализовать функцию с помощью каких-то библиотечных. Может, у кого-то получилось написать все в одну строчку — всегда интересно посмотреть на то, как одну задачу можно решить разными способами. После этой механики кстати стало подключаться на курсы сильно меньше людей, чем до этого. Зато у нас получилось узнать, кто из студентов пришел на курс, чтобы хорошо разобраться в теме, так что механика получилась успешной.
Меня очень радовали студенты, которые активничали и общались со мной на парах, у которых получалось докопаться до того, как сделать так, чтобы сошлись типы в функции с трансформерами.
Мнение самих студентов
Получилось собрать не очень много обратной связи от студентов, но тем не менее курс им, по большей части, понравился. Особенно зашла механика с работой в группах в целом нестандартность курса на фоне «обычного» программирования. Ещё студенты отметили, что курс заставил их поломать голову и подумать в другой плоскости. Я рада, что кому-то понравилось и у меня получилось кого-то заинтересовать!
Спасибо всем, кто дочитал до конца. Если у вас есть опыт в ФП, а особенно в Haskell, и вам интересно поделиться своим опытом, то буду рада контактам!
Всем монад)
Воспользуемся моментом и обратимся к тем, у кого есть дети-выпускники, или друзья, которые прямо сейчас выбирают вуз. До 25 июля можно подавать заявления на бюджет. ФИИТ на матмехе УрФУ — отличное ИТ-направление, а Екатеринбург — крутой город для студенческой жизни. Все подробности и нужные ссылки в ВК https://vk.com/fiiturfu. Смело пересылайте знакомым абитуриентам!
tkutru
Нормальная тема!
Ксюша, было прикольно если бы ты обрисовала основные идеи курса/ФП в отдельном посте. Тем более что по твоей основной работе бекенд на си шарпе это по идее должен быть сплошной ООП. Как ты докатилась до такого? :) успехов