Все профессионалы оттачивают свое мастерство на специальных упражнениях. Музыканты играют гаммы. Доктора тренируются в наложении швов и выполнении других хирургических приемов. Адвокаты репетируют речи. Солдаты участвуют в учениях. Профессионалы тренируются везде, где важна эффективность выполнения работы. Эта глава полностью посвящена возможности тренировки навыков программирования.
Азы тренировки
Концепция тренировки в программировании появилась довольно давно, но собственно тренировкой она была признана лишь в начале нового тысячелетия. Вероятно, первый формальный пример тренировочной программы был напечатан на странице 6 учебника Кернигана—Ричи.
main()
{
printf("hello, world\n");
}
Кто из нас не писал эту программу в той или иной форме? Мы используем ее для того, чтобы опробовать новую среду программирования или новый язык. Когда мы пишем и выполняем эту программу, это доказывает, что мы точно так же можем написать и откомпилировать любую другую программу.
Когда я был намного моложе, освоение нового компьютера обычно начиналось для меня с написания программы 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 × 10 22 .
Это очень большое число. Разница составляет 22 порядка! Это расстояние в ангстремах от нас до альфы Центавра; количество электронов в серебряном долларе; масса Земли в Майклах Мурах – словом, большое, очень большое число. И теперь такой компьютер стоит у меня на коленях – и вероятно, на ваших тоже!
И что я делаю с этой мощью, возросшей на 10 в 22 степени? Примерно то же, что я делал на PDP-8/I. Я пишу команды if, циклы while и команды присваивания.
О, инструменты для написания этих команд заметно улучшились, и языки стали более мощными. Но сама природа команд за это время не изменилась. Код 2010 года будет понятен программисту из 1960-х годов. Глина, из которой мы лепим свои программы, не изменилась за четыре десятилетия.
Длительность рабочего цикла
Но сам процесс работы серьезно изменился. В 1960-е годы я мог ждать день или два для получения результатов компиляции. В конце 1970-х годов программа из 50 000 строк компилировалась около 45 минут. Даже в 1990-е годы долгая сборка казалась нормой.
В наши дни программисты не ждут результатов компиляции. В их распоряжении появилась такая немыслимая вычислительная мощь, что цикл «красный-зеленый-рефакторинг» может прокручиваться буквально за секунды.
Например, я веду проект FitNesse, написанный на Java и состоящий из 64 000 строк кода. Полная сборка со всеми модульными и интеграционными тестами занимает менее 4 минут. Если тесты проходят, то я публикую новую версию продукта. Таким образом, весь процесс контроля качества, от исходного кода до развертывания, занимает менее 4 минут. Время компиляции ничтожно мало. Тесты выполняются за считанные секунды. Выходит, цикл компиляции/тестирования может прокручиваться по 10 раз в минуту!
Конечно, не всегда стоит работать с такой скоростью. Часто бывает лучше замедлиться и подумать. Но в некоторых ситуациях прокрутка цикла с максимальной скоростью оказывается в высшей степени производительной.
Для быстрого выполнения чего угодно необходима тренировка. Быстрая прокрутка цикла «код/тест» требует очень быстрого принятия решений. А для быстрого принятия решений необходимо успешно распознавать огромное количество ситуаций и проблем, а также просто знать решения.
Представьте двух мастеров боевых искусств во время поединка. Каждый должен понять, что пытается сделать другой, и правильно среагировать за считанные миллисекунды. В бою вам не удастся остановить время, проанализировать ситуацию и выбрать подходящий ответ. В бою нужно просто реагировать. Ваше тело реагирует, пока разум работает над стратегией более высокого уровня.
Пока вы прокручиваете цикл «код/тест» по несколько раз в минуту, ваше тело знает, какие клавиши нужно нажимать. Основная часть мозга распознает ситуацию и реагирует за миллисекунды, выдавая подходящее решение, тогда как мозг концентрируется на проблеме более высокого уровня.
И в боевых искусствах, и в программировании скорость зависит от тренированности. И в обоих случаях тренировка проходит примерно одинаково: мы выбираем набор пар «проблема/решение» и повторяем их снова и снова, пока не будем знать наизусть.
Представьте гитариста – скажем, Карлоса Сантану. Музыка в его голове просто переходит в пальцы. Он не задумывается над положением пальцев или приемами игры. Его ум свободен для планирования высокоуровневых мелодий и гармоничных сочетаний, тогда как его тело преобразует эти планы в низкоуровневые движения пальцев.
Но для достижения такой простоты игры необходима практика. Музыкант тренируется в исполнении этюдов, гамм и риффов снова и снова, пока не будет знать их наизусть.
Додзё программирования
С 2001 года я провожу демонстрацию TDD, которую я называю «игрой в кегли». Это маленькое упражнение занимает около 30 минут. Оно выявляет конфликт в архитектуре, развивается до кульминационной точки и преподносит сюрприз напоследок. Я написал целую главу об этом примере.
За годы я проводил эту демонстрацию сотни, а то и тысячи раз. Я достиг в ней настоящего мастерства! Я мог бы повторить ее во сне. Я свел к минимуму количество нажатий клавиш, подобрал самые удобные имена переменных и оптимизировал структуру алгоритма, пока она не стала идеальной. Хотя я тогда и не знал этого, это была моя первая ката.
В 2005 году я посетил конференцию XP2005 в Шеффилде (Великобритания). Там я участвовал в презентации под названием «Додзё программирования» (Coding Dojo), которую проводили Лорен Боссавит и Эммануэль Галло. Все присутствующие открыли свои ноутбуки и программировали вместе с докладчиками, которые применяли методологию TDD для реализации игры Конвея «Жизнь». Докладчики назвали это упражнение «ката» и сообщили, что исходная идея принадлежала «Прагматику» Дэйву Томасу.
С тех пор многие программисты стали использовать метафору боевых искусств для своих тренировочных сеансов. Название «Додзё программирования» тоже прижилось. Иногда несколько программистов встречаются и тренируются вместе, как мастера боевых искусств. Иногда тренировки проходят в одиночку – тоже по аналогии с боевыми искусствами. Около года назад я обучал группу разработчиков в Омахе. За обедом они пригласили меня на свой сеанс «Додзё программирования». Я наблюдал за тем, как 20 разработчиков открыли свои ноутбуки и клавиша за клавишей повторяли действия своего преподавателя, который выполнял кату «игры в кегли».
В додзё используются разные виды упражнений. Некоторые из них представлены ниже.
Ката
В боевых искусствах термином ката называется строго определенный набор отрепетированных движений, имитирующих действия одной стороны в поединке. Их целью (в реальности недостижимой) является достижение совершенства. Мастер стремится к тому, чтобы научить свое тело идеально выполнять каждое движение и объединить отдельные приемы в плавную серию. Хорошо исполняемые ката очень красивы.
Но несмотря на красоту, ката изучаются не для сценического исполнения. Мастера изучают их для того, чтобы обучить ум и тело реагировать на конкретные боевые ситуации. Отработанные движения должны выполняться инстинктивно, чтобы они срабатывали именно в тот момент, когда они нужны.
Программные ката представляют собой строго определенный набор отрепетированных нажатий клавиш и перемещений мыши, имитирующих решение некоторой программной задачи. Вы не решаете задачу, потому что уже знаете решение. Вместо этого вы тренируетесь в выполнении действий и принятии решений, необходимых для решения задачи.
И снова целью является асимптотическое приближение к совершенству. Упражнение повторяется снова и снова, чтобы научить ваш мозг реагировать, а пальцы двигаться. В ходе тренировки могут обнаружиться определенные улучшения и повышение эффективности ваших действий или самого решения.
Отработка нескольких ката помогает запомнить «горячие клавиши» и идиомы навигации. Она также хорошо работает при изучении таких дисциплин, как разработка через тестирование (TDD) и непрерывная интеграция (CI, Continuous Integration). Но самое важное – ката помогают закрепить в подсознании пары «задача/решение»; столкнувшись с этими задачами в реальном программировании, вы попросту будете знать, как они решаются.
Программист, как и мастер боевых искусств, должен знать разные ката и регулярно тренировать их, чтобы они не стерлись из памяти. Описания многих ката находятся по адресам http://katas.softwarecraftsmanship.org и http://codekata.pragprog.com. Некоторые из моих любимых ката:
• Игра в кегли: http://butunclebob.com/ArticleS.UncleBob.TheBowling-GameKata
• Простые числа: http://butunclebob.com/ArticleS.UncleBob.ThePrime-Factors-Kata
• Перенос текста: http://thecleancoder.blogspot.com/2010/10/craftsman-62-dark-path.html
Если вам захочется непростых испытаний, попробуйте выучить ката настолько хорошо, чтобы выполнять их под музыку. Сделать это очень трудно.
Вадза
Когда я занимался джиу-джитсу, большая часть времени в додзё проводилась за парной отработкой вадза (техники). Вадза напоминает ката с участием двух человек. Все действия точно запоминаются и воспроизводятся напарниками. Один играет роль нападающего, другой обороняется. Движения повторяются снова и снова, а спортсмены меняются ролями.
Программисты могут тренироваться аналогичным образом в игре, которая называется пинг-понг. Два напарника выбирают ката или простую задачу. Один пишет модульный тест, а другой должен заставить этот тест проходить. Затем они меняются ролями.
Если напарники выбирают стандартную ката, то результат заранее известен, а программисты отрабатывают работу с клавиатурой и мышью, а также четкость запоминания ката. С другой стороны, если напарники выбирают новую задачу, игра становится более интересной. Программист, пишущий тест, оказывает заметное влияние на то, как будет решаться задача. Также в его власти установка ограничений. Например, если программисты решают реализовать алгоритм сортировки, автор теста может легко установить ограничения по скорости и затратам памяти, которые усложнят задачу его партнера. В таком виде игра становится соревновательной… и интересной.
Рандори
Рандори – свободный спарринг. Во время тренировок по джиу-джитсу мы определяли боевые сценарии, а затем отрабатывали их. Иногда один человек должен был защищаться, тогда как остальные последовательно атаковали его. Иногда два и более нападающих выступали против одного защищающегося (обычно им был наш сэнсэй, который почти всегда выигрывал). Иногда одна пара вступала в единоборство с другой и т. д.
Имитация поединка не имеет нормального аналога в программировании; тем не менее во многих программных додзё играют в игру, которая тоже называется рандори. Она очень похожа на вадза для двоих напарников, решающих задачу. Однако в рандори играет много участников, а правила слегка изменены. На экране, проецируемом на стену, один участник пишет тест. Другой участник обеспечивает прохождение теста, а затем пишет следующий тест. Ход передается по кругу или участники просто выстраиваются в очередь. В любом случае такие упражнения бывают очень забавными.
Удивительно, насколько много можно узнать из таких упражнений. Вы получаете глубокое представление о том, как другие люди подходят к решению задач. Полученная информация помогает расширить ваш кругозор и повысить квалификацию.
Расширение кругозора
Профессиональные программисты часто страдают от однообразия решаемых задач. Работодатели часто ограничиваются одним языком, платформой и предметной областью, в которой должен работать программист. Если вы не позаботитесь о расширении собственного кругозора, это может привести к нежелательному сужению резюме и менталитета. Такие программисты нередко оказываются неподготовленными к изменениям, периодически сотрясающим нашу отрасль.
Проекты с открытым кодом
Один из способов «держаться на переднем крае» позаимствован из практики адвокатов и врачей: выполняйте общественно-полезную работу, участвуя в проекте с открытым кодом. Таких проектов очень много; пожалуй, нет лучшего способа пополнить ваш творческий арсенал, чем поработать над проектом, который принесет пользу другим.
Если вы программируете на Java – поучаствуйте в проекте Rails. Если вы пишете большой объем кода C++ для своего работодателя, найдите проект Python и присоединитесь к нему.
Этика тренировки
Профессиональные программисты тренируются в личное время. Ваш работодатель не обязан заботиться о поддержании вашей квалификации или расширении вашего резюме. Пациенты не платят врачам, тренирующимся в наложении швов. Футбольные болельщики (обычно) не платят, чтобы посмотреть, как игроки бегают на тренировках. Зрители не платят за то, чтобы послушать, как музыканты играют гаммы. И работодатели программистов не обязаны оплачивать им время тренировок.
Так как тренировки проводятся в ваше личное время, вы не обязаны использовать языки и платформы своей основной работы. Выберите любой язык и проявите свои способности полиглота. Если вы работаете на платформе. NET, потренируйтесь в использовании Java или Ruby – дома или в обеденный перерыв.
Заключение
Все профессионалы тренируются тем или иным образом. Они делают это, потому что хотят как можно лучше справиться с порученным делом. Более того, они делают это в свое личное время, поскольку знают, что ответственность за повышение их квалификации лежит на них самих, а не на их работодателях. За тренировки вам никто не платит. Вы занимаетесь ими, чтобы вам платили за основную работу – и платили хорошо.