•
Следуя этим ценностям, мы должны:
• сформировать стратегию проектирования, в результате использования которой формируется простой дизайн;
• найти быстрый способ убедиться в том, что дизайн качественный;
• организовать обратную связь для того, чтобы быстро воплощать наши новые открытия и выводы в дизайне системы;
• сжать цикл времени, в течение которого выполняется весь этот процесс, и сделать его как можно короче.
Принятые нами ранее принципы также хорошо воплощаются в стратегии дизайна.
•
•
•
•
ХР работает против многих программистских инстинктов. Мы, программисты, привыкли ожидать появления проблем. Если проблемы откладываются на более позднее время, мы счастливы. Если проблемы не появляются, мы не обращаем на это внимания. Поэтому наша стратегия проектирования должна увести нас в сторону от этих размышлений о будущем. К счастью, большинство разработчиков способно отучится от этой привычки брать неприятности взаймы (как про это говорила моя бабушка). К сожалению, чем вы умнее, тем сложнее вам отучиться от этого.
Еще один способ взглянуть на это предлагает заданный себе вопрос:
Эта стратегия работает в случае, если между сегодня и завтра ничего не меняется. Если вы точно знаете, что будет завтра, и вы точно знаете, как с этим справиться в большинстве случаев, сегодня вы должны добавить в систему то, что вам нужно сейчас, а также то, что вам потребуется завтра.
Проблема, связанная с этой стратегией, – это неопределенность.
На практике:
• иногда завтра не наступает никогда (то есть возможность, которую вы спроектировали заранее, больше не интересует заказчика);
• иногда вы придумываете лучший способ перехода от сегодня к завтра.
В любом случае, вы должны выбрать между затратами, необходимыми для того, чтобы убрать из системы ненужный дизайн, и затратами, необходимыми для того, чтобы продолжать разработку, имея на руках сложный дизайн, который не приносит вам пользы.
Я ничего не имею против изменений, вносимых заказчиком в план работ. Я также ничего не имею против того, чтобы со временем менять реализацию той или иной части системы в лучшую сторону. В этом случае картинку, изображенную на рис. 8, следует изменить. Мы должны проектировать систему так, чтобы сегодня решать те проблемы, которые стоят перед нами сегодня, и откладывать на завтра решение тех проблем, которые будут стоять перед нами завтра (рис. 9).
Это ведет нас к созданию следующей стратегии проектирования:
1. Вначале разрабатывается тест, благодаря чему у нас появляется возможность определить момент завершения работы. Для того чтобы просто написать тест, мы опять же должны выполнить некоторый объем проектирования: мы должны определить набор объектов, с которыми мы работаем, а также набор видимых методов для этих объектов.
2. Мы проектируем и реализуем только для того, чтобы обеспечить срабатывание тестов. Все только что разработанные нами тесты, а также все тесты, которые были разработаны ранее, должны сработать – это единственная цель, которую мы преследуем в процессе проектирования.
3. Повторяем.
4. Если мы видим возможность упростить наш дизайн, мы немедленно делаем это. Основные принципы, позволяющие нам определить степень простоты дизайна, рассматриваются в разделе:
Эта стратегия может показаться смехотворно простой. И действительно, она очень проста. Но она не смехотворна. Используя данную стратегию, вы можете создавать большие сложные системы. Однако это непросто. Ничего нет сложнее, чем работать в рамках строгих ограничений по времени и при этом всегда находить время чистить код.
Проектируя в данном стиле, при решении некоторой задачи вы реализуете необходимый код самым простым возможным способом. Когда вы используете этот код повторно, вы делаете его более универсальным. При первом использовании код делает только то, что требуется. При повторном использовании код делается более гибким. При таком подходе вы никогда не платите за гибкость, которую вы не используете, кроме того, система имеет тенденцию становиться гибкой тогда, когда она должна становиться гибкой для третьей, четвертой и пятой вариаций.
Если попробовать реализовать эту стратегию на практике, поначалу она покажется вам странной. Мы берем первый тестовый случай. Мы говорим:
После этого мы берем второй тестовый случай. Мы можем попытаться решить задачу, используя то, что есть у нас на руках, однако вместо этого, возможно, будет удобнее преобразовать существующий объект, разбив его на два разных объекта. В этом случае для обеспечения срабатывания тестового случая необходимо заменить один из полученных объектов. Поэтому прежде, чем продолжать работу, мы выполняем реструктуризацию нашей программы, затем мы проверяем, срабатывает ли наш первый тестовый случай, затем мы добиваемся срабатывания второго тестового случая.
После пары дней работы в таком режиме система становится достаточно большой, и мы уже