Азы тренировки
Концепция тренировки в программировании появилась довольно давно, но собственно тренировкой она была признана лишь в начале нового тысячелетия. Вероятно, первый формальный пример тренировочной программы был напечатан на странице 6 учебника Кернигана—Ричи.[24]
main()
{
printf("hello, worldn");
}
Кто из нас не писал эту программу в той или иной форме? Мы используем ее для того, чтобы опробовать новую среду программирования или новый язык. Когда мы пишем и выполняем эту программу, это доказывает, что мы точно так же можем написать и откомпилировать любую другую программу.
Когда я был намного моложе, освоение нового компьютера обычно начиналось для меня с написания программы SQINT, вычисляющей квадраты целых чисел. Я писал ее на ассемблере, BASIC, FORTRAN, COBOL и множестве других языков. Все эти многочисленные версии одной программы также доказывали, что я могу заставить компьютер сделать то, что мне нужно.
Первые персональные компьютеры появились в магазинах в начале 1980-х годов. Каждый раз, когда мне представлялась возможность поработать за одним из них (VIC-20, Commodore-64 или TRS-80), я писал небольшую программу для вывода бесконечного потока символов ' и /'. Рисунки, которые строились такими программами, радовали глаз и выглядели намного сложнее маленькой программы, которая их строила.
И хотя эти программы были чисто учебными, программисты в целом не тренировались. Откровенно говоря, нам это просто не приходило в голову. Мы были слишком заняты написанием кода, чтобы думать о совершенствовании мастерства. Да и зачем? В те годы программирование не требовало хорошей реакции или проворных пальцев. Первые экранные редакторы появились только в конце 1970-х годов. Большая часть нашего рабочего времени проходила за ожиданием компиляции или отладкой длинных, безобразных потоков кода. Короткие циклы TDD еще не были изобретены, поэтому те нетривиальные возможности, которые открываются благодаря тренировке, были попросту не нужны.
Двадцать два нуля
Но с начала эпохи программирования прошло много времени. Некоторые обстоятельства сильно изменились, другие не изменились вовсе.
Одной из первых машин, для которых я программировал, была PDP-8/I. Компьютер имел тактовую частоту 1,5 мс и 4096 12-разрядных слов основной памяти, был размером с холодильник и потреблял значительную мощность. Его дисковый накопитель позволял хранить 32K 12-разрядных слов, а взаимодействие с оператором осуществлялось через телетайп со скоростью передачи 10 символов в секунду. Нам казалось, что это очень мощная машина, на которой можно творить чудеса.
Недавно я купил новый ноутбук Macbook Pro. Он оснащен двухъядерным процессором 2,8 ГГц, 8 Гбайт памяти, 512-гигабайтным SSD-накопителем и 17-дюймовым ЖК-экраном с разрешением 1920× 1200. Я ношу его в рюкзаке. Он легко умещается у меня на коленях и потребляет менее 85 ватт.
По сравнению с PDP-8/I мой ноутбук работает в восемь тысяч раз быстрее, имеет в два миллиона раз больше памяти, в шестнадцать миллионов раз большую емкость запоминающего устройства, потребляет 1 % мощности, занимает 1 % места и стоит в 25 раз меньше. Посчитаем:
8000 × 2000 000 × 16 000 000 × 100 × 100 × 25 = 6,4 × 1022.
Это очень большое число. Разница составляет 22 порядка! Это расстояние в ангстремах от нас до альфы Центавра; количество электронов в серебряном долларе; масса Земли в Майклах Мурах – словом, большое, очень большое число. И теперь такой компьютер стоит у меня на коленях – и вероятно, на ваших тоже!
И что я делаю с этой мощью, возросшей на 10 в 22 степени? Примерно то же, что я делал на PDP-8/I. Я пишу команды if, циклы while и команды присваивания.
О, инструменты для написания этих команд заметно улучшились, и языки стали более мощными. Но сама природа команд за это время не изменилась. Код 2010 года будет понятен программисту из 1960-х годов. Глина, из которой мы лепим свои программы, не изменилась за четыре десятилетия.
Длительность рабочего цикла
Но сам процесс работы серьезно изменился. В 1960-е годы я мог ждать день или два для получения результатов компиляции. В конце 1970-х годов программа из 50 000 строк компилировалась около 45 минут. Даже в 1990-е годы долгая сборка казалась нормой.
В наши дни программисты не ждут результатов компиляции.[25] В их распоряжении появилась такая немыслимая вычислительная мощь, что цикл «красный-зеленый-рефакторинг» может прокручиваться буквально за секунды.
Например, я веду проект FitNesse, написанный на Java и состоящий из 64 000 строк кода. Полная сборка со всеми модульными и интеграционными тестами занимает менее 4 минут. Если тесты проходят, то я публикую новую версию продукта. Таким образом, весь процесс контроля качества, от исходного кода до развертывания, занимает менее 4 минут. Время компиляции ничтожно мало. Тесты выполняются за считанные секунды. Выходит, цикл компиляции/тестирования может прокручиваться по 10 раз в минуту!
Конечно, не всегда стоит работать с такой скоростью. Часто бывает лучше замедлиться и подумать.[26] Но в некоторых ситуациях прокрутка цикла с максимальной скоростью оказывается в высшей степени производительной.
Для быстрого выполнения чего угодно необходима тренировка. Быстрая прокрутка цикла «код/тест» требует очень быстрого принятия решений. А для быстрого принятия решений необходимо успешно распознавать огромное количество ситуаций и проблем, а также просто знать решения.
Представьте двух мастеров боевых искусств во время поединка. Каждый должен понять, что пытается сделать другой, и правильно среагировать за считанные миллисекунды. В бою вам не удастся остановить время, проанализировать ситуацию и выбрать подходящий ответ. В бою нужно просто реагировать. Ваше тело реагирует, пока разум работает над стратегией более высокого уровня.
Пока вы прокручиваете цикл «код/тест» по несколько раз в минуту, ваше тело знает, какие клавиши нужно нажимать. Основная часть мозга распознает ситуацию и реагирует за миллисекунды, выдавая подходящее решение, тогда как мозг концентрируется на проблеме более высокого уровня.
И в боевых искусствах, и в программировании скорость зависит от тренированности. И в обоих случаях тренировка проходит примерно одинаково: мы выбираем набор пар «проблема/решение» и повторяем их снова и снова, пока не будем знать наизусть.
Представьте гитариста – скажем, Карлоса Сантану. Музыка в его голове просто переходит в пальцы. Он не задумывается над положением пальцев или приемами игры. Его ум свободен для планирования высокоуровневых мелодий и гармоничных сочетаний, тогда как его тело преобразует эти планы в низкоуровневые движения пальцев.
Но для достижения такой простоты игры необходима практика. Музыкант тренируется в исполнении этюдов, гамм и риффов снова и снова, пока не будет знать их наизусть.
Додзё программирования
С 2001 года я провожу демонстрацию TDD, которую я называю «игрой в кегли[27]». Это маленькое упражнение занимает около 30 минут. Оно выявляет конфликт в архитектуре, развивается до кульминационной точки и преподносит сюрприз напоследок. Я написал целую главу об этом примере.[28]
За годы я проводил эту демонстрацию сотни, а то и тысячи раз. Я достиг в ней настоящего мастерства! Я мог бы повторить ее во сне. Я свел к минимуму количество нажатий клавиш, подобрал самые удобные имена переменных и оптимизировал структуру алгоритма, пока она не стала идеальной. Хотя я тогда и не знал этого, это была моя первая ката.
В 2005 году я посетил конференцию XP2005 в Шеффилде (Великобритания). Там я участвовал в презентации под названием «Додзё программирования» (Coding Dojo), которую проводили Лорен Боссавит и Эммануэль Галло. Все присутствующие открыли свои ноутбуки и программировали вместе с докладчиками, которые применяли методологию TDD для реализации игры Конвея «Жизнь». Докладчики назвали это упражнение «ката» и сообщили, что исходная идея[29] принадлежала «Прагматику[30]» Дэйву Томасу.
С тех пор многие программисты стали использовать метафору боевых искусств для своих тренировочных сеансов. Название «Додзё программирования» тоже прижилось.[31] Иногда несколько программистов встречаются и тренируются вместе, как мастера боевых искусств. Иногда тренировки проходят в одиночку – тоже по аналогии с боевыми искусствами. Около года назад я обучал группу разработчиков в Омахе. За обедом они пригласили меня на свой сеанс «Додзё программирования». Я наблюдал за тем, как 20 разработчиков открыли свои ноутбуки и клавиша за клавишей повторяли действия своего преподавателя, который выполнял кату «игры в кегли».
В додзё используются разные виды упражнений. Некоторые из них представлены ниже.
Ката
В боевых искусствах термином ката называется строго определенный набор отрепетированных движений, имитирующих действия одной стороны в поединке. Их целью (в реальности недостижимой) является достижение совершенства. Мастер стремится к тому, чтобы научить свое тело идеально выполнять каждое движение и объединить отдельные приемы в плавную серию. Хорошо исполняемые ката очень красивы.