23 окт. 2011 г.

Бессистемность

...Мы называемся школой танцев.
Но мы не учимся, мы танцуем...
(c) Михаил Щербаков

Добрый день.

1. Предисловие.

Одни люди настаивают на последовательном и системном обучении, критикуя любителей «салата» из разнородных навыков, а другие справедливо возражают, что от некоторых строгих учебников и уснуть можно, а спящий человек медленно учится. Кто же из них прав? Тут всё зависит от обучаемых.

Например, как первоклассников учат английскому языку? Сначала с ними разучивают песенки-стишки, придумывают простейшие игры, разыгрывают весёлые сценки-диалоги. Конечно, параллельно стараются учить алфавит и так далее (тоже в форме песенок). Но нормальные учителя не стремятся с первых же занятий отбить желание учиться, поэтому не грузят грамматикой. Математики тоже не пугают детей уравнениями третьей степени. Да и аксиомы Пеано в первом классе не дают, а ведут беседы о грушах и яблоках у Пети и Маши. А можно ли обучить ребёнка программированию, заперев его в комнате с книгами, например, Кнута? Конечно нет, поэтому сначала ребёнку дают что-то вроде Light Bot, а потом помогают самому написать что-то простое и интересное. И это правильно.

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

2. Задача.

Можно было назвать эту заметку «Множественное число в английском языке и javascript». Или вот другое подходящее длинное название: «Регулярные выражения, js и английский язык в одном флаконе».

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

Итак, в нынешней серии заметок мы вспомним/узнаем следующие простейшие вещи:
1) правила формирования множественного числа существительных в английском языке,
2) создание простейшей таблички и формы в HTML,
3) элементарную работу со строками в Javascript,
4) подход к тестированию программного обеспечения.

Почему Javascript, а не какой-нибудь «продвинутый» язык? Да потому что Javascript сейчас есть почти в любом устройстве, умеющем открывать сайты. Поэтому каждый человек может мгновенно посмотреть на результат работы своей программы, написанной на коленке, не задумываясь об установке среды разработчика и прочих сложностях.

3. К делу.

И вот пришёл к нам этот пятиклассник, мечтающий научиться программировать. Голова у него есть, поэтому берёмся за это увлекательное дело. Естественно, можно было порекомендовать ему прочитать какую-нибудь книжку (того же Вирта «Алгоритмы и структуры данных»). Но если ребёнок сам искренне хочет учиться, то надо его поддержать, а не «посылать». Книжку, конечно, ему тоже надо будет прочитать, но пусть сперва увидит первые результаты, пусть почувствует, что у него получается.

— Что будем программировать?
— Не знаю.
— Что-нибудь уже писал на каком-нибудь языке?
— Только свою страничку в интернете на html. Но это же не язык программирования?
— Верно. Но хоть что-то. С Javascript что-то пробовал?
— Да, поставил код счётчиков и гостевой книги на свою страничку.
— Отлично. Давай выберем то, что было бы интересно сделать! Захватывающую игру написать будет трудно, поэтому предлагаю автоматизировать что-нибудь, что пока плохо получается делать головой. Есть такое на примете?
— Да, мы сейчас на английском прошли множественное число, а там столько правил и исключений! Как бы это всё понять?(да, конечно это было после 5 минут расспросов)

Да, ребёнка постарше можно отправить, например, на сайт Codecademy (там можно научиться чуть-чуть писать на JS, если уметь чуть-чуть читать по-английски). Но индивидуальный подход зачастую срабатывает лучше, чем неплохая автоматика.

— Умеешь сделать простую табличку два на два?
— Запросто! Вот так:

<table>
  
<tr><td>left-top</td><td>right-top</td></tr>
  
<tr><td>left-bottom</td><td>right-bottom</td></tr>
</table>

— Отлично! Теперь давай учиться делать функции. Потом мы реализуем серьёзную функцию, которая будет преобразовывать существительные из единственного числа во множественное, но пока нам надо создать простую функцию-заглушку. Это нам нужно, чтобы научиться её тестировать.
— А как?
— Создай файл plural.html со следующим кодом, а потом открой его браузером

<script type="text/javascript">
function getPlural(iSingular) {
  
return iSingular;
}
document.write(
'Test: ' + getPlural('test'));
</script>

— Вижу только строчку «Test: test».
— Да, это последняя строка твоей программы вывела склейку двух строк: «Test: » и результат работы функции getPlural(), получившей на вход строку «test» (а сейчас эта функция возвращает именно то, что получает в качестве аргумента).
— Ага, примерно понятно. А как её тестировать?
— А давай найдём в интернете какой-нибудь тест на знание правил образования множественного числа. Возьмём из этого теста вопросы и ответы — вот и будет тестовая база для нашей программы.

Уже через 15 минут у нас была табличка из четырёх десятков тестовых пар «fork-forks», «book-books» и так далее. Я объяснил, что такое массивы, как можно их описывать в Javascript, поэтому довольно скоро наш файл plural.html расширился функцией, проверяющей, совпадает ли ответ из теста с ответом нашей функции getPlural (а совпадать почти никогда не должно, потому что функция ещё ничего не делает). Конечно, пришлось многое показать и рассказать, но школьник попался толковый, поэтому вникал быстро. Скоро наша программа приобрела следующий вид:

<script type="text/javascript">
function getPlural(iSingular) {
  
return iSingular;
}

function testPlural() {
  
var aSingular = new Array("fork", "watermelon", "dress", "bridge", "book", "garage", "store", "pencil", "horse", "bay", "turkey", "Japanese", "coin", "staple", "fish", "key", "pepper", "wolf", "kitten", "foot", "sky", "oasis", "sit-in", "copy", "commando", "spy", "forget-me-not", "cloud", "watch", "factory", "man", "foot", "mouse", "woman", "tooth", "louse", "child", "ox", "goose");
  
var aPlural = new Array("forks", "watermelons", "dresses", "bridges", "books", "garages", "stores", "pencils", "horses", "bays", "turkeys", "Japanese", "coins", "staples", "fish", "keys", "peppers", "wolves", "kittens", "feet", "skies", "oases", "sit-ins", "copies", "commandos", "spies", "forget-me-nots", "clouds", "watches", "factories", "men", "feet", "mice", "women", "teeth", "lice", "children", "oxen", "geese");
  
var nbErr = 0;
  
for (var i = 0; i < aSingular.length; i++) {
    
if (aPlural[i] != getPlural(aSingular[i])) {
      nbErr
= nbErr + 1;
      document.write(
'For the noun ' + aSingular[i] + ' the plural form must be ' + aPlural[i] + ', but getPlural() returned ' + getPlural(aSingular[i]) + '<br>');
    }
  }
  document.write(
'<b>Number of errors: ' + nbErr + ', number of tests: ' + aSingular.length + '</b>');
}

testPlural();
</script>

Как видите, большая часть этой программы — это таблица существительных (единственное число хранится в массиве aSingular, а множественное — в массиве aPlural). Дальше в цикле for проводится проверка для каждого элемента массива aSingular, совпадает ли ответ нашей функции getPlural() с эталонным ответом, хранящимся в массиве aPlural. Если не совпадает, то программа на единичку увеличивает счётчик ошибок nbErr.

Нынешняя реализация функции getPlural() ничего толкового не делает (не меняет входную строку), поэтому все её ответы должны были быть неправильными. Но радостная новость состоит в том, что даже эта функция-заглушка успешно прошла два теста из тридцати девяти (скопируйте текст этой «программы» в файл plural.html, а потом просто откройте его браузером, чтобы убедиться в этом).

— Отлично, программа работает. Но 37 ошибок из 39 — это очень много. Давай остановимся на более весёлой ноте. Как обычно образуется множественное число в английском языке?
— Добавляется «s».
— Верно! Давай научим нашу функцию хотя бы этому. Ты уже умеешь склеивать строки, поэтому всё можешь сам.
— Да, сейчас попробую. Там же всего одну строчку надо поправить

function getPlural(iSingular) {
  
return iSingular + 's';
}

Ух ты, всего 20 ошибок!
— Вот видишь, мы сразу смогли увидеть, как поменялись результаты работы нашей программы после минимальной правки. Это одно из преимуществ данного подхода (сначала создаём тесты, а потом программу). В тестировании ничего не надо делать вручную, если это можно автоматизировать. А если что-то автоматически сделать нельзя, то надо подумать, а потом всё равно автоматизировать :)

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

Ну а я скоро опубликую продолжение этой истории.

Хорошего дня!

18 комментариев:

  1. Это очень здорово и интересно мне очень не хватало такого в школе )

    ОтветитьУдалить
  2. Анонимный23.10.2011, 22:35

    Этого не хватало многим в школе или на первом курсе.

    Одну вещь я лишь не пойму. Почему iSingular, а не просто singular?

    ОтветитьУдалить
  3. Анонимный23.10.2011, 23:20

    Да, любопытно почитать, как дальше будут развиваться события. С ходу я бы добавил еще одну проверку, а все нестандартные слова обрабатывал по словарю (если ничего не путаю, устойчивой системы в исключениях нет). Именно поэтому интересно, до чего дойдет у вас... Пишите, пожалуйста!

    ОтветитьУдалить
  4. Анонимный24.10.2011, 00:25

    Как учитель информатики по образованию, я считаю, что это все же сложноватый пример для пятиклассника. И функции и массивы и циклы и ветвления - брр))

    ОтветитьУдалить
  5. Анонимный24.10.2011, 01:42

    Очень интересно, и не только пятиклассникам.

    ОтветитьУдалить
  6. Я как-то писал про Testing first - сначала тестировать Это неоконченная серия заметок. Лично мне категорически не нравится этот подход.

    ОтветитьУдалить
  7. slynko, есть много разных стандартов кодирования. Мне, например, так удобно:
    * входные параметры функции называются iName,
    * выходные - oName,
    * изменяемые в процессе работы функции - ioName
    и так далее.

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

    Уважаемый аноним, преподающий информатику, Вы правы, далеко не всем пятиклассникам по силам такое блюдо. Если бы этот был слабее, то и делали бы мы с ним что-нибудь более простое. Я предпочитаю загружать ребёнка на 105%, а не на 200%. Так как в первом случае школьник интенсивно растёт (у него не всё получается, но прогресс потрясает), а во втором - просто опускаются руки от неподъёмной задачи.

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

    ОтветитьУдалить
  8. Очень хочу продолжения.

    ОтветитьУдалить
  9. Анонимный24.10.2011, 19:35

    Очень интересно, жду продолжения

    ОтветитьУдалить
  10. Я тоже заинтересован :).

    ОтветитьУдалить
  11. Так как комментариев не густо, то я попробую ещё раз сформулировать свою мысль. Цитата:

    "Потом мы реализуем серьёзную функцию, которая будет преобразовывать существительные из единственного числа во множественное, но пока нам надо создать простую функцию-заглушку. Это нам нужно, чтобы научиться её тестировать."

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

    Так вот, хотя я признаю, что методология testing first приведённая выше имеет право не существование, хотя лично я её не люблю, я не считаю умно начинать с неё. Нужно сначала было сделать простую имплиментацию с добавлением "s" в конце слова, затем показать, как вручную можно протестировать эту функцию. Привести примеры, где это не работает и отослать ученика учить английский.

    На следующем этапе, когда ученику надоест всё время нажимать на refresh и проверять одни и те же "плохие" слова, всякий раз, когда он улучшает имплиментацию, можно написать автоматическую систему тестирования. Тогда ученик поймёт, почему это важно. И уже в самом конце, а ещё лучше в другом упражнение можно упомянуть о том, что вопрос когда писать тест, до написания кода, после или во время является отдельным интересным вопросом и объяснить ему что такое функции-заглушки. Лично я пишу тесты во время написания кода и естественно добавляю новые test cases, при починке багов.

    ОтветитьУдалить
  12. Обычно на Информатике учат рисовать что-то - это универсально всем интересно, но если это один ученик, то можно конечно и так.
    А что касается языка и IDE, что мешает например BASIC-256 использовать (если конечно ученик сам не хочет какой-то конкретный язык). Я на Спектруме в детстве с ним познакомился.
    Часто basic ругают, но на данный момент VBA пока еще в большинстве компьютеров (MSOffice). К тому же у ребетенка главное сформировать представление об алгоритмах.
    У меня не ИТ специальность, но я могу читать код почти на любом языке кроме редкой экзотики и asm-а, что иногда сильно помогает в работе - макросы в экселе, auto-it, у разработчиков попросить код pl/sql и понять где они с логикой накосячили...

    ОтветитьУдалить
  13. Анонимный02.11.2011, 11:22

    Интересно было бы знать, насколько сложным иностранцы считают наш язык в плане исключений. Как им удается запомнить всё это:

    держАТЬ - держУ
    скакАТЬ - скачу (а не скакУ, что напрашивается по аналогии)
    скачАТЬ - скачаю (а не скачУ)

    нагнУТЬ - нагнУ
    нагинАТЬ - нагинаю (а не нагинУ)
    нагнАТЬ - нагоню, а не нагнУ

    поживАТЬ - поживАЮ
    пожевАТЬ - пожую (а не пожевАЮ)

    Неправы те кто сетует что в английском много исключений.

    ОтветитьУдалить
  14. Анонимный02.11.2011, 11:28

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

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

    ОтветитьУдалить
  15. Анонимный07.11.2011, 04:34

    Как им удается запомнить всё это:
    ... поскипано ...

    Примеры может и интересные, но совершенно некорректные - разные глаголы приводятся к разным формам.

    ОтветитьУдалить
  16. Бесполезно усиленно учить языки без практики. Базовые знания и грамматику можно выучить на уроках, но не более того. Это универсально.
    Я в школе Биологию на 5 экзамен сдал, сейчас я вообще ничего не помню кроме базы - не нужно оно мне.
    По английскому у меня никогда пятерки не было, но 5 лет MMO игр на евро серверах позволяют мне достаточно свободно общаться, смотреть сериалы и фильмы на английском и в большинстве случаев переводить на лету.

    Согласен с lugka.

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

    ОтветитьУдалить
  17. alexsmail, согласен, этот подход может сработать. Но иногда дети оказываются слишком энергичными: им не жалко времени на постоянный ввод одних и тех же запросов при проверках. Это мы (взрослые люди) ленимся много раз делать одно и то же. А ребёнку порой это легко (ему радостно "работать за компьютером", поэтому он готов долбить одни и те же проверки сколько угодно раз). Но повторюсь, что я согласен, что часто это работает (а для некоторых задач автоматизации это вообще наилучший вариант - показать, что руками всё делать долго и неэффективно, поэтому надо делать робота).

    Андрей, VisualBasic преобладает на компьютерах с MSOffice, который на школьный linux обычно не ставят :)
    С тем, что не надо зацикливаться на одном языке согласен, конечно. Basic256 может и неплох, но его тоже надо ставить (как и почти что угодно), а браузер есть сразу и везде.

    Что касается бесполезности языков без практики, то не могу согласиться с этим категоричным утверждением. Всё зависит от того, что мы считаем полезным.

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

    Спасибо за пример с правилом Крамера!

    Вышло продолжение заметки, поэтому предлагаю развить обсуждение уже там.

    ОтветитьУдалить
  18. Анонимный25.01.2015, 07:22

    Для начинающего я бы посоветовал не JS, а с Tcl
    потому что он концептуально прост, легко создаются приложения с GUI

    ОтветитьУдалить