Постигая Agile — страница 53 из 89

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


Рис. 7.1. Успешные XP-разработчики имеют привычку искать и исправлять код «с душком», например очень большие классы или дублированный код. Этим антипаттернам следует придавать структуру отдельных модулей. В этой главе мы будем использовать шестеренки в качестве визуальной метафоры для кода на рисунках


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


Рис. 7.2. Некоторые примеры кода «с душком» возникают как следствие громоздкой архитектуры системы и сложного взаимодействия модулей


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

Другой пример кода «с душком» – это неправильная организация взаимодействия отдельных модулей друг с другом. Спагетти-код, или код со сложной и запутанной структурой, – один из самых старых типов кода «с душком», он известен по крайней мере с 1960-х годов. Часто спагетти-код можно распознать по пугающим комментариям других разработчиков, которые ранее безрезультатно пытались распутать его. А другая разновидность – лазанья-код – может оказаться более коварной проблемой. Современная архитектура программного обеспечения, как правило, делит код на слои. Каждый из них имеет определенную цель или выполняет определенную роль, и эти слои составляют общую архитектуру. Однако когда слоев слишком много и шаблоны, по которым их писали, оказались несогласованными, становится трудно понять, что должен делать каждый слой. Эта ситуация может усугубляться протечками между слоями, где код, типы данных или идеи, которые должны находиться в одном слое, просачиваются в соседние.

Хуки, крайние случаи и код, делающий слишком много

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

Приведем пример. Команда будет прогнозировать способ использования модуля кода (например, класса Java) в будущем и добавит некий хук, или заполнитель, который впоследствии будет заменен кодом. Хук кажется «бесплатным», но на самом деле имеет цену: он связывает команду принятым сегодня решением, которое можно было бы отложить на будущее. Когда наконец приходит время для использования хука, команда глубже понимает проблему и он должен быть другим. Команда приходит в замешательство, обнаружив, что ее предположения о том, как будет использован хук, привели к необходимости создать еще одну часть кода, которая будет обходить этот хук. Поэтому его стало гораздо труднее изменить (несмотря на то, что он пуст!) – ведь он уже используется в другом месте кода. Программист, привыкший добавлять слишком много хуков, забывает, где они расположены. Он будет постоянно сталкиваться с неприятностями при попытке использовать код, написанный несколько недель назад. Ведь окажется, что нужный код так и не был написан, а вместо него стоит комментарий со словами «надо сделать».

Это антипаттерн: добавление такого количества хуков, что становится трудно точно отследить, что именно делает код.

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

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

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

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

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


Рис. 7.3. Блестящий веб-комикс xkcd показывает, что происходит, когда разработчики попадают в платформенную ловушку


Рон Джеффрис, партнер Кента Бека по созданию ХР, описал, как избежать платформенной ловушки. «Реализуйте то, в чем вы действительно нуждаетесь в данный момент, и не стремитесь предугадывать, что вам может понадобиться в будущем»[61]. Некоторые XP-команды любят использовать аббревиатуру YAGNI (You Ain’t Gonna Need It – «вам это не понадобится»), если речь заходит о таких ситуациях. Пытаясь предугадать будущие потребности и создавая дополнительный код, чтобы их удовлетворить, вы легко попадаете в платформенную ловушку.

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

Нетрудно понять, почему разработчики идут по этому пути. Они думают так: «Если бы кто-то другой создал платформу для работы, которую я сейчас выполняю, то я бы просто ее применил. Так почему бы не потратить немного времени на решение проблемы в общем виде?» Это очень благородно со стороны разработчиков и объясняет, почему так много команд попадают в платформенную ловушку.

Постойте, а что не так с повторно используемыми платформами?

Все нормально, и, конечно, в XP нет ничего, что исключает использование или разработку таких платформ. Одна из наших наиболее популярных книг Head First CM учит программистов использовать. NET Framework, технологию Microsoft, для создания Windows-приложений. Существуют отличные готовые платформы для разработки веб-приложений, рендеринга 3D-графики, создания сетевых сервисов и т. д.

Это не значит, что у вашего проекта должна быть установка на создание сетевого сервиса.

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