Идеальный программист. Как стать профессионалом разработки ПО

Мартин Роберт С.

Приложение

Инструментарий

 

 

В 1978 году я работал в Teradyne над телефонной тестовой системой, о которой упоминал ранее. Система состояла примерно из 80 тысяч строк кода ассемблера M365. Исходный код хранился на магнитных лентах.

Ленты напоминали 8-дорожечные стереокассеты, которые были так популярны в 1970-е годы. Лента была склеена, а накопитель мог перематывать только в одном направлении. Ленты в кассетах имели длину 10, 25, 50 и 100 футов. Чем длиннее была лента, тем больше времени занимала «перемотка», так как накопителю приходилось просто перематывать ее вперед до «точки загрузки». Перемотка 100-футовой ленты до точки загрузки занимала около 5 минут, поэтому мы осмотрительно подходили к выбору длины лент.

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

На полке в лаборатории лежала эталонная 100-футовая копия ленты с исходным кодом. Чтобы отредактировать файл, мы ставили в один накопитель эталонный экземпляр, а в другой – 10-футовую пустую (рабочую) ленту. Эталонная лента проматывалась до нужного файла, после чего файл копировался на рабочую ленту. Тогда мы «перематывали» обе ленты в начало, и эталонная лента ставилась обратно на полку.

На доске в лаборатории была прикреплена специальная распечатка эталонной ленты. Когда мы создавали копии файлов, которые требовалось отредактировать, мы прикрепляли цветную булавку рядом с именем этого файла. Так производился контроль изменений!

Редактирование производилось в экранном режиме. Мы пользовались очень хорошим текстовым редактором ED-402 – близким аналогом vi. Страница читалась с ленты, мы редактировали ее содержимое, записывали ее обратно и читали следующую. Страница обычно состояла примерно из 50 строк кода. Мы не могли «заглянуть вперед» на ленту и увидеть предстоящие страницы и не могли вернуться назад к уже отредактированным страницам. Поэтому мы использовали листинги.

В листингах отмечались все предстоящие изменения, после чего файлы редактировались в соответствии с пометкой. Никто не писал и не изменял код спонтанно! Это было бы самоубийством.

После внесения изменений во все файлы, которые требовалось отредактировать, мы объединяли их с содержимым эталонного экземпляра. Полученная лента использовалась для проведения компиляции и тестирования.

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

В группе было трое разработчиков. У каждого были кнопки своего цвета, поэтому мы могли легко определить, кто взял на редактирование те или иные файлы. А поскольку мы все работали в одной лаборатории и постоянно говорили друг с другом, текущее состояние кодовой базы постоянно хранилось в наших головах. Так что распечатка часто оказывалась излишней, и часто мы обходились без нее.

 

Инструменты

Современным разработчикам доступны самые разнообразные инструменты программирования. От некоторых стоит держаться подальше, но есть и такие, которыми должен уверенно владеть любой разработчик. В этой главе описан мой личный текущий инструментарий. Я не привожу полного описания всех представленных инструментов, так что обзор не является исчерпывающим. Я описываю лишь то, что использую сам.

 

Управление исходным кодом

 

В том, что касается управления исходным кодом, обычно стоит использовать программы с открытым кодом. Почему? Потому что они пишутся разработчиками и для разработчиков. Иначе говоря, разработчики пишут программы с открытым кодом для самих себя, когда им понадобится работоспособное решение.

Существует немало дорогих, коммерческих «корпоративных» систем контроля версий. По моему мнению, они продаются не столько разработчикам, сколько руководителям, менеджерам и «инструментальным группам». Список функций таких программ выглядит впечатляюще. К сожалению, в нем часто не оказывается того, что действительно нужно разработчикам. И главной проблемой обычно оказывается скорость.

 

«Корпоративные» системы управления исходным кодом

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

Вы можете регистрировать исходный код в «корпоративной» системе в конце каждой итерации (каждые две недели или около того), а в середине итераций использовать систему с открытым кодом. Все будут довольны, вы не нарушите корпоративных правил, а ваша производительность останется высокой.

 

Пессимистическая и оптимистическая блокировка

В 1980-е годы пессимистическая блокировка казалась хорошей идеей. В конце концов, простейший путь к решению проблем параллельного обновления – их распараллеливание. Если я редактирую файл, то вам лучше к нему не прикасаться. Система цветных кнопок, использованная нами в конце 1970-х, была своего рода механизмом пессимистической блокировки. Если файл был помечен кнопкой, то другие не должны были его редактировать.

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

Современные инструменты значительно лучше справляются со слиянием параллельно редактируемых исходных файлов. Ведь это нетривиальная задача: программа анализирует два разных файла и предка этих двух файлов, а затем применяет различные стратегии для определения способа интеграции параллельных изменений. И надо сказать, хорошо справляется с этой работой.

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

Когда все будет готово к регистрации изменений, выполняется операция обновления. Она сообщает нам, не было ли более ранней регистрации изменений другими пользователями, выполняет автоматическое слияние большинства изменений, находит конфликты и помогает выполнить остальные слияния. После этого объединенный код регистрируется в базе.

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

 

CVS/SVN

 

Одна из традиционных систем управления исходным кодом – CVS – была хороша для своего времени, но в современных проектах она уже начинает отставать. Хотя CVS отлично подходит для работы с отдельными файлами и каталогами, она не слишком хорошо справляется с переименованием файлов и удалением каталогов. А уж подкаталоги Attic… Чем меньше говорить об этом, тем лучше.

С другой стороны, система Subversion работает очень хорошо. Она позволяет получить доступ ко всей системе за одну операцию. В ней легко выполняются операции обновления, слияния и закрепления изменений. При отсутствии разветвляющихся изменений системы SVN достаточно просты в управлении.

 

Разветвление

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

Если вы используете SVN, то я по-прежнему считаю, что это хорошая политика. Однако в последнее время появились новые инструменты, которые полностью изменяют ситуацию. Я говорю о распределенных системах управления исходным кодом. В этой категории моим любимым инструментом является git. Сейчас я расскажу об этой системе более подробно.

 

git

Я начал использовать git в конце 2008 года. Эта система полностью изменила мой подход к управлению исходным кодом. Объяснения того, почему эта программа так сильно изменила правила игры, выходят за рамки книги. Тем не менее сравнение рис. П.1 с рис. П.2 красноречивее многих слов, которые я здесь приводить не буду.

Рис. П.1. Проект FitNesse под управлением Subversion

На рис. П.1 показан ход разработки проекта FitNesse за несколько недель под управлением SVN. Вы видите эффект моей жесткой политики отказа от ветвления. Мы попросту не использовали его, зато в главной ветке часто выполнялись операции обновления, слияния и закрепления.

На рис. П.2 показана структура нескольких недель разработки того же проекта с использованием git. Как видно из рисунка, операции ветвления и слияния происходят постоянно. Дело не в том, что я ослабил свою политику ветвления; просто такой рабочий процесс стал самым очевидным и эффективным. Отдельные разработчики создают ветви с очень коротким сроком жизни, а затем объединяют их с результатами своих коллег тогда, когда считают нужным.

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

Рис. П.2. Проект FitNesse под управлением git

Правда, я поддерживаю специальный эталонный репозиторий, в котором хранятся все опубликованные версии и внутренние сборки. Но называть его «главной ветвью» значило бы совершенно не понимать суть дела. В действительности это всего лишь удобный «снимок» всей истории, которая сохраняется локально всеми разработчиками.

Если вы не поняли что-то из сказанного, это нормально. На первых порах git вызывает немало затруднений. К тому, как работает эта система, нужно привыкнуть. Но будьте уверены: git и другие подобные системы – это будущее управления исходным кодом.

 

IDE/редактор

 

Мы, разработчики, проводим большую часть времени за чтением и редактированием кода. Инструменты, используемые нами для этих целей, значительно изменились за прошедшие годы. Некоторые из них обладают неимоверной мощью, а некоторые почти не изменились с 1970-х годов.

 

vi

Казалось бы, эпоха использования vi как основного редактора для разработки давно прошла. В наши дни появились инструменты, значительно превосходящие vi по своим возможностям, и другие простые текстовые редакторы того же типа. Однако в последнее время наблюдается заметный всплеск популярности vi, который объясняется его простотой, удобством использования, скоростью и гибкостью. Хотя vi и уступает Emacs или Eclipse по широте возможностей, он остается быстрым и мощным редактором.

При этом я уже не являюсь опытным пользователем vi. Когда-то меня называли «богом» vi, но это время давно прошло. Я использую vi время от времени, когда мне нужно быстро отредактировать текстовый файл. Я недавно использовал его для быстрого изменения исходного файла Java в удаленном режиме. Но объем полноценного кода, написанного мной в vi за последние 10 лет, ничтожно мал.

 

Emacs

Emacs до сих пор остается одним из самых мощных редакторов и, вероятно, останется им еще несколько ближайших десятилетий. Его мощь обеспечивается внутренней моделью на базе lisp. В категории инструментов редактирования общего назначения ни один другой редактор даже отдаленно не может с ним конкурировать. С другой стороны, я думаю, что Emacs не может полноценно конкурировать со специализированными интегрированными средами разработки (IDE), которые сейчас заняли лидирующее положение. Редактирование кода не относится к задачам редактирования общего назначения.

В 1990-е годы я был фанатом Emacs. Я просто не рассматривал другие варианты. Тогдашние редакторы с управлением мышью были смешными игрушками, к которым ни один разработчик не мог относиться серьезно. Но в начале 2000-х я познакомился с IntelliJ – моим фаворитом среди IDE, и уже не оглядывался назад.

 

Eclipse/IntelliJ

Я – пользователь IntelliJ. Я люблю эту систему. Я использую ее для написания кода на Java, Ruby, Clojure, Scala, Javascript и многих других языках. Она была написана программистами, которые понимают, что нужно программисту при написании кода. За прошедшие годы IntelliJ почти никогда не подводила меня, а впечатления почти всегда оставались положительными.

Среда Eclipse по своей мощи и масштабу сравнима с IntelliJ. Эти две среды качественно превосходят Emacs по возможностям редактирования Java-кода. В этой категории существуют и другие IDE, но я не упоминаю их здесь, потому что у меня нет непосредственного опыта их использования.

Эти интегрированные среды отличаются от таких инструментов, как Emacs, прежде всего чрезвычайно мощными возможностями манипулирования кодом. Например, IntelliJ позволяет извлечь суперкласс из класса всего одной командой. Вы можете переименовывать переменные, извлекать методы, преобразовывать наследование в композицию… и это далеко не полный список.

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

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

 

TextMate

Редактор TextMate мощен и нетребователен к ресурсам. Правда, он не умеет выполнять потрясающие манипуляции, на которые способны IntelliJ и Eclipse. У него нет мощного lisp-ядра и библиотеки Emacs. Он не обладает скоростью и гибкостью vi. С другой стороны, его можно быстро освоить, а выполняемые операции интуитивно понятны.

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

 

Отслеживание задач

Сейчас я использую Pivotal Tracker. Эта система проста и элегантна, она хорошо интегрируется с гибкими/итеративными методологиями и позволяет всем заинтересованным сторонам и разработчикам быстро общаться друг с другом. Я очень доволен ей.

В очень мелких проектах я иногда использую Lighthouse. Эта система очень проста и удобна в настройке и использовании, но по широте возможностей она и близко не подходит к Tracker.

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

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

Я рекомендую своим клиентам начать с подобной «ручной» системы, прежде чем приобретать специализированные программы. Освоив ручную систему, клиент получает знания, которые позволят ему сделать разумный выбор – иногда в пользу той же доски с карточками.

 

Счетчики дефектов

Группе разработчиков определенно необходим список текущих задач. К их числу относятся как задания на реализацию новых возможностей и функций, так и исправления ошибок. Для группы разумного размера (от 5 до 12 разработчиков) такой список должен содержать от несколько десятков до сотен позиций. Не тысяч! Если в вашей системе тысячи ошибок, с ней что-то не так. Если ваш список насчитывает тысячи задач и/или функций, с ней что-то не так. В общем случае список должен быть относительно небольшим, поэтому для работы с ним должно быть достаточно такого несложного инструмента, как вики, Lighthouse или Tracker.

На рынке имеются коммерческие программы, которые выглядят неплохо. Я видел, как мои клиенты пользуются ими, но пока не имел возможности поработать лично. Не имею ничего против таких инструментов – при условии, что список задач остается небольшим и легко управляемым. Когда средства отслеживания задач вынуждены работать со списками из тысяч позиций, само слово «отслеживание» теряет смысл. Список текущих задач превращается в «свалку текущих задач» (и часто пахнет соответствующим образом).

 

Непрерывная сборка

В последнее время для обеспечения непрерывной сборки я использую Jenkins. Система нетребовательна, проста, а работа с ней не требует длительной подготовки. Вы загружаете программу, запускаете ее, проводите несложную настройку конфигурации – а дальше все работает. Очень удобно.

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

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

В проекте FitNesse я требую, чтобы каждый разработчик выполнял сценарий непрерывной сборки перед регистрацией своих изменений. Сборка занимает менее 5 минут, так что она необременительна. Если в ходе сборки обнаруживаются проблемы, разработчики устраняют их до регистрации. Таким образом, автоматическая сборка редко сталкивается с какими-либо проблемами. Чаще всего проблемы при автоматической сборке возникают из-за настроек рабочей среды, поскольку моя среда автоматической сборки значительно отличается от сред разработчиков.

 

Инструменты модульного тестирования

Для каждого языка существуют свои специализированные средства модульного тестирования. Лично я использую JUnit для Java, rspec для Ruby, NUnit для. Net, Midje для Clojure и CppUTest для C и C++.

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

1. Тесты должны запускаться легко и быстро. Не важно, как именно это делается – при помощи плагинов IDE или простых утилит командной строки; главное, чтобы разработчики могли запускать эти тесты по своему усмотрению. Команда запуска должна быть тривиально простой. Например, я запускаю свои тесты CppUTest в TextMate простым нажатием клавиш command+M. Я связал эту комбинацию с запуском makefile, который автоматически выполняет тесты и выводит короткий однострочный отчет в том случае, если все тесты прошли успешно. IntelliJ поддерживает JUnit и rspec, поэтому от меня требуется лишь нажать кнопку. Для выполнения NUnit я использую плагин Resharper.

2. Программа должна выдавать четкий визуальный признак прохождения/непрохождения теста. Не важно, будет ли это зеленая полоса на графическом экране или консольное сообщение «Все тесты прошли». Суть в том, чтобы вы могли быстро и однозначно определить, что все тесты прошли. Если для определения результата тестирования приходится читать многострочный отчет или, того хуже, сравнивать выходные данные двух файлов, – условие не выполнено.

3. Программа должна выдавать четкий визуальный признак прогресса. Не важно, будет ли это графический индикатор или строка постепенно появляющихся точек – главное, чтобы пользователь видел, что процесс идет, а тестирование не остановилось и не прервалось.

4. Программа должна препятствовать взаимодействию между отдельными тестовыми сценариями. JUnit решает эту проблему, создавая новый экземпляр тестового класса для каждого тестового метода; таким образом предотвращается использование переменных экземпляров для взаимодействия между тестами. Другие инструменты запускают тестовые методы в случайном порядке, чтобы исключить возможную зависимость от конкретного порядка выполнения тестов. Независимо от конкретного выбора механизма, программа должна принять меры к обеспечению независимости тестов. Зависимые тесты – опасная ловушка, которую необходимо избегать.

5. Программа должна по возможности упрощать написание тестов. Например, JUnit предоставляет удобный API для проверки условий (assertions), а также использует рефлексию и атрибуты Java для того, чтобы отличать тестовые функции от обычных. В результате хорошие IDE могут автоматически идентифицировать тесты, а вы избавляетесь от хлопот с подготовкой тестов.

 

Инструменты компонентного тестирования

 

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

 

Определение

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

 

FitNesse

Мой любимый инструмент компонентного тестирования – FitNesse. Я написал большую часть его кода, и я являюсь его основным автором. В общем, это мое детище.

FitNesse – система на базе вики, которая позволяет бизнес-аналитикам и специалистам по контролю качества писать тесты в очень простом табличном формате. Эти таблицы имеют много общего с таблицами Парнаса по форме и предназначению. Тесты легко объединяются в пакеты, которые можно выполнить в любой момент.

Система FitNesse написана на Java, однако она может использоваться для тестирования систем на любых языках, потому что она взаимодействует с базовой системой тестирования, которая может быть написана на любом языке. В настоящее время поддерживаются языки Java, C#/.NET, C, C++, Python, Ruby, PHP, Delphi и другие.

В основе FitNesse лежат две системы: Fit и Slim. Система Fit была написана Уордом Каннингемом, послужила источником вдохновения для FitNesse и является ее близким родственником. Slim – более простая и лучше портируемая система тестирования, которой сейчас пользуются многие сторонники FitNesse.

 

Другие инструменты

Я знаю еще несколько других инструментов, которые можно отнести к категории компонентного тестирования.

• Система RobotFX была разработана инженерами Nokia. Как и в FitNesse, в ней используется табличный формат, но не на базе вики. RobotFX просто работает с неструктурированными файлами, созданными в Excel или другой аналогичной программе. Программа написана на Python, но при использовании соответствующих «мостов» может тестировать системы, написанные на любом языке.

• Green Pepper – коммерческая программа, в некоторых аспектах похожая на FitNesse. Базируется на популярной вики confluence.

• Cucumber – текстовая программа, работающая на ядре Ruby, но подходящая для тестирования на многих разных платформах. В языке Cucumber используется популярный стиль Given/When/Then.

• JBehave – аналог и «идеологический родитель» Cucumber. Программа написана на Java.

 

Инструменты интеграционного тестирования

Инструменты компонентного тестирования также могут использоваться для выполнения многих интеграционных тестов, но они плохо подходят для тестов, управляемых через пользовательский интерфейс.

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

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

Для тестирования пользовательского интерфейса я предпочитаю использовать программы Selenium и Watir.

 

UML/MDA

 

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

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

Я мечтал, что разработчики избавятся от подробностей текстового кода и начнут строить системы на более высоком диаграммном уровне. В самых дерзких мечтах программисты вообще становились лишними. Архитекторы могли строить целые системы по диаграммам UML. Ядро системы – огромное, бесстрастное и равнодушное к бедам обычных программистов – преобразует диаграммы в исполняемый код. Так выглядела великая мечта модельно-ориентированной архитектуры (MDA, Model Driven Architecture).

К сожалению, у великой мечты имеется один крошечный изъян. MDA предполагает, что проблемы создает код. Однако код сам по себе не создает проблем и никогда не создавал. Проблема заключается в детализации.

 

Детализация

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

Какими же подробностями мы управляем?

Вы знаете, чем различаются два символа \n и \r? Первый, \n – перевод строки (line feed), а второй, \r – возврат каретки (carriage return). Что такое «каретка»?

В 1960-х и начале 1970-х годов основным устройством вывода для компьютеров был телетайп. Модель ASR33 была самой распространенной.

Устройство состояло из печатающей головки, которая могла печатать до 10 символов в секунду. Печатающая головка состояла из цилиндра, на котором были нанесены рельефные символы. Цилиндр поворачивался так, чтобы к бумаге был обращен правильный символ, после чего молоточек ударял по цилиндру и прижимал его к бумаге. Между цилиндром и бумагой проходила красящая лента, краска с которой переносилась на бумагу в виде символа.

Печатающая головка перемещалась на каретке. С каждым символом каретка сдвигалась на одну позицию вправо, вместе с ней смещалась и печатающая головка. Когда каретка доходила до конца 72-символьной строки, каретку приходилось возвращать в начало строки, отправляя символ возврата каретки (\r = 0x0D); без этого печатающая головка продолжала бы печатать символы в 72 столбце, и от многократной печати там появился бы черный прямоугольник.

Конечно, этого было недостаточно. Возврат каретки не приводил к смещению бумаги к следующей строке. Если бы после возврата каретки не передавался символ перевода строки (\n = 0x0A), то новая строка была бы напечатана поверх старой.

Итак, для телетайпа ASR33 строки должны были завершаться последовательностью «\r\n». Однако и здесь была необходима осторожность, потому что возврат каретки мог занять более 100 миллисекунд. Если ограничиться отправкой «\n\r», то следующий символ мог оказаться напечатанным во время обратного хода каретки, а в середине строки появился бы смазанный символ. Для надежности символы конца строки часто дополнялись одним или двумя символами «забой» (0xFF).

В 1970-е годы, когда телетайпы стали постепенно выходить из употребления, в операционных системах UNIX последовательность конца строки сократилась до \n. Однако другие операционные системы – например DOS – продолжали использовать обозначение \r\n.

Когда вам в последний раз попался текстовый файл, использующий «неправильное» обозначение? Я сталкиваюсь с этой проблемой не реже раза в год. Два идентичных файла с исходным кодом не сравниваются, а их контрольные суммы различаются, потому что в них используются разные завершители строк. Текстовые редакторы некорректно переносят слова или разделяют строки двойным интервалом, потому что они интерпретируют \r\n как две строки. Некоторые программы понимают \r\n, но не распознают \n\r… И так далее.

Вот что я имею в виду под детализацией. Попробуйте-ка закодировать логику обработки завершителей строк на UML!

 

Без изменений и надежд

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

Движение MDA обещало, что работа с диаграммами будет осуществляться на более высоком уровне абстракции, чем работа с кодом – подобно тому, как Java находится на более высоком уровне абстракции по сравнению с ассемблером. Но и эти обещания тоже не оправдались. Различия в уровне абстракции в лучшем случае незначительны.

В завершение представьте, что в один прекрасный день будет изобретен действительно полезный диаграммный язык. Но ведь рисовать диаграммы будут не архитекторы, а программисты. Диаграммы попросту станут новым кодом, и программистам придется «рисовать» этот код – ведь в конечном итоге все сводится к подробностям, а управлять ими приходится именно программистам.

 

Заключение

С тех времен, как я занялся программированием, появилось великое множество новых и чрезвычайно мощных инструментов. Мой текущий инструментарий ограничивается небольшим подмножеством этого арсенала. Я использую git для управления исходным кодом, Tracker для отслеживания текущих задач, Jenkins для непрерывной сборки, интегрированную среду IntelliJ, XUnit для тестирования и FitNesse для компонентного тестирования.

Я работаю на компьютере Macbook Pro с процессором 2.8Ггц Intel Core i7, с 17-дюймовым монитором, 8 Гбайт памяти, 512Гбайт SSD и двумя дополнительными экранами.