Два года назад я начал читать курс “Язык программирования Ди” в самом настоящем университете, провёл в общей сложности 40 лекций, примерно столько же практических занятий даже дважды принял экзамен, один раз удалённо. Как так случилось, кому вообще может быть нужен D, и как ученик превосходит учителя, под катом.
Всё началось чуть два с половиной года назад. Тогда в почтовой рассылке D появился необычный вопрос: А не хочет ли кто-нибудь поучить студентов в Москве? Но прежде, чем можно будет продолжить нужно раскрыть несколько моментов.
Что такое D?
Ответ требует лекции на полтора часа. Но если коротко, то это C++ сделанный правильно. Статьи про него есть на хабре, но уходить в подробности не вижу смысла. Он гораздо удобнее и приятнее для программиста, предлагает более высокую продуктивность при той же производительности. Убийца C++, если хотите, только при этом не rust.
Зачем он студентам?
Вакансий на D мало. И я говорю на первой лекции, что скорее всего в реальной работе практические навыки не пригодятся. Но это не делает его изучение бесполезным. Во-первых, на нём проще учиться программировать, чем на C или C++. Это важно, потому что даже после курса программирования на C и ООП на C++ многие вообще не умеют программировать. Во-вторых, разнообразие это хорошо, чем шире кругозор, тем лучше код. Ну и самое важное, D - будущее C++ и не только. На нём обкатывались многие новшества C++, почти все возможности C++11/17/20 уже были в D. И он всё ещё куда прогрессивнее и богаче плюсов. Мне знакомство с D позволило улучшить код на C++, а также значительно ускорило изучение Python, а точнее его итераторов.
Кто я и зачем он мне?
Проще всего сказать, что я C++ программист, по крайней мере по основной профессиональной деятельности. Я никогда ничего не преподавал и, честно говоря, даже на основной работе не очень-то участвую в менторстве над джунами. С момента окончания магистратуры нижегородского ВМК 6 лет назад к академической среде вообще не имею никакого отношения. Первое время в университете меня посещали мысли о том, чтобы учить школьников, но как я сейчас понимаю, это просто было некоторое стремление к ”справедливости”. Ведь в школе всё неправильно, а в универе всё круто и надо применить универские подходы в школе, и тогда всё получится. Наивно, конечно, но весь первый семестр меня не покидала мысль “Если бы мне объяснили это так раньше”. Я ощутил, что за месяц в университете получаю знаний больше, чем в школе за год, и это круто. Желание пойти работать в школу у меня пропало после получения первой зарплаты программиста, но некоторая память о стремлении осталась.
Программированием на D я тоже заинтересовался в универе. После C++ он казался просто идеальным. Можно писать такой же быстрый код, но без всех этих атавизмов. В итоге софт для диплома я написал на D и мне понравилось. По скорости выполнения получилось лучше, чем у предыдущей C++ версии, а по простоте и объёму кода вдвое лучше. Скорость удалось выжать благодаря тому, что чуть более сложные и эффективные алгоритмы банально проще реализовывать, а на C++ лениво, да и сроки у студентов всегда горят.
Так что с тех пор я интересовался D и старался писать на нём свои домашние поделки. Хотелось как-то помочь сообществу этого языка, но писать нужные библиотеки у меня не получалось, да и как-то в целом на open source не хватает мотивации.
3 месяца до начала
Автором исходного предложения был Дмитрий Ольшанский, довольно известный в D’ишном сообществе человек, автор библиотеки регулярных выражений D и не только. Я написал ему, что мне интересно было бы попробовать, и стал ждать. Самостоятельным преподавателем я себя не видел и рассчитывал, что буду помогать ну или вести практические занятия по готовому плану. И в начале всё так и выглядело: лектором вызвался другой довольно известный в сообществе человек - Rikki Cattermole. Он собирался удалённо читать лекции по скайпу, а от меня требовалось помогать на месте. Примерно в этот же момент выяснилось, что ВУЗ, где всё будет происходить - РГГУ, Российский Государственный Гуманитарный Университет. Да, там есть технические факультеты и да, они действительно программируют. В этом я убедился, просмотрев учебную программу. D добавляли в программу третьего курса, а на первых двух у них был C, C++, Prolog, кажется даже Lisp (многовато, но почему и нет). По математике программа тоже выглядела серьёзно (да, я из тех, кто считает математику важной для программистов). Так что с самого начала я взял за ориентир свои собственные воспоминания об учёбе и уровне навыков на третьем курсе.
Меня познакомили с преподавателями кафедры, рассказали, чем они занимаются, предложили даже поучаствовать в научной работе в роли программиста.
Неспешно мы начали готовить программу, хотя в этом “мы” я почти отсутствовал. А зря.
1 месяц до начала
Выясняется что из-за какого-то, чуть ли не личного, конфликта с Дмитрием Рикки отказывается продолжать и покидает нас. Для меня это было неожиданно, но ещё же вагон времени? Тогда же с радаров начинает пропадать Дмитрий.
Оказывается, что не все начинают учиться в один день. Более того, не все курсы идут весь семестр и мой идёт с октября. Самое время формально устраиваться, решать бюрократические вопросы и приступать. На работу оформляли меня, но я рассчитывал, что фактически буду не один. Почему я на это рассчитывал, сказать трудно. По всем объективным показателям было понятно, что помощи не будет и весь курс придётся делать в одиночку. Но инертность ожиданий долго не рассеивалась. Окончательное осознание всего происходящего пришло за неделю до начала курса. Вот тогда я и начал по-настоящему готовиться.
Бюрократия
Тут должны были описываться страшные истории, как бедный программист преодолевал ужасные бюрократические преграды. Сходив первый раз подписать договор, я даже начал всем рассказывать, как же там много бумажек. Когда понадобилось оформить карту МИР для зарплаты, "ржали всем офисом". Но на самом деле, на этом всё. Следующей бюрократической задачей было составление рабочей программы (это такой официальный документ, содержащий учебную программу и материалы). Там действительно куча формальностей, но мне помогли, показав программу очень похожего курса. Ну, а наполнение программы это уже вполне реальная и важная вещь. Так что с точки зрения бумажек и формальностей всё было гораздо лучше, чем я ожидал. Спасибо за это преподавателям и работникам кафедры. Договор был сроком на год, в этом году я смог его перезаключить, появившись один раз, оставив на столе одну бумажку, и намалевав автограф ещё на двух. Первый раз было сложнее, но сейчас всё очень просто и быстро.
Первое занятие
Расписание сложилось так, что первым занятием был семинар (он же лаба, она же практика), а не лекция. Это только формально так, потому что на весь поток одна группа, всего 14 человек, и нет фактической разницы, когда что делать. Позже расписание немного поправили и у меня было 2 пары подряд и я сам решал, что есть лекция, а что практика. Сразу сложился график: на первой паре я рассказываю что-то и отвечаю на общие вопросы (лекция), на второй студенты программируют и задают практические вопросы.
К первой паре я подготовил довольно короткий обзор языка, сконцентрировался на базовом описании “на что это похоже”, показал синтаксис, дал компилятор и несколько очень простых задач. Было решение квадратного уравнение, подсчёт площади треугольника и подобные задачи, которые по простому вводу предлагали простой вывод. Идея была в том, чтобы быстро погрузить студентов в тему и сразу дать что-то сделать. План удался и к концу первого занятия многие совладали с консольным компилятором, написали в блокноте код, решив по несколько задач.
Консоль и блокнот
Думаю, найдётся немало людей, которые на предыдущем предложении возмутились по поводу консоли и блокнота. Что, даже IDE нет? Есть, но в первом семестре я оставил это на откуп желающим. Причиной этому был собственный опыт изучения программирования в целом и C++ в частности. Понимание того, как вообще работает компилятор, и как потом из нескольких файлов линковать проект, критически необходимо для понимания языка в целом. Такие понятия как объявление (declaration) и определение (definition) в C просто не имеют смысла без понимания процесса сборки. Да, в D подобных тонкостей меньше, нет заголовочных файлов, но всё же хотелось учить программированию на D, а не в конкретной IDE. Да и без хедеров раздельная компиляция никуда не делась и с консольным компилятором понять принцип работы import проще, чем через “интуитивно понятный интерфейс”. Плюс, базовый синтаксис запоминается лучше, если автоподстановка не пишет код вместо тебя.
Развитие курса
Окрылённый первым успехом я пролетел с первой же лекцией. Предполагалось начать полноценное объяснение, с теорией, какой бывает типизация, со сравнением с другими языками, списком проблем C и C++, демонстрацией контраста D на их фоне, но не получилось ничего. Во-первых, это слишком много для одной лекции. Во-вторых, материалы были подготовлены в том числе из моих предыдущих презентаций о D, которые я делал на работе, и фактически были рассчитаны на опытных программистов. Итого, лекция прочитана меньше чем за час, ни одного вопроса по ходу, ни одного после. Под конец я даже начал спрашивать слышно ли и понятно ли меня, мало ли проблемы дикции, но вроде нет. Стало понятно, что всё подготовленное на следующие лекции можно выкидывать и писать снова.
Новая программа
Первым кандидатом на упрощение, а то есть исключение, было метапрограммирование. Убрать шаблоны нереально, на них работают самые базовые концепции и алгоритмы, но вот всевозможную генерацию кода на этапе компиляции убрал сразу. Туда же отправилось всё, что требовало сторонних библиотек. Осталось только то, без чего D невозможно представить, и без чего не получится на нём писать.
Так как взаимодействие на практике и живое общение во время программирования на самом занятии получилось лучше, то я решил уделить этому больше времени. Переделывать программу прямо во время семестра получалось с переменным успехом, но основной канвой стало следующее: за семестр требовалось написать довольно сложную вычислительную программу, на лекциях разбирали необходимые языковые средства для конкретной задачи, а на практике всё это приобретало форму кода.
Задача
Возможно, многие видели видео о проблеме числа 10958. Суть в том, что нужно расставить знаки и скобки между цифрами 1 2 3 4 5 6 7 8 9, чтобы полученное выражение было равно 10958. Все остальные числа до 11000 раскладываются, а под это никто ничего не нашёл. Строгого доказательства отсутствия разложения тоже нет, поэтому это называют проблемой. Я предложил студентам написать программу, которая прямым перебором будет искать разложение. То есть переберёт все возможные расстановки знаков и скобок. Вычисления в простых double, без длинной арифметики, поэтому это совсем не доказательство, зато проще. Мне задача казалась хорошей по разным причинам. Во-первых, я написал решение, аналог которого хотел видеть от студентов, примерно за 5 часов или 2 вечера. С поправкой на студенческий уровень объём работ выглядит подходящим для семестрового проекта. Во-вторых, задача не решается совсем в лоб. Прямой перебор требует слишком много времени, значит нужно правильно отсечь одинаковые выражения ещё на этапе построения перебора. То есть нужно сначала подумать, оценить свои действия, и только потом программировать. Ну и в-третьих, мне задача казалась увлекательной и даже захватывающей. И вот в этом я не мог ошибиться сильнее. Большинству подобная математика оказалась не то что неинтересна, они вообще не поняли в чём тут проблема и зачем нужно это 10958. Заинтересовать не получилось.
Менять программу к моменту осознания проблемы было слишком поздно, поэтому первый семестр вышел не очень увлекательным. Всего несколько студентов выполнили задачу в полном объёме, для остальных же она оказалась неподъёмной.
Второй семестр
Курс рассчитан на год, поэтому у меня была возможность исправиться. Для второго семестра я старался подобрать максимально интерактивную и практическую задачу. Поэтому предложил студентам написать игру. По плану шли сети и интернет, поэтому игра была нужна многопользовательская. Вспомнилось, как студентами мы играли в “крестики-нолики на всё поле” на скучных лекциях. По умному эта игра называется гомоку. Два игрока могут играть по сети, а реализация логики самой игры не так сложна. Я надеялся заинтересовать студентов игрой, что они попробуют поиграть друг с другом на бумаге, вовлекаясь в предметную область.
Не знаю, играли ли они на самом деле, но всё же эта задача пошла гораздо лучше предыдущей. Однако, успехом результат назвать всё равно сложно.
Я очень хотел показать удобное асинхронное программирование на корутинах (в D они называются Fiber), как всё удобно в фреймвёрке vibe.d, и как легко подключаются сторонние библиотеки через менеджер dub. Ошибка номер один - не надо продавать корутины тем, кто ещё не понял проблемы callback hell. Ошибка номер два - не проверять оборудование и требования фреймвёрков.
Сложности откуда не ждали
Никогда бы до этого не подумал, что однопоточная компиляция может упереться в объём оперативной памяти. А она может, потому что на компьютерах в университете было по 2 гигабайта RAM, а на некоторых нетбуках студентов встречалось и по одному. Простенькие программки собираются превосходно даже на таких слабых машинках, всё же D не C++, он значительно быстрее компилируется. Но вот большой фреймвёрк для своей сборки потребовал много памяти. И вот представьте, я только что рассказал на лекции, как всё легко и просто делается, а у большинства даже hello world с сетью не собирается. В свою защиту скажу, что я заранее проверял, что всё будет работать, установив себе нужную версию windows 7 в виртуалку с 2 гигабайтами памяти. На ней проверил работу дополнительных ключей компиляции для снижения потребления памяти. То есть теоретически я был готов. Но новая библиотека + новая система сборки + флаги компиляции это слишком много для одного раза,
И всё же результаты второго семестра были лучше - как минимум клиентскую часть игры поняли и сделали все. Кто-то заблудился в корутинах на сервере, но в целом эта часть была воспринята нормально. Однако, мне было мало. Я дал сверхзадачу - написать простой ИИ для игры. Это позволяет понять плюсы клиент-серверной архитектуры, понять, что ИИ это просто другой клиент, а код сервера трогать не надо. Кроме того, в клиенте можно не трогать взаимодействие с сетью, а поменять только код опроса хода. Это хорошая задача на архитекутуру, до неё добрались только те, кто уже неплохо программировал, поэтому проектирование как раз для них и актуально.
Итоги года
К сожалению я потребовал слишком много для одного семестра, поэтому хоть какой-то ИИ был всего у одной студентки. Зато, по её словам, она очень радовалась, когда он сделал первый осмысленный ход. Ещё одна студентка весь год говорила, что программирование это вообще не её и она не понимает. В конце года она сама написала и клиент и сервер. Значит всё было не зря.
Попытка номер два
Всё написанное выше происходило в учебном году 18/19. Звёзды сложились, и на следующий учебный год я продолжил. Новые студенты, новые возможности, новая программа. На этот раз я был готов гораздо лучше. Уже были материалы для большинства лекций, не пришлось всё перекраивать на ходу, да и за лето была возможность сделать работу над ошибками.
Я сразу убрал задачу 10958 за скучность. Вместо этого растянул игру гомоку почти на оба семестра. Почти, потому что первый семестр начинался с простой задачи на ООП, где требуется реализовать классы геометрических фигур с кастомизацией их вывода на экран. Это следующий шаг после “hello world”, чтобы все освоились с инструментарием, а я понял уровень студентов. Думаю, что ни для кого не секрет, что уровень очень разный. Кто-то уже работает программистом и ходит на курс только ради интереса, а кто-то испытывает проблемы с переменными и циклами. Ещё в первый год я для себя решил, что я делаю курс не для всех, а для тех, кому интересно и хорошо получается. Но всё же совсем забрасывать остальных тоже неправильно, поэтому нужны задачи подходящего уровня для всех.
Для упрощения старта работы с сетью я поднял свой сервер с эталонной реализацией, к которому можно было подключиться и играть хоть через telnet. Дополнительное время и объяснения сказались на продуктивности очень позитивно. Многие добрались до сверхзадачи, и в конце получилось устроить небольшой конкурс между ИИ. Их всё ещё легко обыгрывает человек, но это большой прогресс по сравнению с предыдущим годом.
Приятная неожиданность
Интересным прецедентом второго года был другой конкурс. В первом семестре я предлагал сыграть в кодгольф. Простая задача, которую нужно решить минимальной программой. Чтобы добавить мотивации, я сказал, что лучшие результаты в группе освобождаются от написания отчёта по семестровой работе. А если вдруг кто-то побьет моё решение, то зачёт автоматом. Самонадеянно, но я был уверен, что никто не побьет, ведь я это решение очень долго оттачивал. Через неделю слегка ошарашенный, с трудом подбирая слова, потому что меня побили. И нет, я не отказался от своих слов, я поставил этот зачёт, но как только получил ведомость. А всё потому, что я за год отстал от последних изменений в компиляторе, и некоторые запрещённые ранее вещи стали разрешены. Что интересно, я смог улучшить предложенное решение, сократив ещё на 4 символа. Я очень боялся, что автомат почти в середине семестра отобьёт желание ходить на пары, но к счастью оказался не прав.
Назад в настоящее
И вот в октябре 2020 я начал третий год в роли преподавателя. Второй год был лучше первого, но всё ещё далёк от идеала. Менять программу я не планирую, а вот в способе её подачи наметил несколько важных моментов.
Нужно рушить стену в личном общении. Чем более доверительные отношения, тем лучше идёт процесс. Сложнее всего с теми, кто боится преподавателя даже когда всё получается. Нужно искать контакт и комфортную социальную дистанцию. Ничего конкретного пока не придумал, всё решим в частном порядке.
Контроль нужен даже тем, кто хочет учиться. Раньше мне казалось, что контроль посещаемости это для того, чтобы запугать и заставить ходить тех, кто не хочет. Так получилось, что самые хорошие преподаватели в универе не отмечали отсутствующих. Поэтому я очень лояльно относился к ситуациям, когда отсутствует половина группы. Всё же должны быть рамки и немного подпинывать надо. Двоечники всё равно будут прогуливать, зато ленивые хорошисты чему-нибудь научатся.
Нужен промежуточный контроль успеваемости. То есть не просто того факта, что люди учатся, а того, насколько они понимают программу. Я сводил всё к выполнению одной работы и отчёту в конце семестра, из-за этого терял тех, кто что-то не уловил на середине. Это можно было понять гораздо быстрее. Кто-то спросит, какие-то вопросы всплывают в личном общении на практике, но кто-то молчит. Контрольные работы по программированию это какой-то бред, но небольшие письменные опросы устраивать планирую. И влиять на итоговую оценку они будут, но слабо. У студентов должна быть мотивация писать ответы хорошо, но основная задача промежуточного контроля - корректировка программы и подтягивание отстающих, а не окончательное их добивание долгами.
Коронавирус
Нельзя не упомянуть, как пандемия сказалась на образовании. Весной все занятия были перенесены в онлайн. Читать лекции удалённо очень удобно, я действительно считаю, что это хорошо работает. Можно договориться об удобном времени проведения и не нужно заботиться о поиске свободной аудитории. Особенно хорошо, что вопросы можно задавать голосом - это аналог поднятой руки в оффлайне, а можно написать в чат. Такие вопросы не сбивают, но при этом на них можно своевременно реагировать. А вот практику вести у меня не получилось. Когда студенты сидят в аудитории они хоть что-то делают, ведь проще вообще не приходить, если ничего делать не собираешься. Когда всё удалённо они всегда “не приходят”. То есть не получается это сессии программирования с оперативной помощью от преподавателя. Я пробовал решить это предложением писать вопросы в любое время, а не во время пар, надеясь, что смогу помочь тогда, когда они реально пишут код. Но нет, это сработало только для 2-3 человек. Остальным помочь не смог.
Сейчас пока можно учиться очно, пусть и с ограничениями. Пока на обязательную удалёнку отправили только преподавателей из группы риска (65+ и их не мало). Надеюсь, что ситуация останется под контролем и можно будет проводить занятия очно.
Спасибо, что дочитали!
Автор: Григорий