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.

291 lines
29KB

  1. <!DOCTYPE html>
  2. <html>
  3. <meta charset="utf-8">
  4. <head>
  5. <style>
  6. #header
  7. {
  8. background: #2BA6E3;
  9. padding: 0.7em;
  10. text-align: left;
  11. }
  12. #header a
  13. {
  14. color: white;
  15. text-decoration: none;
  16. padding: 0.5em 1em 0.5em 1em;
  17. }
  18. #lang
  19. {
  20. float: right;
  21. }
  22. .news_item
  23. {
  24. background: #FFFFFF;
  25. width: 720px;
  26. padding: 1em;
  27. margin-top: 2em;
  28. margin-bottom: 2em;
  29. border: 1px solid #E0E0E0;
  30. text-align: left;
  31. }
  32. .news_item_contents
  33. {
  34. color: #444;
  35. line-height: 1.5em;
  36. }
  37. .news_item_date
  38. {
  39. margin-bottom: 2em;
  40. color: #aaa;
  41. }
  42. html
  43. {
  44. font-family: sans-serif;
  45. }
  46. body
  47. {
  48. background: #FAFAFA;
  49. }
  50. code, pre
  51. {
  52. font-family: monospace, serif;
  53. font-size: 1em;
  54. color: #7f0a0c;
  55. }
  56. /*
  57. figure
  58. {
  59. margin: 0px;
  60. padding: 0px;
  61. }
  62. */
  63. img
  64. {
  65. width: 720px;
  66. }
  67. a
  68. {
  69. color: #3A91CB;
  70. text-decoration: none;
  71. }
  72. table
  73. {
  74. border-collapse: collapse;
  75. }
  76. table, th, td
  77. {
  78. border: 1px solid #aaa;
  79. padding: 0.5em;
  80. margin-top: 0.5em;
  81. margin-bottom: 0.5em;
  82. }
  83. </style>
  84. </head>
  85. <body>
  86. <div id="header">
  87. <strong id="title">Open Game Studio</strong>
  88. <a href="../../ru/news/index.html">Новости</a>
  89. <a href="../../ru/game/index.html">Игры</a>
  90. <a href="../../ru/tool/index.html">Инструменты</a>
  91. <a href="../../ru/page/about.html">О нас</a>
  92. <div id="lang">
  93. <a href="../../en/news/teaching-to-program-2019.html">EN</a>
  94. <a href="../../ru/news/teaching-to-program-2019.html">RU</a>
  95. </div>
  96. </div>
  97. <center>
  98. <h1>В новостях...</h1>
  99. <div class="news_item">
  100. <h2 class="news_item_title">
  101. <a href="teaching-to-program-2019.html">Обучение программированию 2019, или в поисках идеальной программы: Последовательность</a>
  102. </h2>
  103. <p class="news_item_date">
  104. 2020-02-12 00:00
  105. </p>
  106. <div class="news_item_contents">
  107. <p><img src="../../images/2020-02-11_teaching-to-program-2019_screenshot.png" alt="МУРОМ" /></p>
  108. <p>В этой статье Михаил расскажет об обучении ребят программированию в 2019-м году.</p>
  109. <p><strong>Предисловие</strong></p>
  110. <p>Осенью 2019-го я в третий раз участвовал в курсе обучения ребят 10-15 лет программированию в качестве одного из преподавателей. Наши курсы проходили с середины сентября по середину декабря. Каждое занятие было в субботу с 10:00 до 12:00. Подробнее о структуре каждого урока и деталях создаваемой на курсе игры можно узнать из <a href="teaching-kids-to-program.html">статьи за 2018-й год</a>.</p>
  111. <p>Лично для себя я выделил две основные цели, к которым иду с помощью курсов:</p>
  112. <ul>
  113. <li>создать удобный инструмент для создания простейших игр, понятный заинтересованным людям в возрасте от 10 лет;</li>
  114. <li>создать программу обучения программированию, позволяющая заинтересованным людям в возрасте от 10 лет самостоятельно делать простейшие игры.</li>
  115. </ul>
  116. <p><strong>Игра</strong></p>
  117. <p><img src="../../images/2020-02-11_teaching-to-program-2019_game.png" alt="Игра" /></p>
  118. <p>Простейшей игрой уже второй раз является игра на память, суть которой в поиске совпадающих элементов на игровом поле. Детально механика игры разобрана в <a href="teaching-kids-to-program.html">статье за 2018-й год</a>. Поиграть в созданную на курсе игру вы можете прямо из браузера <a href="http://kornerr.ru/ekids2019">по этой ссылке</a>.</p>
  119. <p><strong>Инструмент</strong></p>
  120. <p><img src="../../images/2020-02-11_teaching-to-program-2019_ide.png" alt="Среда" /></p>
  121. <p>Основным критерием при создании инструмента для меня являлась <strong>неприхотливость</strong>, выражающаяся в следующем:</p>
  122. <ol>
  123. <li>работает на любой операционной системе<ul>
  124. <li>разработка на Linux, macOS, Windows</li>
  125. <li>воспроизведение результата на ПК, планшете и мобилках</li></ul></li>
  126. <li>не нужно ничего настраивать: открыл ссылку в браузере и начал работу</li>
  127. <li>фактически не нужен интернет: можно работать локально, т.к. нет какого-либо сервера на стороне</li>
  128. <li>результат доступен всем<ul>
  129. <li>если положить на GitHub Pages, то достаточно дать ссылку</li>
  130. <li>если кинуть файл по Skype, то его можно открыть локально</li></ul></li>
  131. </ol>
  132. <p>Инструмент представляет из себя интегрированную среду разработки (ИСР), технически являющуюся одним файлом HTML. В этом единственном файле находится как ИСР, так и создаваемый результат (в данном случае игра на память). Инструмент в целом выглядит довольно стандартно:</p>
  133. <ol>
  134. <li>слева находится панель кода выбранного модуля;</li>
  135. <li>посередине - панель с кнопками перезапуска, сохранения результата и управления модулями;</li>
  136. <li>в правом верхнем углу - результат;</li>
  137. <li>в правом нижнем углу - список всех модулей: как относящихся к ИСР, так и созданных для игры.</li>
  138. </ol>
  139. <p>Ввиду того, что у нас лишь один файл, нам нужно уметь запускать его в двух режимах:</p>
  140. <ol>
  141. <li>воспроизведение<ul>
  142. <li>является режимом по умолчанию</li>
  143. <li>достаточно просто открыть файл HTML</li></ul></li>
  144. <li>редактирование<ul>
  145. <li>доступно при добавлении символов <code>?0</code> в адресной строке</li></ul></li>
  146. </ol>
  147. <p>Временное хранение изменений осуществляется с помощью хранилища браузера (IndexedDB). Для сохранения изменений на постоянной основе, например, для публикации, необходимо скачать этот же самый файл с изменениями, нажав на соответствующую кнопку в средней панели.</p>
  148. <p><strong>Первые занятия</strong></p>
  149. <p>Для первого занятия я подготовил <a href="http://kornerr.ru/ekids19?техника">80 строк кода на JavaScript</a>, распечатал их и раздал каждому. Каждый ученик должен был набрать распечатанный код в инструменте. Набором кода я преследовал две цели:</p>
  150. <ol>
  151. <li>узнать скорость набора текста учениками;</li>
  152. <li>показать API инструмента.</li>
  153. </ol>
  154. <p>Скорость набора оказалась чрезвычайно низкой: от примерно 14 символов в минуту (ученик успел набрать лишь половину) до примерно 39 символов в минуту. Сам я этот код набирал со скоростью 213 символов в минуту, поэтому от результатов учеников опешил: у меня появилось подозрение, что написать необходимые 300 строк игры за 1 час мы к концу курса не осилим физически.</p>
  155. <p>На втором занятии мы в набранном ранее коде искали опечатки. Я встретил такие опечатки, которые ни у себя, ни у других коллег в жизни не находил. Тут я опешил второй раз: ученикам было чрезвычайно сложно найти опечатки, даже имея перед глазами распечатанный код. Страшно представить, что случилось бы с их психикой, если бы мы проходили <a href="https://cantunsee.space/">жесточайший тест по дизайну интерфейсов</a> с вопросами вроде такого:</p>
  156. <p><img src="../../images/2020-02-11_teaching-to-program-2019_cant-unsee.jpg" alt="Can't unsee" /></p>
  157. <p>С третьего по шестое занятия я уменьшал код вплоть до 10 строк, выдавал инструмент уже с частично набранным кодом, в котором нужно было найти и исправить ошибки. Ничего не помогало: ученики просто не воспринимали написанное, как-будто вместо чего-то членораздельного на экране видели иероглифы.</p>
  158. <p><strong>Успешное седьмое занятие</strong></p>
  159. <p>Прошло уже больше половины курса, а я не продвинулся ни на йоту. В очередной попытке найти хоть какой-то способ объяснить код игры я ещё раз переписал игру. На этот раз с модулем под интригующим названием <code>последовательность</code>.
  160. К моему удивлению, на занятии был оглушительный успех: мы успели до "звонка", и ребята буквально горели энтузиазмом. Горели настолько, что устроили под конец занятия мозговой штурм о том, чего бы ещё добавить в появившуюся в ходе занятия игру:</p>
  161. <p><img src="../../images/2020-02-11_teaching-to-program-2019_brainstorm.jpg" alt="Мозговой штурм" /></p>
  162. <p>Итак, давайте разберём это занятие подробнее.</p>
  163. <p><strong>Доска</strong></p>
  164. <p>Предыдущие занятия у нас строились в формате "преподаватели подходят к каждому ученику и помогают ему индивидуально". За шесть занятий мы - два преподавателя - осознали, что подход к каждому и погружение в частные опечатки/ошибки занимает времени больше, чем объяснение нового материала.</p>
  165. <p>С седьмого занятия мы решили завязать всех учеников на доску, т.е. доска становилась центральным местом, где все мы творили, куда выходили и где писали. Компьютеры же превращались в место, куда ученики копируют содержимое доски. Практика показала, что доски в школах существуют не зря:</p>
  166. <ul>
  167. <li>все в школе привыкли получать информацию с доски, поэтому знали, куда смотреть;</li>
  168. <li>преподаватель работает с тем, что на доске, поэтому может объяснять сразу всем про одно, без углубления в индивидуальные ошибки;</li>
  169. <li>исправление индивидуальных ошибок происходит быстрее, т.к. большинство из них связаны с невнимательностью, т.е. опечатками при копировании с доски.</li>
  170. </ul>
  171. <p>Важно отметить, что на доске преподаватели работают совместно с учениками: преподаватель задаёт направление, но ученики сами выходят и пишут на ней ответы на вопросы, заданные преподавателем. Плюсы такого подхода следующие:</p>
  172. <ul>
  173. <li>ученик сам пишет, т.е. принимает решение и реализует его сам, учитель не записывает с его слов;</li>
  174. <li>ученик выходит к доске, т.е. двигается, что и полезно, и уменьшает количество необузданной энергии;</li>
  175. <li>ученику приходится запоминать код, чтобы записать его на доске;</li>
  176. <li>по тому, насколько легко и организованно ученик запомнил и записал код на доске, можно судить о его внимательности.</li>
  177. </ul>
  178. <p><strong>Последовательность</strong></p>
  179. <p>Модуль <code>последовательность</code> для игры на память выглядит следующим образом:</p>
  180. <p><img src="../../images/2020-02-11_teaching-to-program-2019_sequence.png" alt="Последовательность" /></p>
  181. <p>Последовательность позволяет записать алгоритм в виде событий и реакций:</p>
  182. <ul>
  183. <li>события (<code>начало</code>, <code>выбор</code> и т.д.) расположены без отступа слева;</li>
  184. <li>реакции (<code>настроить ThreeJS</code>, <code>показать заставку</code>) расположены под соответствующими событиями с отступом.</li>
  185. </ul>
  186. <p>Таким образом, при запуске игры (событие <code>начало</code>) мы настраиваем ThreeJS (реакция <code>настроить ThreeJS</code>), показываем заставку (реакция <code>показать заставку</code>) и т.д.</p>
  187. <p>Занятие мы начинали с практически пустым модулем <code>последовательность</code>, присутствовали заранее лишь события без реакций:</p>
  188. <p><img src="../../images/2020-02-11_teaching-to-program-2019_events.png" alt="События" /></p>
  189. <p>Эти же события я выписал на доске, оставив свободное место для записи реакций (замазано уже в GIMP для удобства иллюстрации):</p>
  190. <p><img src="../../images/2020-02-11_teaching-to-program-2019_board-events.jpg" alt="События на доске" /></p>
  191. <p>Реакции мы искали в модуле <code>память.реакции</code>:</p>
  192. <p><img src="../../images/2020-02-11_teaching-to-program-2019_reactions.png" alt="Реакции" /></p>
  193. <p>Каждая реакция модуля <code>последовательность</code> представлена в модуле <code>память.реакции</code> <a href="https://learn.javascript.ru/constructor-new">функцией-конструктором</a>. Например, реакции <code>проверить окончание</code> однозначно соответствует функция <code>ПроверитьОкончание</code>:</p>
  194. <pre><code class="javascript language-javascript">function ПроверитьОкончание(мир) // 1.
  195. {
  196. мир.состояние["скрыто сфер"] = 0; // 2.
  197. this.исполнить = function() // 3.
  198. {
  199. мир.состояние["скрыто сфер"] += 2; // 4.
  200. var скрыто = мир.состояние["скрыто сфер"]; // 5.
  201. var сфер = мир.состояние["сферы"].length; // 6.
  202. if (сфер == скрыто) // 7.
  203. {
  204. мир.события["конец"].уведомить(); // 8.
  205. }
  206. };
  207. }
  208. </code></pre>
  209. <p>Рассмотрим эту функцию подробнее:</p>
  210. <ol>
  211. <li>Функция принимает на вход <code>мир</code> (словарь), используемый для общения функций друг с другом. <code>мир</code> состоит из трёх областей (ключей словаря):<ul>
  212. <li><code>состояние</code> содержит переменные значения для обмена данными;</li>
  213. <li><code>настройки</code> содержат константные значения для настройки функций;</li>
  214. <li><code>события</code> содержат <a href="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)">издателей</a> для организации возможности подписать функции на события.</li></ul></li>
  215. <li>Экземпляр функции-конструктора создаётся оператором <code>new</code> при разборе модуля <code>последовательность</code>. Фактически всё, что не входит в метод <code>исполнить</code>, является телом конструктора. В частности, здесь мы создаём переменную <code>скрыто сфер</code> для учёта количества скрытых сфер.</li>
  216. <li>Метод <code>исполнить</code> вызывается на каждое уведомление о событии.</li>
  217. <li>Т.к. реакцию <code>проверить окончание</code> вызывают на событие сокрытия пары сфер, то счётчик <code>скрыто сфер</code> увеличиваем на <code>2</code>.</li>
  218. <li>Просто задаём короткий псевдоним для счётчика <code>скрыто сфер</code>.</li>
  219. <li>Получаем общее количество сфер на игровом поле.</li>
  220. <li>Сравниваем количество скрытых сфер с общим их количеством.</li>
  221. <li>Если они равны, т.е. все сферы скрыты, уведомляем о завершении игры с помощью события <code>конец</code>.</li>
  222. </ol>
  223. <p>Поиск функций в модуле <code>память.реакции</code> ученики осуществляли по очереди:</p>
  224. <ul>
  225. <li>ученик ищет функцию в модуле (для упрощения я разделил функции символами <code>// // // //</code>);</li>
  226. <li>при нахождении озвучивает название функции и выходит к доске;</li>
  227. <li>на доске пишет название функции в общий список найденных функций (допускается пользоваться любыми средствами для запоминания названия, кроме подсказки преподавателя).</li>
  228. </ul>
  229. <p>Это упражнение тоже позволяет проследить, кто внимательно следит за поиском и записью функции, а кто не может, когда подходит его очередь, найти свою функцию.</p>
  230. <p>После выписывания названий всех функций на доску мы сопоставляли события с реакциями (функциями) схожим образом:</p>
  231. <ul>
  232. <li>преподаватель спрашивает, например, какие из функций подходят для события <code>начало</code></li>
  233. <li>в случае верного ответа предлагает ученику<ul>
  234. <li>выйти к доске</li>
  235. <li>написать реакцию под событием</li>
  236. <li>вычёркнуть соответствующую функцию из списка найденных функций</li></ul></li>
  237. </ul>
  238. <p>После получения более-менее рабочего набора реакций для одного события можно предложить ученикам перенести реакции с доски в компьютеры. Таким образом мы заполняем реакции как на доске:</p>
  239. <p><img src="../../images/2020-02-11_teaching-to-program-2019_board-sequence.jpg" alt="Последовательность на доске" />
  240. <img src="../../images/2020-02-11_teaching-to-program-2019_board-functions.jpg" alt="Функции на доске" /></p>
  241. <p>так и в инструменте:</p>
  242. <p><img src="../../images/2020-02-11_teaching-to-program-2019_sequence.png" alt="Последовательность" /></p>
  243. <p><strong>Следующие занятия</strong></p>
  244. <p>На следующих занятиях мы пытались создать новую реакцию и соответствующую ей функцию-конструктор. Сначала я пытался опять наскоками (целыми строками кода) вбить решение в головы, однако, существенных результатов это не дало. Поэтому пришлось разбирать в течение нескольких занятий примерно такой код:</p>
  245. <pre><code class="js language-js">var кот = "9";
  246. console.log(кот);
  247. </code></pre>
  248. <p>К сожалению, донести смысл этих двух строк кода так и не удалось: ребята путались в том, что такое переменная, а что такое значение. На этом проблемы не закончились: в новой функции нужно было работать с массивом, что оказалось просто невозможно объяснить. Мне ещё предстоит научиться объяснять переменные и массивы в ходе следующих курсов.</p>
  249. <p>К концу занятий мы, конечно, функцию написали, но понимания и последующей веры в себя, выраженной в горящем энтузиазме, как это было на седьмом занятии, уже не было.</p>
  250. <p><strong>Последнее занятие</strong></p>
  251. <p>На последнем занятии вместо стандартного круга приветствия я попросил каждого (включая себя) высказаться, что понравилось в курсе (+), а что стоит изменить (-). Получилась следующая таблица:</p>
  252. <p><img src="../../images/2020-02-11_teaching-to-program-2019_retro.jpg" alt="Ретро" /></p>
  253. <p>Как ни странно, ребятам не нравилось писать на доске, несмотря на то, что она увеличивала эффективность изложения материала. С одной стороны, была "объёмная программа", а с другой - "одно и то же каждый урок", т.е. повторение пройденного ранее материала.</p>
  254. <p>Раз в несколько занятий мы сохраняли результат на GitHub. Давалось это тоже нелегко: мы тратили до получаса на то, чтобы каждый вошёл в свою учётную запись. Как всегда, никто не помнил свой пароль (причём каждый раз) либо для подтверждения захода с нового устройства требовался доступ к почте, пароль от которой либо тоже никто не помнил, либо почта была родительская (ребята звонили родителям).</p>
  255. <p>Так или иначе, у каждого ученика к концу курса осталась собственная версия игры с персональными заставкой и концовкой:</p>
  256. <p><img src="../../images/2020-02-11_teaching-to-program-2019_addr.jpg" alt="Адрес" /></p>
  257. <p><strong>Выводы</strong></p>
  258. <p>С одной стороны, были явные успехи:</p>
  259. <ul>
  260. <li>инструмент оказался неприхотливым и полностью работоспособным;</li>
  261. <li>концепция последовательностей была хорошо принята.</li>
  262. </ul>
  263. <p>С другой стороны, были явные неудачи:</p>
  264. <ul>
  265. <li>инструмент предполагает навык работы с JavaScript, чем ученики не обладали;</li>
  266. <li>программа обучения буксовала практически все занятия.</li>
  267. </ul>
  268. <p>Поэтому в ходе курса обучения программированию 2020-го года я попробую ответить на следующие вопросы:</p>
  269. <ol>
  270. <li>Будет ли другой язык (Python, Lua) проще для объяснения и работы?</li>
  271. <li>Можно ли скрыть работу с Git внутри инструмента, чтобы сохранять результат на <a href="https://isomorphic-git.org/">Git, не покидая инструмента</a>?</li>
  272. <li>Можно ли сделать декларативный API по аналогии со <a href="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">SwiftUI</a>?</li>
  273. <li>Как всё-таки объяснить переменные и массивы?</li>
  274. </ol>
  275. <p>Ответы на эти и другие вопросы будут через год ;)</p>
  276. <p><img src="../../images/2020-02-11_teaching-to-program-2019_group.jpg" alt="Группа" /></p>
  277. </div>
  278. </div>
  279. <div id="footer">
  280. Сайт сгенерирован <a href="http://opengamestudio.org/pskov/ru">ПСКОВОМ</a>
  281. из <a href="http://github.com/ogstudio/site-opengamestudio">этого исходного кода</a>.
  282. Сайт размещён на <a href="https://pages.github.com">GitHub Pages</a>.
  283. </div>
  284. </center>
  285. </body>
  286. </html>