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

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

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

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

14 окт. 2011 г.

Маляры и котлеты

- Илья, где ты пропадаешь две недели?
- В глубоком-глубоком роуминге :)

Но я вернулся, почти всем ответил на почту и комментарии, а теперь, извините, поделюсь неприятным впечатлением от Питерского Пулково-1. Несколько лет я не был в этом дивном месте, поэтому успел подзабыть его бардак и грязь. Если бы номер гейта на билете соответствовал реальному номеру двери, от которой автобус повезёт к самолёту, если бы табло над гейтом правильно указывало номер рейса, то сотрудницы аэропорта не были бы вынуждены кричать: «Рейс ###, подходите сюда, а рейс ### отойдите, сейчас мы не вас сажаем. Да, мы знаем, что на табло сейчас указан ваш город, поэтому не читайте табло». Зачем я это пишу? Пару лет назад помогло же :) А пока, если меня спросят европейцы, через какую из столиц лучше влетать в Россию, то я однозначно назову Москву. Как минимум, в Москве работают лифты, хорошо светят лампочки и моют туалеты, а в Пулково-1 в тёмных коридорах неподвижно стоят грязные эскалаторы, о которых сразу забываешь, посетив уборную. Злые языки утверждают, что ремонта там не было со времён блокады Ленинграда.

Ладно, забыли и проехали. Давайте лучше вспомним важный жанр задачек на поиск оптимального решения (в данном случае, минимального количества действий для достижения результата):

1. Много лет назад у нас была задачка о хрупких шариках: Есть стакан с очень дорогими одинаковыми хрупкими шариками из очень прочного материала. И есть лестница с сотней ступенек. Какой минимум шариков придётся разбить, чтобы выяснить предельную высоту (число от 1 до 100 — бросаем со ступенек), с которой можно ронять шарики целыми (т.е. чтобы они не разбились)?

2. Старинная детская задачка о готовке звучит так: На одной сковороде может поместиться не более 2 котлет. Одна сторона котлеты жарится 1 минуту. За какое минимальное время можно пожарить три котлеты с 2-х строн.

3а. Два маляра столкнулись на дороге с другими двумя малярами. Этикет обязывает каждого из первой пары поздороваться с каждым из второй пары, но руки у каждого маляра испачканы в краске своего цвета. А так как маляры не хотят пачкать руки в краске другого цвета, то у них есть несколько чистых перчаток. Какое минимальное количество перчаток они будут вынуждены испачкать, чтобы поприветствовать друг друга?

3б. Три маляра столкнулись на дороге с одним маляром. Соответственно, каждый из них должен с ним поздороваться. Остальное как в задаче (3а): их руки испачканы четырьмя цветами, есть несколько чистых перчаток. Сколько перчаток им придётся испачкать?

(последние две задачки своевременно напомнил Антон, а я чуть-чуть поменял формулировки)

Пожалуйста, напишите в комментариях статус по этим задачкам примерно в таком виде:
   1. Помню, ответ x,
   2. Давно знаю, ответ y,
   3. а) тоже слышал, ответ z1, б) первый раз слышу, ответ z2.


Хороших выходных!

Понравилась заметка? Подпишитесь на RSS-feed или email-рассылку.

Хотите поделиться ссылкой с другими? Добавьте в закладки:



Есть вопросы или предложения? Пишите письма на адрес mytribune АТ yandex.ru.

С уважением,
      Илья Весенний