загрузка...

Прагматический подход


Существует ряд подсказок и уловок, применимых ко всем уровням разработки программ: идеи, которые почти аксиоматичны, и процессы, которые практически универсальны. Однако эти подходы редко документируются как таковые; в основном они фиксируются как случайные высказывания в дискуссиях по проектированию, руководству проектами или программированию.
В этой главе эти идеи и процессы сводятся воедино. Первые два раздела, "Пороки дублирования" и «Ортогональность», тесно связаны между собой. Первый предостерегает от дублирования знания в ваших системах, второй – от растаскивания единого фрагмента знания по многим компонентам системы.
Все вокруг меняется очень быстро, и становится все труднее и труднее поддерживать приложения на должном уровне. В разделе «Обратимость» рассматриваются некоторые методики, позволяющие изолировать проекты от изменяющейся окружающей среды.
Следующие два раздела также связаны между собой. В разделе "Стрельба трассирующими" говорится о стиле разработки программ, позволяющем одновременно осуществлять сбор требований, тестировать проектные решения и реализовывать текст программы. Если для вас это звучит слишком хорошо, чтобы быть правдой, то так оно и есть: разработки в стиле "Стрельба трассирующими" применимы не всегда. Для последнего случая в разделе "Прототипы и памятные записки" показано, как при тестировании архитектур, алгоритмов, интерфейсов и идей используются прототипы.
По мере того как информатика становится зрелой наукой, разработчики изобретают языки программирования все более высокого уровня. Поскольку компилятор, работающий по принципу "сделай так, как приказано" еще не изобретен, в разделе "Языки, отражающие специфику предметной области" представлен ряд более скромных предложений, которые можно реализовать для себя.
Ну и наконец, все мы работаем в мире с ограниченным временем и ресурсами. Оба этих недостатка переживаются легче (радуя ваше начальство), если поднатореть в оценке продолжительности какого-либо дела, о чем и говорится в разделе "Оценка".
Держа в голове эти фундаментальные принципы, можно создать программу, которая будет лучше, быстрее и устойчивее. Ее можно даже сделать на вид более простой.
7
Пороки дублирования
Капитан Джеймс Т. Кирк больше всего любил отключать хищный искусственный интеллект, вводя в компьютер два противоречащих друг другу фрагмента знания. К несчастью, этот принцип оказывается столь же эффективным при доведении вашей программы до обморочного состояния.
Программисты собирают, организуют, сопровождают и связывают воедино знание. Знание документируется в требованиях, воплощается в запускаемых программах и используется для контроля в ходе тестирования.
К сожалению, знание нестабильно. Оно изменяется – часто очень быстро. Понимание некоего требования может измениться после встречи с заказчиком. Правительство изменяет административные положения, и некая бизнес-логика устаревает. Тесты могут показать, что выбранный алгоритм не будет работать. Вся эта нестабильность означает, что мы проводим большую часть времени в режиме сопровождения, осуществляя реорганизацию знания и выражая его по-новому в опекаемых нами системах.
Большинство людей полагает, что сопровождение начинается в момент выпуска приложения в свет и означает устранение ошибок и улучшение характеристик. Мы думаем, что эти люди ошибаются. Программисты постоянно находятся в режиме сопровождения. Наше понимание изменяется день ото дня. Новые требования возникают по мере того, как мы проектируем или создаем текст программы. Возможно, изменяется операционная система. Какой бы ни была причина, сопровождение является не дискретным видом деятельности, а рутинной частью процесса разработки в целом.
Когда мы осуществляем сопровождение, нам приходится отыскивать и изменять представления о предметах – капсулах знания, заложенных в приложение. Проблема состоит в том, что тиражировать знание в требованиях, процессах и программах, которые мы разрабатываем, легко, и когда мы поступаем подобным образом, возникает призрак сопровождения – тот самый, который начинает делать свое черное дело задолго до отправки готового приложения заказчику.
Мы полагаем, что единственно надежным способом разработки программ и облегчения их понимания и сопровождения является следование принципу "Не повторяй самого себя" (Далее DRY = Don't Repeat Yourself. – Прим. пер.):
КАЖДЫЙ ФРАГМЕНТ ЗНАНИЯ ДОЛЖЕН ИМЕТЬ ЕДИНСТВЕННОЕ, ОДНОЗНАЧНОЕ, НАДЕЖНОЕ ПРЕДСТАВЛЕНИЕ В СИСТЕМЕ.
Подсказка 11: Не повторяй самого себя
Альтернативой является представление одного и того же предмета в двух или более местах. Если меняется одно, придется вспоминать и об изменении других, или же ваша программа (подобно компьютерам пришельцев) будет поставлена на колени в виду противоречий. Вопрос не в том, вспомните ли вы о необходимом изменении или нет; вопрос в том, когда вы об этом забудете.
Вы обнаружите, что принцип DRY будет время от времени появляться на протяжении всей книги, часто в контексте, который не имеет ничего общего с программированием. Мы полагаем, что этот принцип является одним из наиболее важных инструментов в арсенале программиста-прагматика.
В этом разделе мы обрисуем проблемы, связанные с дублированием, и предложим общие стратегии по тому, как с ним справиться.
Как возникает дублирование?
Большинство наблюдаемых явлений дублирования подпадают под одну из следующих категорий:

Навязанное дублирование.Разработчики чувствуют, что у них нет выбора – им кажется, что дублирования требует среда окружения.

Неумышленное дублирование.Разработчики не осознают, что они тиражируют информацию.

Нетерпеливое дублирование.Разработчики ленятся и осуществляют дублирование, потому что им кажется, что так проще.

Коллективное дублирование.Фрагмент информации тиражируются несколькими членами одной команды разработчиков (или нескольких команд)
Рассмотрим эти четыре категории дублирования более подробно.
Навязанное дублирование
Иногда кажется, что нас заставляют осуществлять дублирование. Стандарты, по которым делается проект, могут потребовать наличия документов, содержащих дублированную информацию, или документов, которые тиражируют информацию в тексте программы. При наличии нескольких целевых платформ каждая из них требует отдельных языков программирования, библиотек и сред разработки, что заставляет нас тиражировать общедоступные определения и процедуры. Сами языки программирования требуют наличия ряда конструкций, которые тиражируют информацию. Все мы находились в ситуациях, когда были не в силах избежать дублирования. И все же зачастую находятся способы сохранения каждого фрагмента знания в одном и том же месте – в соответствии с принципом DRY – и облегчения нашей жизни одновременно. Вот некоторые методики:
Множественные представления информации.На уровне создания текста программы, нам часто необходимо представить одну и ту же информацию в различных формах. Предположим, мы пишем приложение «клиент-сервер» с использованием различных языков для клиента и сервера и должны представить некоторую общедоступную конструкцию и на первом, и на втором. Возможно, нам необходим класс, чьи атрибуты отражают схему таблицы базы данных. Может быть, вы пишете книгу и хотите включить в нее фрагменты программ, которые вы также хотели бы скомпилировать и протестировать.
Немного изобретательности – и дублирование вам не понадобится. Зачастую ответ сводится к написанию простого фильтра или генератора текста программы. Конструкции с использованием нескольких языков можно собрать из обычного представления метаданных, применяя простой генератор текста программ всякий раз при осуществлении сборки программы (пример этого показан на рисунке 3.4). Определения класса могут быть сгенерированы автоматически из интерактивной схемы базы данных или из метаданных, используемых для построения схемы изначально. Фрагменты программ в этой книге вставлялись препроцессором всякий раз при форматировании текста. Уловка состоит в том, чтобы сделать процесс активным: это не может быть однократным преобразованием, в противном случае мы опять окажемся в положении людей, тиражирующих данные.
Документация в тексте программы.Программистов учат комментировать создаваемый ими текст программы: удачный текст программы снабжен большим количеством комментариев. К сожалению, им никогда не объясняли, зачем тексту программы нужны комментарии: неудачному тексту требуется большое количество комментариев.
Принцип DRY говорит о сохранении низкоуровневого знания в тексте программы, частью которого он является, и сохранении комментариев для других, высокоуровневых толкований. В противном случае мы тиражируем знание, и каждое изменение означает изменение и в тексте программы, и в комментариях. Комментарии неизбежно устаревают, а ненадежные комментарии хуже, чем их отсутствие вообще. (Более подробная информация о комментариях содержится в разделе "Все эти сочинения").
Документация и текст программы.Вы пишете документацию, затем создаете текст программы. Что-то меняется, и вы исправляете документацию и обновляете текст. И документация, и текст содержат представления одного и того же знания. И все мы знаем, что в суматохе, когда приближается контрольный срок, а важные заказчики высказывают требования, обновление документации стараются отложить.
Однажды Дэйв Хант работал над переключателем телекса на разные языки. Вполне понятно, что заказчик требовал исчерпывающей тестовой спецификации, а также того, чтобы программы проходили полное тестирование при поставке каждой новой версии. Чтобы убедиться в том, что тесты находились в точном соответствии со спецификацией, команда сгенерировала их автоматически из самого документа. Когда заказчик вносил исправления в спецификацию, автоматически изменялся и тестовый набор программ. Команда убедила заказчика, что, после того как процедура прошла нормально, генерация приемочных тестов длилась лишь несколько секунд.
Языковые аспекты.Многие языки навязывают значительное дублирование в исходном тексте программы. Зачастую это происходит, когда язык отделяет интерфейс модуля от его реализации. Языки С и С++ используют файлы заголовка, которые тиражируют имена и печатают информацию о переменных экспорта, функциях и классах (для С++). Язык Object Pascal даже тиражирует эту информацию в том же самом файле. Если вы используете удаленные вызовы процедур или технологию CORBA[URL 29], то при этом происходит дублирование интерфейсной информации в спецификации интерфейса и тексте программы, его реализующей.
Не существует простой методики, позволяющей преодолеть требования языка. В то время как некоторые среды разработки скрывают потребность в файлах заголовка, генерируя их автоматически, а язык Object Pascal позволяет вам сокращать повторяющиеся объявления функции, в общем случае вы используете то, что вам дано. По крайней мере, для большинства языковых аспектов, файл заголовка, который противоречит реализации, будет генерировать некоторое сообщение об ошибке компиляции или компоновки.
Также стоит подумать о комментариях в файлах заголовка и реализации. В дублировании комментария функции или заголовка класса в этих двух файлах нет абсолютно никакого смысла. Файлы заголовка используются для документирования аспектов интерфейса, а файлы реализации – для документирования некоторых подробностей, которых пользователи вашей программы знать не должны.
Неумышленное дублирование
Иногда дублирование происходит в результате ошибок в проекте.
Рассмотрим пример из области транспорта. Пусть аналитик установил, что, наряду с прочими атрибутами, грузовик имеет тип, номерной знак и водителя. Аналогично, маршрут доставки груза представляет собой сочетание маршрута, грузовика и водителя. Мы создаем программы для некоторых классов, основанных на этом представлении.
Но что происходит, если водитель по имени Салли заболевает и приходится менять водителя? Классы Truck и DeliveryRoute содержат описание водителя. Какой из них мы должны изменить? Ясно, что это дублирование неудачно. Нормализуйте его в соответствии с базовой бизнес-моделью – необходим грузовику водитель как часть базового набора атрибутов? А маршрут? Возможно, необходим третий объект, который связывает воедино водителя, грузовик и маршрут. Каким бы ни было окончательное решение, стоит избегать этого типа ненормализованных данных.
Есть не столь очевидный тип ненормализованных данных, который имеет место при наличии множественных взаимозависимых элементов данных. Рассмотрим класс, представляющий отрезок:
class Line {
public:
Point start;
Point end;
double length:
};
На первый взгляд, этот класс может показаться разумным. Отрезок явно имеет начало и конец и всегда будет иметь длину (даже если она нулевая). Но происходит дублирование. Длина определяется начальной и конечной точками: при изменении одной из точек длина меняется. Лучше сделать длину вычисляемым полем:
class Line {
public:
Point start;
Point end;
double length() {return start.distanceTo(end);}
};
Позже, в ходе разработки, вы можете нарушить принцип "Не повторяй самого себя" в силу требований к производительности. Зачастую это происходит, когда вам необходимо кэшировать данные во избежание повторения дорогостоящих операций. Эта уловка призвана ограничить воздействие. Нарушение принципа не подвержено воздействию внешнего мира: лишь методы в пределах класса должны поддерживаться в надлежащем состоянии.
class Line {
private:
bool changed;
double length;
Point start;
Point end;
public:
void setStart(Point p) {start = p; changed = true;}
void setEnd(Point p) {end = p; changed = true;}
Point getStart(void) {return start;}
Point getEnd(void) {return end;}
double getLength() {
if (changed) {
length = start.distanceTo(end);
changed = false;
}
return length;
}
};
Этот пример также иллюстрирует важный аспект для объектно-ориентированных языков типа Java и С++. Там, где это возможно, всегда используются функции средства доступа – для чтения и записи атрибутов объектов
[6]. Это облегчает добавление функциональных возможностей (типа кэширования) в будущем.
Нетерпеливое дублирование
Каждый проект испытывает давление времени – силы, которая может двигать лучшими из нас, заставляя идти напролом. Вам нужна подпрограмма, подобная уже написанной вами? Вас соблазнит возможность копирования и внесения лишь нескольких изменений? Вам нужно значение, чтобы представить максимальное число точек? Если я изменю файл заголовка, целый проект должен быть перестроен. Может, мне просто использовать константы в этом месте?… и в этом… и в том… Нужен класс, подобный тому, который есть в системе поддержки Java? У вас в распоряжении имеется исходный текст, так почему бы просто его не скопировать и не внести необходимые изменения (несмотря на лицензионное соглашение)?
Если вы чувствуете, что поддаетесь искушению, вспомните банальный афоризм: "Тише едешь – дальше будешь". Экономя несколько секунд в данный момент, вы потенциально теряете целые часы. Подумайте об аспектах, относящихся к "проблеме 2000 года". Многие из них были вызваны ленью разработчиков, которые не сделали параметризацию размера полей даты (или не внедрили централизованные библиотеки служб доступа к дате).
Нетерпеливое дублирование легко обнаруживается и устраняется, но это требует дисциплины и желания потратить время в настоящий момент, чтобы избежать головной боли впоследствии.
Коллективное дублирование
Самый трудный в обнаружении и обработке тип дублирования – коллективный – возникает между различными разработчиками проекта. Целые наборы функциональных возможностей могут тиражироваться по неосторожности, и это дублирование может оставаться незамеченным на протяжении многих лет, что приводит к возникновению проблем при сопровождении. Нам известно, как в одном из штатов США компьютерные системы, установленные в правительственных учреждениях, проверялись на наличие "проблемы 2000 года". Аудиторы обнаружили свыше 10000 программ, каждая из которых по-своему осуществляла проверку правильности номера карточки социального страхования.
На высоком уровне с проблемой можно справиться при наличии ясного проектного решения, сильного технического руководителя проекта (см. 'Команды прагматиков") и разделения обязанностей в пределах проекта. Однако на уровне модуля проблема является более коварной. Обычно необходимые функциональные возможности или данные, не относящиеся к очевидной области ответственности, могут реализовываться много раз.
Мы полагаем, что лучший способ справиться с этим – поощрять активное и частое взаимодействие между разработчиками. Устраивайте форумы для обсуждения общих проблем. (При работе над предыдущими проектами мы организовывали конференции в сети, чтобы позволить разработчикам обмениваться идеями и задавать вопросы. Этим обеспечивается ненавязчивый способ общения – даже на нескольких сайтах – при сохранении непрерывной хронологии всего высказанного). Назначьте одного из членов команды библиотекарем проекта, чьей обязанностью будет обеспечение обмена знаниями. Организуйте специальное место в каталоге с исходными текстами, в котором будут сохраняться сервисные подпрограммы и скрипты. Обратите особое внимание на чтение исходного текста и документации других членов команды, неформально или при анализе текста программы.
При этом вы отнюдь не шпионите за ними – вы учитесь у них. И помните, что доступ к тексту программы осуществляется по взаимной договоренности – вас не должно коробить, если и другие члены команды сосредоточенно изучают (или вынюхивают?) ваш текст программы.
Подсказка 12: Сделайте так, чтобы программу можно было легко использовать повторно
Все, что вы пытаетесь делать, способствует развитию среды, где проще находить и многократно использовать существующий материал, чем создавать его самому. Но если это непросто, люди не станут это делать. И если вы будете не в состоянии многократно использовать этот материал, вы рискуете заняться дублированием знания.
Другие разделы, относящиеся к данной теме:
• Ортогональность
• Работа с текстом
• Генераторы исходных текстов
• Реорганизация
• Команды прагматиков
• Вездесущая автоматизация
• Все эти сочинения
8
Ортогональность
Ортогональность очень важна, если вы хотите создавать системы, которые легко поддаются проектированию, сборке, тестированию и расширению. Однако этому принципу редко обучают непосредственно. Часто он является лишь скрытым достоинством других разнообразных методик, которые вы изучаете. Это неправильно. Как только вы научитесь непосредственно применять принципы ортогональности, вы сразу заметите, как улучшилось качество создаваемых вами систем.
Что такое ортогональность?
Термин «ортогональность» заимствован из геометрии. Две линии являются ортогональными, если они пересекаются под прямым углом, например, оси координат на графике. В терминах векторной алгебры две такие линии являются независимыми. Если двигаться вдоль одной из линий, то проекция движущейся точки на другую линию не меняется.
Этот термин был введен в информатике для обозначения некой разновидности независимости или несвязанности. Два или более объекта ортогональны, если изменения, вносимые в один из них, не влияют на любой другой. В грамотно спроектированной системе программа базы данных будет ортогональной к интерфейсу пользователя: вы можете менять интерфейс пользователя без воздействия на базу данных и менять местами базы данных, не меняя интерфейса.
Перед тем как рассмотреть преимущества ортогональных систем, познакомимся с неортогональной системой.
Неортогонольноя система
Предположим, вы находитесь в экскурсионном вертолете, совершающем полет над Гранд-Каньоном, когда пилот, который совершил ошибку, наевшись рыбы за обедом, внезапно вскрикивает и теряет сознание. По счастливой случайности это происходит, когда вы парите на высоте 30 метров. Вы догадываетесь, что рычаг управления общим шагом несущего винта
[7]обеспечивает подъем машины, так что, если его слегка опустить, вертолет начнет плавно снижаться. Однако когда вы пытаетесь сделать это, то осознаете, что жизнь – не такая уж простая штука. Вертолет клюет носом, и вас начинает вращать по спирали влево. Внезапно вы понимаете, что управляете системой, в которой каждое воздействие имеет побочные эффекты. При нажатии на левый рычаг вам придется сделать уравновешивающее движение назад правым рычагом и нажать на правую педаль. Но при этом каждое из этих действий вновь повлияет на все органы управления. Неожиданно вам приходится жонглировать невероятно сложной системой, в которой любое изменение влияет на все остальные управляющие воздействия. Вы испытываете феноменальную нагрузку: ваши руки и ноги находятся в постоянном движении, пытаясь уравновесить все взаимодействующие силы.
Органы управления вертолетом определенно не являются ортогональными.
Преимущества ортогональности
Как показывает пример с вертолетом, неортогональные системы сложнее изменять и контролировать. Если составляющие системы отличаются высокой степенью взаимозависимости, то невозможно устранить какую-либо неисправность лишь на локальном уровне.
Подсказка 13: Исключайте взаимодействие между объектами, не относящимися друг к другу
Мы хотим спроектировать компоненты, которые являются самодостаточными: независимыми, с единственным, четким назначением; в книге Йордона и Константина [YC86] это явление называется сцеплением (cohesion). Когда компоненты изолированы друг от друга, вы уверены, что можно изменить один из них. не заботясь об остальных. Пока внешние интерфейсы этого компонента остаются неизменными, вы можете быть спокойны, что не создадите проблем, которые распространятся по всей системе.
С созданием ортогональных систем у вас появятся два больших преимущества: увеличение производительности и снижение риска.
Увеличение производительности
• Изменения в системе локализуются, поэтому периоды разработки и тестирования сократятся. Легче написать относительно небольшие, самодостаточные компоненты, чем один большой программный модуль. Простые компоненты могут быть спроектированы, запрограммированы, протестированы и затем забыты – не нужно непрерывно менять существующий текст по мере того, как к нему добавляются новые фрагменты.
• Ортогональный подход также способствует многократному использованию компонентов. Если компоненты имеют определенную, четкую сферу ответственности, они могут комбинироваться с новыми компонентами способами, которые не предполагались при их первоначальной реализации. Чем меньше связанность в системах, тем легче их перенастроить и провести их обратное проектирование.
• При комбинировании ортогональных компонентов происходит едва заметное увеличение производительности. Предположим, что один компонент способен осуществлять AJ, а второй – N различных операций. Если эти компоненты ортогональны и комбинируются, то в сумме они способны осуществить М х N различных операций. Но если два компонента не являются ортогональными, то они будут перекрываться и результат их действия будет меньшим по сравнению с ортогональными компонентами. Вы получаете большее количество функциональных возможностей в пересчете на единичное усилие, если комбинируете между собой ортогональные компоненты.
Снижение риска
Ортогональный подход приводит к снижению уровня риска, присущего любой разработке.
• Ошибочные фрагменты текста программы изолируются. Если модуль содержит ошибку, то вероятность ее распространения на всю систему уменьшается. Кроме того, ошибочный фрагмент может быть извлечен и заменен новым (исправленным).
• Конечный продукт (система) становится менее хрупким. Проблемы, появляющиеся при внесении небольших изменений и устранении недочетов на определенном участке, не проходят дальше этого участка.
• Ортогональная система способствует повышению качества тестирования, поскольку облегчается проектирование и тестирование отдельных ее компонентов.
• Вы не будете слишком сильно привязаны к определенному субподрядчику, программному продукту или платформе, поскольку интерфейсы между компонентами, производимыми фирмами-субподрядчиками, не будут играть главенствующей роли в проекте.
Рассмотрим некоторые из способов, при помощи которых вы сможете внедрить принцип ортогональности в вашу работу.
Проектные группы
Приходилось ли вам замечать, насколько эффективно работают проектные команды, все члены которых знают, что делать, и полностью отдают себя делу, тогда как в других командах сотрудники постоянно препираются между собой и не собираются ни в чем уступать друг другу?
Зачастую это не что иное, как проблема ортогональности. Если команды организованы с большим числом перекрытий, то сотрудники путают свои должностные обязанности. Для любого изменения необходимо собирать всю команду, поскольку оно, может быть, затронет каждого.
Как разбить команду на группы с четкими обязанностями и минимальным перекрытием? На этот вопрос нет простого ответа. В некоторой степени это зависит от проекта и вашего анализа областей, которые в перспективе могут измениться. Это также зависит от людей, находящихся в вашем распоряжении. Мы предпочитаем отделять инфраструктуру от приложения. Каждому из основных инфраструктурных компонентов (база данных, интерфейс связи, промежуточное программное обеспечение и т. д.) приписывается только ему принадлежащая группа. Подобным образом производится и разделение функциональных возможностей приложения. После этого мы изучаем людей, которые имеются в нашем распоряжении на данный момент (или планируем их появление в будущем), и сообразно этому корректируем состав групп.
Вы можете неформально определить уровень ортогональности структуры проектной команды. Для этого просто посмотрите, скольких людей необходимо привлечь к обсуждению каждого изменения, требуемого со стороны. Чем больше эта цифра, тем ниже уровень ортогональности группы. Отсюда ясно, что ортогональная команда работает более эффективно. (Высказав это, мы тем самым поощряем стремление сотрудников более мелких подразделений постоянно общаться друг с другом.)
Проектирование
Большинство разработчиков знакомо с потребностью в проектировании ортогональных систем, хотя они наверняка используют термины «модульный», "компонентно-ориентированный" и «многоуровневый» для описания конкретного процесса. Системы должны быть скомпонованы из набора взаимодействующих модулей, каждый из который реализует функциональные возможности независимо от других. Иногда эти компоненты объединены в уровни, каждый из которых обеспечивает некий уровень абстракции. Данный многоуровневый подход является мощным методом проектирования ортогональных систем. Поскольку на каждом уровне используются только абстракции, обеспеченные на низших уровнях, можно легко изменить основные реализации, не затрагивая самой программы. Иерархическое представление также уменьшает риск появления неконтролируемых зависимостей между модулями. Иерархическое представление часто показываются с помощью диаграмм, как на рисунке 2.1.
Рис. 2.1. Типичная диаграмма иерархической структуры
Существует простой тест на ортогональность проектирования. Как только вы составили схему компонентов, спросите себя: "Сколько модулей подвергнутся воздействию, если я резко изменю требования по конкретной функции?" В ортогональной системе ответ должен быть «один»
[8]. Перемещение кнопки на панели графического интерфейса пользователя не должно требовать внесения изменений в схему базы данных. Добавление контекстно-зависимой справки не должно изменить подсистему выставления счетов.
Рассмотрим сложную систему контроля и управления отопительной установкой. Первоначально требовалось наличие графического интерфейса, но затем требования были изменены, с тем чтобы добавить систему речевого ответа и управления установкой при помощи телефона с тональным набором. В ортогонально спроектированной системе для этого вам пришлось бы изменить только модули, связанные с интерфейсом пользователя, а основная логика управления предприятием остается неизменной. На самом деле, если вы тщательно структурируете систему, то у вас должна быть возможность поддержки обоих интерфейсов при наличии одной и той же программной базы. В разделе "Всего лишь представление" говорится о написании программ, в которых отсутствует связанность, используя парадигму "модель-представление-контроллер" (Model-View-Controller), подходящую в данной ситуации.
Стоит спросить себя, как защитить вашу конструкцию от изменений в окружающем мире. Например, вы пользуетесь номером телефона в качестве идентификатора заказчика. Что произойдет, если телефонная станция изменит коды междугородной связи? Не полагайтесь на свойства предметов, которыми не можете управлять.
Инструментарии и библиотеки
Будьте внимательным, чтобы сохранить ортогональность вашей системы при введении инструментариев и библиотек, произведенных фирмами-субподрядчиками. Проявите мудрость при выборе технологии.
Однажды авторы работали над проектом, в котором требовалось, чтобы некий фрагмент программы на языке Java выполнялся автономно – на сервере и в удаленном режиме – на клиентской машине. В этом случае возможными вариантами распределения классов были технологии RMI и CORBA. Если удаленный доступ к классу обеспечивался при помощи RMI, то в этом случае каждое обращение к удаленному методу в этом классе могло бы привести к генерации исключения, означающей, что эта наивная реализация потребовала бы от нас обработки этого исключения всякий раз при использовании удаленных классов. В данном случае использование RMI явно не ортогонально: программа, обращающаяся к удаленным классам, не должна зависеть от их физического расположения. Альтернативный способ – технология CORBA – не налагает подобного ограничения: мы можем написать программу, для которой не имеет значения, где физически находятся классы.
Когда вы используете инструментарий (или даже библиотеку, созданную другими разработчиками), вначале спросите себя, не заставит ли он внести в вашу программу изменения, которых там быть не должно. Если схема долговременного хранения объекта прозрачна, то она ортогональна. Если же при этом требуется создание объектов или обращение к ним каким-либо особым образом, то она неортогональна. Отделение этих подробностей от вашей программы дает дополнительное преимущество, связанное с возможностью смены субподрядчиков в будущем.
Интересным примером ортогональности является система Enterprise Java Beans (EJB). В большинстве диалоговых систем обработки запросов прикладная программа должна обозначать начало и окончание каждой транзакции. В системе EJB эта информация выражена описательно в виде метаданных вне любых программ. Та же самая прикладная программа может работать в различных транзакционных средах EJB без каких-либо изменений. Вероятно, это станет прообразом многих операционных сред будущего.
Другой интересной проверкой на ортогональность является технология Aspect-Oriented Programming (АОР) – исследовательский проект фирмы Xerox Pare ([KLM+97] и [URL 49]). Технология АОР позволяет выразить в одном-единственном месте линию поведения, которая в противном случае была бы распределена по всему исходному тексту программы. Например, журнальные сообщения обычно генерируются путем явных обращений к некоторой функции записи в журнал по всему исходному тексту. Используя технологию АОР, вы реализуете процедуру записи в журнал ортогонально к записываемым данным. Используя версию АОР для языка Java можно записать сообщение журнала при входе в любой метод класса Fred, запрограммировав аспект:
aspect Trace {
advise * Fred.*(…) {
static before {
Log.write("-» Entering " + thisJoinPoint.methodName);
}
}
}
При вплетении этого аспекта в текст вашей программы будут генерироваться трассировочные сообщения. Если этого не сделать, не будет и сообщений. В обоих случаях исходный текст остается неизменным.
Написание текста программы
Всякий раз, когда вы пишете программу, вы подвергаетесь риску снижения уровня ортогональности вашего приложения. Если вы постоянно не отслеживаете не только то, что вы делаете, но и весь контекст приложения, то существует опасность неумышленного дублирования функциональных возможностей в некотором другом модуле или выражения существующих знаний дважды.
Есть ряд методик, которые можно использовать для поддержки ортогональности:

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

Избегайте глобальных данных.Всякий раз, когда ваша программа ссылается на глобальные данные, она привязывается к другим компонентам, использующим эти данные. Даже глобальные переменные, которые вы собираетесь использовать только для чтения, могут вызвать проблемы (например, если вам необходимо срочно изменить программу, сделав ее многопоточной). Вообще программа станет проще в понимании и сопровождении, если вы явно перешлете любой требуемый контекст в ваши модули. В объектно-ориентированных приложениях контекст часто пересылается как параметр к конструкторам объектов. В другой программе вы можете создать конструкции, содержащие контекст, и обходить ссылки на них.
Шаблон Singleton, упомянутый в книге "Design Patterns" [GHJV95], представляет собой способ подтвердить существование единственного представителя объекта определенного класса. Многие используют эти объекты типа Singleton как своего рода глобальную переменную (особенно при работе с языками типа Java, которые иначе не поддерживают технологию глобальных переменных). Будьте внимательны с шаблонами Singleton – они также могут приводить к ненужному связыванию.

Подобные функции.Зачастую вы сталкиваетесь с набором функций, похожих друг на друга; возможно, они используют общий фрагмент в начале и конце программы, но в ее середине каждая пользуется своим алгоритмом. Дублированная программа является признаком структурных проблем. Для того чтобы составить программу лучше, следует обратить внимание на шаблон Strategy в книге "Design Patterns".
Пусть постоянное критическое отношение к вашей программе войдет у вас в привычку. Ищите любые возможности реорганизации для усовершенствования ее конструкции и повышения уровня ортогональности. Этот процесс называется реорганизацией, и он важен настолько, что в книге ему посвящен целый раздел (см. "Реорганизация").
<< | >>
Источник: Эндрю Хант. Программист-прагматик. Путь от подмастерья к мастеру. 2004

Еще по теме Прагматический подход:

  1. Прагматическая мораль
  2. Прагматическая философия
  3. Прагматические проекты
  4. Прагматическая паранойя
  5. ГЛАВА 6. СРАВНИТЕЛЬНЫЙ ПОДХОД К ОЦЕНКЕ ТЕХНИЧЕСКИХ ОБЪЕКТОВ. МЕТОДЫ РЕАЛИЗАЦИИ СРАВНИТЕЛЬНОГО ПОДХОДА
  6. ГЛАВА 7. ДОХОДНЫЙ ПОДХОД. МЕТОДЫ ДОХОДНОГО ПОДХОДА В ОЦЕНКЕ ТЕХНИЧЕСКИХ СРЕДСТВ
  7. ПОДХОД
  8. 4.2 Затратный подход
  9. 5.2. Сравнительный подход
  10. 4.3 Доходный подход
  11. 5.4. Затратный подход
  12. 5.3 Сравнительный подход
  13. 5.6. Доходный подход
  14. 5.3. Затратный подход
  15. 9.5. Сравнение методологических подходов
  16. ТЕМА 5. Основные подходы к оценке
  17. 5.1. Доходный подход
  18. ПОДХОДЫ К СОЗДАНИЮ РЕКЛАМЫ