You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2020-02-11_teaching-programming-2019.md 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. Title: Обучение программированию 2019, или в поисках идеальной программы: Последовательность
  2. Date: 2020-02-12 00:00
  3. Category: News
  4. Slug: teaching-to-program-2019
  5. Lang: ru
  6. ![МУРОМ][screenshot]
  7. В этой статье Михаил расскажет об обучении ребят программированию в 2019-м году.
  8. **Предисловие**
  9. Осенью 2019-го я в третий раз участвовал в курсе обучения ребят 10-15 лет программированию в качестве одного из преподавателей. Наши курсы проходили с середины сентября по середину декабря. Каждое занятие было в субботу с 10:00 до 12:00. Подробнее о структуре каждого урока и деталях создаваемой на курсе игры можно узнать из [статьи за 2018-й год][article-2018].
  10. Лично для себя я выделил две основные цели, к которым иду с помощью курсов:
  11. * создать удобный инструмент для создания простейших игр, понятный заинтересованным людям в возрасте от 10 лет;
  12. * создать программу обучения программированию, позволяющая заинтересованным людям в возрасте от 10 лет самостоятельно делать простейшие игры.
  13. **Игра**
  14. ![Игра][screenshot-game]
  15. Простейшей игрой уже второй раз является игра на память, суть которой в поиске совпадающих элементов на игровом поле. Детально механика игры разобрана в [статье за 2018-й год][article-2018]. Поиграть в созданную на курсе игру вы можете прямо из браузера [по этой ссылке][game].
  16. **Инструмент**
  17. ![Среда][screenshot-ide]
  18. Основным критерием при создании инструмента для меня являлась **неприхотливость**, выражающаяся в следующем:
  19. 1. работает на любой операционной системе
  20. * разработка на Linux, macOS, Windows
  21. * воспроизведение результата на ПК, планшете и мобилках
  22. 1. не нужно ничего настраивать: открыл ссылку в браузере и начал работу
  23. 1. фактически не нужен интернет: можно работать локально, т.к. нет какого-либо сервера на стороне
  24. 1. результат доступен всем
  25. * если положить на GitHub Pages, то достаточно дать ссылку
  26. * если кинуть файл по Skype, то его можно открыть локально
  27. Инструмент представляет из себя интегрированную среду разработки (ИСР), технически являющуюся одним файлом HTML. В этом единственном файле находится как ИСР, так и создаваемый результат (в данном случае игра на память). Инструмент в целом выглядит довольно стандартно:
  28. 1. слева находится панель кода выбранного модуля;
  29. 1. посередине - панель с кнопками перезапуска, сохранения результата и управления модулями;
  30. 1. в правом верхнем углу - результат;
  31. 1. в правом нижнем углу - список всех модулей: как относящихся к ИСР, так и созданных для игры.
  32. Ввиду того, что у нас лишь один файл, нам нужно уметь запускать его в двух режимах:
  33. 1. воспроизведение
  34. * является режимом по умолчанию
  35. * достаточно просто открыть файл HTML
  36. 1. редактирование
  37. * доступно при добавлении символов `?0` в адресной строке
  38. Временное хранение изменений осуществляется с помощью хранилища браузера (IndexedDB). Для сохранения изменений на постоянной основе, например, для публикации, необходимо скачать этот же самый файл с изменениями, нажав на соответствующую кнопку в средней панели.
  39. **Первые занятия**
  40. Для первого занятия я подготовил [80 строк кода на JavaScript][80-sloc], распечатал их и раздал каждому. Каждый ученик должен был набрать распечатанный код в инструменте. Набором кода я преследовал две цели:
  41. 1. узнать скорость набора текста учениками;
  42. 1. показать API инструмента.
  43. Скорость набора оказалась чрезвычайно низкой: от примерно 14 символов в минуту (ученик успел набрать лишь половину) до примерно 39 символов в минуту. Сам я этот код набирал со скоростью 213 символов в минуту, поэтому от результатов учеников опешил: у меня появилось подозрение, что написать необходимые 300 строк игры за 1 час мы к концу курса не осилим физически.
  44. На втором занятии мы в набранном ранее коде искали опечатки. Я встретил такие опечатки, которые ни у себя, ни у других коллег в жизни не находил. Тут я опешил второй раз: ученикам было чрезвычайно сложно найти опечатки, даже имея перед глазами распечатанный код. Страшно представить, что случилось бы с их психикой, если бы мы проходили [жесточайший тест по дизайну интерфейсов][cant-unsee] с вопросами вроде такого:
  45. ![Can't unsee][screenshot-cant-unsee]
  46. С третьего по шестое занятия я уменьшал код вплоть до 10 строк, выдавал инструмент уже с частично набранным кодом, в котором нужно было найти и исправить ошибки. Ничего не помогало: ученики просто не воспринимали написанное, как-будто вместо чего-то членораздельного на экране видели иероглифы.
  47. **Успешное седьмое занятие**
  48. Прошло уже больше половины курса, а я не продвинулся ни на йоту. В очередной попытке найти хоть какой-то способ объяснить код игры я ещё раз переписал игру. На этот раз с модулем под интригующим названием `последовательность`.
  49. К моему удивлению, на занятии был оглушительный успех: мы успели до "звонка", и ребята буквально горели энтузиазмом. Горели настолько, что устроили под конец занятия мозговой штурм о том, чего бы ещё добавить в появившуюся в ходе занятия игру:
  50. ![Мозговой штурм][screenshot-brainstorm]
  51. Итак, давайте разберём это занятие подробнее.
  52. **Доска**
  53. Предыдущие занятия у нас строились в формате "преподаватели подходят к каждому ученику и помогают ему индивидуально". За шесть занятий мы - два преподавателя - осознали, что подход к каждому и погружение в частные опечатки/ошибки занимает времени больше, чем объяснение нового материала.
  54. С седьмого занятия мы решили завязать всех учеников на доску, т.е. доска становилась центральным местом, где все мы творили, куда выходили и где писали. Компьютеры же превращались в место, куда ученики копируют содержимое доски. Практика показала, что доски в школах существуют не зря:
  55. * все в школе привыкли получать информацию с доски, поэтому знали, куда смотреть;
  56. * преподаватель работает с тем, что на доске, поэтому может объяснять сразу всем про одно, без углубления в индивидуальные ошибки;
  57. * исправление индивидуальных ошибок происходит быстрее, т.к. большинство из них связаны с невнимательностью, т.е. опечатками при копировании с доски.
  58. Важно отметить, что на доске преподаватели работают совместно с учениками: преподаватель задаёт направление, но ученики сами выходят и пишут на ней ответы на вопросы, заданные преподавателем. Плюсы такого подхода следующие:
  59. * ученик сам пишет, т.е. принимает решение и реализует его сам, учитель не записывает с его слов;
  60. * ученик выходит к доске, т.е. двигается, что и полезно, и уменьшает количество необузданной энергии;
  61. * ученику приходится запоминать код, чтобы записать его на доске;
  62. * по тому, насколько легко и организованно ученик запомнил и записал код на доске, можно судить о его внимательности.
  63. **Последовательность**
  64. Модуль `последовательность` для игры на память выглядит следующим образом:
  65. ![Последовательность][screenshot-sequence]
  66. Последовательность позволяет записать алгоритм в виде событий и реакций:
  67. * события (`начало`, `выбор` и т.д.) расположены без отступа слева;
  68. * реакции (`настроить ThreeJS`, `показать заставку`) расположены под соответствующими событиями с отступом.
  69. Таким образом, при запуске игры (событие `начало`) мы настраиваем ThreeJS (реакция `настроить ThreeJS`), показываем заставку (реакция `показать заставку`) и т.д.
  70. Занятие мы начинали с практически пустым модулем `последовательность`, присутствовали заранее лишь события без реакций:
  71. ![События][screenshot-events]
  72. Эти же события я выписал на доске, оставив свободное место для записи реакций (замазано уже в GIMP для удобства иллюстрации):
  73. ![События на доске][screenshot-board-events]
  74. Реакции мы искали в модуле `память.реакции`:
  75. ![Реакции][screenshot-reactions]
  76. Каждая реакция модуля `последовательность` представлена в модуле `память.реакции` [функцией-конструктором][constructor-function]. Например, реакции `проверить окончание` однозначно соответствует функция `ПроверитьОкончание`:
  77. ```javascript
  78. function ПроверитьОкончание(мир) // 1.
  79. {
  80. мир.состояние["скрыто сфер"] = 0; // 2.
  81. this.исполнить = function() // 3.
  82. {
  83. мир.состояние["скрыто сфер"] += 2; // 4.
  84. var скрыто = мир.состояние["скрыто сфер"]; // 5.
  85. var сфер = мир.состояние["сферы"].length; // 6.
  86. if (сфер == скрыто) // 7.
  87. {
  88. мир.события["конец"].уведомить(); // 8.
  89. }
  90. };
  91. }
  92. ```
  93. Рассмотрим эту функцию подробнее:
  94. 1. Функция принимает на вход `мир` (словарь), используемый для общения функций друг с другом. `мир` состоит из трёх областей (ключей словаря):
  95. * `состояние` содержит переменные значения для обмена данными;
  96. * `настройки` содержат константные значения для настройки функций;
  97. * `события` содержат [издателей][pub-sub] для организации возможности подписать функции на события.
  98. 1. Экземпляр функции-конструктора создаётся оператором `new` при разборе модуля `последовательность`. Фактически всё, что не входит в метод `исполнить`, является телом конструктора. В частности, здесь мы создаём переменную `скрыто сфер` для учёта количества скрытых сфер.
  99. 1. Метод `исполнить` вызывается на каждое уведомление о событии.
  100. 1. Т.к. реакцию `проверить окончание` вызывают на событие сокрытия пары сфер, то счётчик `скрыто сфер` увеличиваем на `2`.
  101. 1. Просто задаём короткий псевдоним для счётчика `скрыто сфер`.
  102. 1. Получаем общее количество сфер на игровом поле.
  103. 1. Сравниваем количество скрытых сфер с общим их количеством.
  104. 1. Если они равны, т.е. все сферы скрыты, уведомляем о завершении игры с помощью события `конец`.
  105. Поиск функций в модуле `память.реакции` ученики осуществляли по очереди:
  106. * ученик ищет функцию в модуле (для упрощения я разделил функции символами `// // // //`);
  107. * при нахождении озвучивает название функции и выходит к доске;
  108. * на доске пишет название функции в общий список найденных функций (допускается пользоваться любыми средствами для запоминания названия, кроме подсказки преподавателя).
  109. Это упражнение тоже позволяет проследить, кто внимательно следит за поиском и записью функции, а кто не может, когда подходит его очередь, найти свою функцию.
  110. После выписывания названий всех функций на доску мы сопоставляли события с реакциями (функциями) схожим образом:
  111. * преподаватель спрашивает, например, какие из функций подходят для события `начало`
  112. * в случае верного ответа предлагает ученику
  113. * выйти к доске
  114. * написать реакцию под событием
  115. * вычёркнуть соответствующую функцию из списка найденных функций
  116. После получения более-менее рабочего набора реакций для одного события можно предложить ученикам перенести реакции с доски в компьютеры. Таким образом мы заполняем реакции как на доске:
  117. ![Последовательность на доске][screenshot-board-sequence]
  118. ![Функции на доске][screenshot-board-functions]
  119. так и в инструменте:
  120. ![Последовательность][screenshot-sequence]
  121. **Следующие занятия**
  122. На следующих занятиях мы пытались создать новую реакцию и соответствующую ей функцию-конструктор. Сначала я пытался опять наскоками (целыми строками кода) вбить решение в головы, однако, существенных результатов это не дало. Поэтому пришлось разбирать в течение нескольких занятий примерно такой код:
  123. ```js
  124. var кот = "9";
  125. console.log(кот);
  126. ```
  127. К сожалению, донести смысл этих двух строк кода так и не удалось: ребята путались в том, что такое переменная, а что такое значение. На этом проблемы не закончились: в новой функции нужно было работать с массивом, что оказалось просто невозможно объяснить. Мне ещё предстоит научиться объяснять переменные и массивы в ходе следующих курсов.
  128. К концу занятий мы, конечно, функцию написали, но понимания и последующей веры в себя, выраженной в горящем энтузиазме, как это было на седьмом занятии, уже не было.
  129. **Последнее занятие**
  130. На последнем занятии вместо стандартного круга приветствия я попросил каждого (включая себя) высказаться, что понравилось в курсе (+), а что стоит изменить (-). Получилась следующая таблица:
  131. ![Ретро][screenshot-retro]
  132. Как ни странно, ребятам не нравилось писать на доске, несмотря на то, что она увеличивала эффективность изложения материала. С одной стороны, была "объёмная программа", а с другой - "одно и то же каждый урок", т.е. повторение пройденного ранее материала.
  133. Раз в несколько занятий мы сохраняли результат на GitHub. Давалось это тоже нелегко: мы тратили до получаса на то, чтобы каждый вошёл в свою учётную запись. Как всегда, никто не помнил свой пароль (причём каждый раз) либо для подтверждения захода с нового устройства требовался доступ к почте, пароль от которой либо тоже никто не помнил, либо почта была родительская (ребята звонили родителям).
  134. Так или иначе, у каждого ученика к концу курса осталась собственная версия игры с персональными заставкой и концовкой:
  135. ![Адрес][screenshot-addr]
  136. **Выводы**
  137. С одной стороны, были явные успехи:
  138. * инструмент оказался неприхотливым и полностью работоспособным;
  139. * концепция последовательностей была хорошо принята.
  140. С другой стороны, были явные неудачи:
  141. * инструмент предполагает навык работы с JavaScript, чем ученики не обладали;
  142. * программа обучения буксовала практически все занятия.
  143. Поэтому в ходе курса обучения программированию 2020-го года я попробую ответить на следующие вопросы:
  144. 1. Будет ли другой язык (Python, Lua) проще для объяснения и работы?
  145. 1. Можно ли скрыть работу с Git внутри инструмента, чтобы сохранять результат на [Git, не покидая инструмента][isomorphic-git]?
  146. 1. Можно ли сделать декларативный API по аналогии со [SwiftUI][swiftui]?
  147. 1. Как всё-таки объяснить переменные и массивы?
  148. Ответы на эти и другие вопросы будут через год ;)
  149. ![Группа][screenshot-group]
  150. [screenshot]: ../../images/2020-02-11_teaching-to-program-2019_screenshot.png
  151. [article-2018]: teaching-kids-to-program.html
  152. [screenshot-game]: ../../images/2020-02-11_teaching-to-program-2019_game.png
  153. [game]: http://kornerr.ru/ekids2019
  154. [screenshot-ide]: ../../images/2020-02-11_teaching-to-program-2019_ide.png
  155. [80-sloc]: http://kornerr.ru/ekids19?техника
  156. [cant-unsee]: https://cantunsee.space/
  157. [screenshot-cant-unsee]: ../../images/2020-02-11_teaching-to-program-2019_cant-unsee.jpg
  158. [screenshot-brainstorm]: ../../images/2020-02-11_teaching-to-program-2019_brainstorm.jpg
  159. [screenshot-sequence]: ../../images/2020-02-11_teaching-to-program-2019_sequence.png
  160. [screenshot-events]: ../../images/2020-02-11_teaching-to-program-2019_events.png
  161. [screenshot-board-events]: ../../images/2020-02-11_teaching-to-program-2019_board-events.jpg
  162. [screenshot-reactions]: ../../images/2020-02-11_teaching-to-program-2019_reactions.png
  163. [constructor-function]: https://learn.javascript.ru/constructor-new
  164. [screenshot-board-sequence]: ../../images/2020-02-11_teaching-to-program-2019_board-sequence.jpg
  165. [screenshot-board-functions]: ../../images/2020-02-11_teaching-to-program-2019_board-functions.jpg
  166. [screenshot-retro]: ../../images/2020-02-11_teaching-to-program-2019_retro.jpg
  167. [screenshot-addr]: ../../images/2020-02-11_teaching-to-program-2019_addr.jpg
  168. [screenshot-group]: ../../images/2020-02-11_teaching-to-program-2019_group.jpg
  169. [isomorphic-git]: https://isomorphic-git.org/
  170. [swiftui]: https://medium.com/someswift/swiftui-dsl-%D0%BD%D0%B0-%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D0%BA%D0%B0%D1%85-891741685efe
  171. [pub-sub]: https://ru.wikipedia.org/wiki/%D0%98%D0%B7%D0%B4%D0%B0%D1%82%D0%B5%D0%BB%D1%8C-%D0%BF%D0%BE%D0%B4%D0%BF%D0%B8%D1%81%D1%87%D0%B8%D0%BA_(%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD_%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F)