Преподаем программирование в вузе
Блоги17.04.2023

Преподаем программирование в вузе

Как мы внедряли новый подход к обучению в МГТУ им Н. Э. Баумана

Современным вузам необходимо быть гибкими и адаптировать образовательный процесс к трендам, которые задает стремительно меняющийся рынок труда. Особенно, если речь идет об ИТ, где рынок быстро изменяется с точки зрения технологий и подходов к разработке, а образование за ним не всегда успевает перестраиваться. Иван Крыгин, Вячеслав Вершинин и Андрей Бородин рассказали нам, как им удалось интегрировать лучшие практики разработки в учебный процесс и помочь студентам приобрести полезные навыки, востребованные работодателями сегодня.

Введение

Всем привет!

Мы с коллегами преподаем дисциплину «Алгоритмические языки программирования» на кафедре «Информационная безопасность» в МГТУ им. Н. Э. Баумана. В рамках курса студенты получают базовые знания и навыки программирования на C/C++, пишут несложные программы без графического интерфейса, а также учатся более осознанно подходить к изучению других языков, таких как Java, C# или Python.

Курс рассчитан на студентов 1-2 курсов, которые впервые сталкиваются с программированием. Первый семестр посвящен языку C, а остальные — базовому и углубленному изучению C++. В течение всего курса студенты получают теоретические знания на лекциях, затем разбирают теорию на семинарах, а также закрепляют полученные знания на практике во время лабораторных работ. О них-то мы и хотели бы рассказать подробнее.

Что не так с лабораторными?

Задача лабораторных работ — помочь студентам закрепить теоретические знания, полученные на лекциях и семинарах.

Самый простой способ организовать лабораторные работы выглядит так:

1. В начале занятия преподаватель дает задание. Как правило, студентам нужно написать какой-либо алгоритм для автоматизации, например, программу для нахождения n!.

2. Во время занятия студенты выполняют задание и задают преподавателю вопросы.

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

У такого подхода есть несколько недостатков:

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

Также важно проверить соблюдение нефункциональных требований, например, соответствие CodeStyle или отсутствие утечек памяти. Эти требования тоже трудно сформулировать для студентов и проблематично оценивать. Кроме того, снижая оценку из-за того, что нефункциональные требования не соблюдены, преподаватель рискует показаться предвзятым. Студенты могут посчитать, что он излишне придирчив, так как с точки зрения функциональности написанный код работает.

В одной учебной группе, как правило, может обучаться 15 и более человек, а значит качественно проверить работы и дать обратную связь каждому студенту зачастую невозможно. Студенты заканчивают выполнять задания примерно в одно и то же время — к концу занятия — и на проверку преподавателю работы попадают одновременно. Если студент пропустил занятие по какой-то причине, возникает эффект «снежного кома». На следующем занятии ему придется либо закрывать долги, либо выполнять новую лабораторную, оставляя долг на потом. Оба варианта имеют очевидные недостатки.

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

Наш подход

Приближаем обучение к рабочим процессам

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

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

Итак, раз уж мы решили приближать опыт студентов к опыту разработчиков, первым делом нужно было ответить на вопрос: «В чем именно заключается работа младшего разработчика?». Обратившись к собственному опыту, мы определили типичные задачи начинающего программиста следующим образом:

1. Получает задание;

2. Пишет код;

3. Отправляет код в репозиторий;

4. Исправляет код, чтобы пройти тесты (unit-test, линтеры, и т. д.);

5. Дописывает тесты или исправляет существующие;

6. Получает ревью от техлида;

7. Исправляет замечания;

8. Получает аппрув от техлида;

9. Вливает PR;

10. Переходит к следующей задаче.

При таком формате работы преподаватель выступает в роли техлида, а студенты учатся не только программировать, но и работать с VCS ((Version Control System), писать unit-тесты, читать логи от существующих юнит тестов, искать ошибки в тестах (некоторые из них были допущены по неосторожности, а некоторые сделаны намеренно), приучаются к строгим замечаниям в PR.

Внедряем автоматизацию

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

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

Для автоматизации проверки функциональных требований мы используем автоматические тесты, которые выдаем вместе с заданием, либо просим студентов реализовать такие тесты самостоятельно. Здесь главным инструментом является GTest — фреймворк для написания unit-тестов при разработке на C++.

Чтобы автоматизировать проверки на соответствие нефункциональным требованиям, мы использовали cpplint (проверяет на соответствие code style), AddressSanitizer (проверяет утечки памяти), ThreadSanitizer (проверяет «гонки» в многопоточной среде). Все эти инструменты вместе с заданием студенты получают в заготовленном проекте с настроенной инфраструктурой на базе CMake в виде репозитория на GitHub. В таком проекте при каждом Pull Request в основную ветку происходит следующее:

  • Развертывание проекта;
  • Запуск проверок.

Мы отправляем студентам задания через GitHub Classroom — инструмент в составе GitНub, который позволяет тиражировать репозитории. Преподаватель заранее готовит шаблон задания, на базе которого сервис создает отдельную копию проекта для каждого студента.

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

Результат

Вот как сейчас выглядит процесс проведения лабораторных работ в рамках нашего подхода:

1. При подготовке к лабораторной работе преподаватель с помощью сервиса GitHub Classroom создаёт задание, которое включает в себя шаблон проекта с описанными выше автоматическими проверками но без кода, который нужно проверять. Написать этот код — задача студента.

2. Для каждого студента под каждую лабораторную работу создаётся отдельный репозиторий на GitHub на базе соответствующего шаблона.

3. Студент работает с созданным репозиторием, реализует предполагаемую заданием логику.

4. После внесения изменений в репозиторий, автоматически запускаются проверки в изолированной среде, и студент может видеть результаты этих проверок. Если написанный код не проходит проверки, студент вносит исправления (см п.3).

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

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

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

Заключение

В результате нам удалось адаптировать курс так, чтобы не только обучать студентов программированию на С++, но и познакомить их с технологиями разработки ПО, такими как VCS, Code Review, Pull Request, CI. Знание этих инструментов дает весомое преимущество при трудоустройстве.

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

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

Благодарности

Хочется выразить благодарность кафедре «Информационная безопасность» (ИУ8), Быкову Александру Юрьевичу за оказанную поддержку, а также студентам Кулагину Руслану, Александрову Алексею, Климанову Антону и Степанову Дмитрию за полезную обратную связь и своевременную актуализацию системы.

Читайте также
Комментариев пока нет
Больше статей