WWW.LIBRUS.DOBROTA.BIZ
БЕСПЛАТНАЯ  ИНТЕРНЕТ  БИБЛИОТЕКА - собрание публикаций
 

Pages:     | 1 | 2 || 4 | 5 |

«Мартина ФаУflера Предметно-ориентированное П оекти ОБ иие еТРУКТУРИ3АЦИЯ елО жныIx ПРО rPAMMHbIX СИ еТЕМ Domain -Driven Design TACKLING COMPLEXITY IN ТНЕ HEART OFSOFTWARE Eric Evans Addison-Wesley ...»

-- [ Страница 3 ] --

И последнее, но не по значимости: тако й интерфейс легче тестировать, поскольку • модель предлагает явный способ для определения входных данных генератора, ЧАСТЬ 1 11. УГЛУБЛЯЮЩИЙ Р ЕФАКТОРИНГ который одновременно является U способом nроверки его выходных данных. Дру­ гими словами, та же самая СПЕЦИФИКАЦИЯ, которая передается в интерфейс ге­ нератора для накладывания ограничени й на процесс генерирования данных, мо­ жет затем использоваться в своей проверочно й роли (если это поддерживается в программной реализации) для подтверждения правильности создания объекта .

( Э то пример шаблона УТВЕРЖДЕ Н ИЕ, или ASSERTION, которы й рассматривается в главе 1 0.) Создание по заказу может означать генерирование объекта " с нуля ", но это может быть и переконфигурирование уже существующих объектов для подгонки под СПЕЦИФИКА ЦИЮ .

Пример

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

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

–  –  –

Можно было бы начать с написания процедуры, которая брала бы химикат и помеща­ ла его в контей нер, но давай те начнем с задачи проверки. Э то побудит нас формулиро­ вать все правила явно и даст возможность протестировать фИНaJIЬНУIО реализаЦИIО .

Каждый химикат будет иметь СПЕЦИФИКА ЦИЮ необходимого для него контей нера .

–  –  –

Например, СПЕЦИФИКАЦИЯ, приложенная к взрывоопасному химикату, будет проверять сво йство "усиленны й" (ARМORED) .

pub l i c c l a s s Cont ainerSpec i f i ca t i on { priva t e Cont ainerFeature requi redFeature ;

–  –  –

Но это не та программа, KOTOPYIO нам заказывали. Владельцам склада полезно знать и о такой возможности, но все-таки на нас возложили разработку программы-организатора .

у нас же пока есть только тест для такого организатора. Наше понимание предметно й об­ ласти и модели, основанно й на СПЕЦИФИКАЦИЯХ, дает нам возможность определить чет­ кий и простой интерфейс для СЛУЖБЫ, которая будет принимать коллекции Бочек (Drums) и Контейнеров и помеlцать их на склад в соответствии с правилами хранения .

interface Warehouse Packer { public pub l i c voi d pack { Co l l e c t i on cont ainersToFi l l, Col le c t ion drumsToPac k ) throws NoAnswerFoundExcept i on i

–  –  –

Теперь задача проектирования такого модуля-реluателя для задачи оптимизации с наложенными ограничениями, которы й БыI реализовал функции службы СICJIадиров ­ щика (Packer), отделена от остальной части программы, и эти механизмы не будут загро­ мождать ту часть архитектуры, которая непосредственно выражает модель. (См. о деклара­ ТИВIIОМ стиле проектирования архитектуры в главе 10, а о с вязных механизмах в гла­ ве 15.) Тем не менее правила, регламентирующие складирование, не извлечены из объектов предметно й области .

Пример Рабочий прототип организатора складирования I-Iаписать алгоритм оптимизации ДЛЯ программы-организатора складирования не так­ то просто .





Для этой цели выделена небольшая группа программистов и специалистов по складскому хранению, но они еlце даже не начали писать код. Между тем другая небольшая группа разрабатывает приложение, с помощью которого пользователи смогут извлекать инвентарную опись из базы данных, отправлять ее в СЮIаДИРОВЩИI (Packer) и интерпре­ тировать результаты. Они пытаются подстроить архитектуру под о)кидаемый СЮIадиров ­ щик, но все, что у них получается, - это воспроизвести дубликат интерфейса пользователя и написать кое-какой код для интеграции с базой данных. Они не могут предъявить поль­ зователям полноценный рабочи й интерфейс, чтобы получить от них обратную связь. По той же причине разработчики СЮIадировщика также работают в вакууме .

Имея в своем распоряжении объекты предметно й области и интерфейс СЛУЖБЫ, группа разработки приложения вдруг осознает, что могла бы написать упрощенную вер­ сию Складировщика, которая помогла бы продвинуть вперед параллельные процессы разработки и наладить обраТНУIО связь. Конечно, полноценно все заработает только в за­ конченной и собранной воедино системе .

c l a s s Cont ainer { public private doubl e capac itY i private S e t content s i // ( Drums ) Бочки

–  –  –

ЧАСТЬ 1 1 1. УГЛУБЛЯЮЩИЙ Р ЕФАКТОРИНГ Этот код, конечно, оставляет желать много лучшего .

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

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

Имея этот прототип, разработчики клиентского приложения могут двигаться дальше на полной скорости, включая и интеграцию с внешними системами. Группа разработчиков СICJIадировщика (Packer) также получила обратную связь со специалистами, которые ра­ ботают с прототипом и четче формулируют свои идеи, помогая прояснить требования и приоритеты. Эта группа решает доработать прототип для проверки собственных идей .

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

Как только будет готов главный, сложны й С IJIадировщик, интеграция не составит никакого труда, поскольку он был написан для хорошо знакомого интерфейса - тот са­ мый интерфе йс с теми самыми П РОВЕРКАМИ, для которого писалось клиентское прило­ жение, взаимоде й ствовавшее с прототипом .

Преодоление " мертвых точек " с помощью прототипов Одна ['руппа должна ожидать, пока вторая напишет рабочий код, чтобы двигаться дальше .

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

В такого рода "мертвых точках" часто можно "сдвинуться с места", написав прототип ключевого компонента на основе предметной.модели, пусть даже он и не удовлетворяет всем функциональным требованиям. Когда реали­ по проекту зация независима от интерфейса, тогда можно гибко распараллелить работы дальше, имея всего ЛИIПЬ какую-нибудь, более-менее работаIОЩУЮ реализацию и двигаться (прототип). Когда придет время, этот прототип можно будет заменить более эффективной реализацией. Между тем все остальные части системы получат на время разработки некий заменитель смежного компонента, с которым они смогут взаимодействовать .

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

Итак, здесь мы видим пример использования " простейшего возможного решения, кото­ рое работает ". Это стало возможным благодаря наличию достаточно сложной модели. Что­ бы получить функционирующий прототип очень сложного компонента, бывает достаточно написать два-три десятка строк легко понятного кода. При подходе, в меньшей степени ориентированном на модель, все это было бы менее понятно, менее удобно в доработке (поскольку Складировщик был бы теснее привязан к остальной архитектуре), и в данном случае потребовало бы гораздо большего времени на разработку рабочего прототипа .

–  –  –

К онечная цель существования программ - служить их пользователям. Н о прежде те же самые программы должны послужить их разработчикам. Особенно это верно для технологи й разработки, в которых важное место занимает рефакторинг. В ходе ЭВОЛIОЦИИ програМl'JlЫ разработчики реоргаНИЗУIОТ и переписываIОТ каждую ее часть. О ни интеГРИРУIОТ объекты предметной области как с приложениями, так и с новыми объек­ тами предметно й области. Да)I{е многие годы спустя программисты-доработчики изме­ НЯIОТ и дописываIОТ код. Л ЮДЯl'Yl приходится это делать. Но захотят ли они?

Если программное обеспечение, ВЫПОЛНЯЮlцее сложные операции, не имеет хороше й архитектуры, его элементы трудно поддаIОТСЯ расчленению или СЛИЯНИIО в ходе рефак­ торинга. Как только програМlVIИСТ теряет уверенность в том, что он MO)I{eT предсказать все последствия то й или ино й операции, начинается дублирование кода. Если элементы архитектуры МОНОЛИТНЫ и отдельные их части нельзя перекомбинировать в новое целое, ТОl да дублирование становится неизбе)I{НЫМ. Классы и методы MO)I{HO разбить на части ДЛЯ ЛУ'lппей переНОСИl'YI0СТИ в новы й КОД, но тогда стано вится тяжело уследить за тем, что делают разные мелкие их части. Когда у программы нет четко й архитектуры, программи­ сты боятся даже заглядывать в хаотическое " месиво " ее кода, не говоря уже о том, чтобы ВI-IUСИТЬ изменения, которые могли бы усугубить путаницу или что-нибудь испортить из­ за наличия непредвиденнuй связи. В Лlобой системе, за ИСКЛIочением самых примитив­ ных, подобная уязвимость задает " потолок " сложнuсти операционных алгоритмов, которые можно в это й системе реализовать. Рефакторинг и итерационное усовершенствова­ ние в тако й системе невозможны .

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

Гибкая архитектура (sиррlе design) - это логическое дополнение к углубленному мо­ делированию. Как только вы " раскопали " неявные понятия и концепции, а потом пере­ вели их в явные, перед вами оказывается " сырье ". Серией итераци й вы " выковываете" из этого " сырья " нечто полезное, одновременно формируя модель, которая просто и четко выражает ключевые цели и задачи проекта, и выстраивая архитектуру, которая позволит разработчику клиентской части приложения включить эту модель в реальную работу .

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

В о имя гибкости архитектуры в программах было нагромождено множество ненуж­ ных конструкци й. Л ишние уровни абстрагирования и косвенных ссылок чаще мешают, чем помогают в этом деле. Посмотрите на архитектуру, которая де й ствительно вдохнов­ ляет программистов, занимающихся ее доработкой, - и вы увидите, как правило, что­ нибудь очень простое. Н о простое - не значит легкое в исполнении. Чтобы создать такие элементы, которые можно собрать в сложные системы и при этом нетрудно понять, необ­ ходимо сочетать " преданность " ПРОЕКТИРОВАНИЮ ПО МОДЕЛИ (MODEL-DRIVEN DESIGN) с достаточно строгим стилем архитектуры. Определенны й навык проектирования н ужен не только для создания чего-либо, но даже для использования готового .

Разработчики программ играIОТ две роли, и в обеих им должна помогать архитектура .

Один и тот же человек вполне может играть обе роли - даже переЮIIочаться с одной на другую через каждые несколько минут - но, тем не менее, его отношение к коду в этих ро­ лях отличается. Одна из роле й - это разработчик клиентско й части приложения, который вплетает объекты предметно й области в код прикладных операци й или другой код того же уровня предметной области, пользуясь возможностями архитектуры. Гибкая архитектура выражает углубленную модель, лежащую в ее основе, и раскрывает ее потенциал. Разра­ ботчик клиентского кода может гибко использовать минимальный набор слабо зависимых между собой понятий для того, чтобы выразить широки й диапазон рабочих сценариев, реа­ лизующихся в предметной области. Элементы архитектуры сочетаются друг с другом есте­ ственным образом и в итоге выдаIОТ результат надежный, легко предсказуемый, четко ха­ рактеризуемый .

Н о в равной степени архитектура должна служить и разработчику, занимаlощемуся ее доработкой. Чтобы демонстрировать открытость к изменениям, архитектура должна быть легко понятно й и выражать ту же самую модель, на KOTOPYIO опирается разработ­ чик клиентского кода. О на должна следовать очертаниям углубленной модели предмет­ ной области, чтобы большинство изменений " гнули " архитектуру только в тех местах, где она поддается изгибу. В лияние той или иной части кода должно быть очевидным, а по­ следствия изменений соответственно легко предсказуемыми .

Ранние версии программно й архитектуры обычно не обладаIОТ нужной гибкостью .

Многие так и не достигаIОТ этого состояния из-за временных или бlоджетных ограниче­ ни й проекта. Я никогда не видел большой программы, которая бы обладала этим качест­ вом в полной мере. Но когда главным препятствием на пути продвижения проекта являЧАСТЬ 111. УГЛУБЛЯЮЩИЙ РЕФАКТОРИНГ ется сложность, " перековка " самых сложных и критических частей программы в гибкую архитектуру сразу показывает разницу между топким болотом доработки устаревшего кода и решительным прорывом потолка сложности .

Стандартных формул для проектирования такого программного обеспечения не су­ ществует. Но тем не менее я подобрал ряд архитектурных шаблонов, которые, по моему опыту, придают архитектуре гибкость в тех случаях, где их применение уместно. Эти шаблоны и примеры должны давать общее понятие о том, что такое гибкая архитектура и какое мышление нужно для ее построения .

–  –  –

Рис. 10. 1. Некоторые архитектурные шаблоны, помогающие построить гибкую архитектуру Информативные интерфейсы Б предметно-ориентированном проектировании программ наша главная задача - ду­ Код, которы й фактически мать о смыслово й нагрузке операци й из предметной области .

реализует эффект от некоторого правила, но не дает его явного определения, заставляет нас применять пошаговые процедуры, чтобы все-таки его выяснить. То же самое отно­ сится и к любо й вычислительной операции, KOTOPYIO выполняет определенны й фрагмент кода, при этом не открывая ее логический смысл. Н е имея прямой привязки к модели, трудно понять, како й эффект имеет тот или ино й код или предвидеть последствия вно­ симого изменения. В предыдуще й главе рассматривалось моделирование правил и опе­ раций как явных объектов. Реализация таких объектов требует глубокого ПОIIимания мельчайших деталей операций и всевозможных тонкостей, заложенных в моделируемых правилах. К расота и сила объектов состоит в том, что они YMeIOT инкапсулировать все это, чтобы клиентски й код оставался простым и доступным для интерпретации в ПОIIЯ­ ти ях более высокого уровня .

ГЛАВА 1 0. ГИБКАЯ АРХИТЕКТУРА 223 Н о если интерфейс не сообщает разработчику достаточной информации для того, чтобы использовать объект эффективно, ему придется самостоятельно залезть во " внутренности" и раскопать все детали .

То же самое будет вынужден делать и читатель клиентского кода .

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

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

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

К ент Б ек (Kent Beck) уже писал о том, как через имена методов передавать их назна­ чение с помощью ИНФОРМАТИВНОГО СЕЛЕКТОРА ( INTENTION-REVEALING SELECTOR) [4] .

В се об щедоступные (public) элементы архитектуры некоторого программного компонен­ та об разуют его интерфейс, и выб ор имени для каждого из таких элементов - это воз­ можность передать информацию о назначении данного компонента. Имена типов, имена методов, имена аргументов - все это вместе образует ИНФОРМАТИВНЫЙ ИНТЕРФЕЙ С

(INTENTION-REVEALING INTERFACE)

давайте такие имена классам и операциям, чтобы они описывали их назначеlШе и получаемый результат, но не способ вьmолнения ими своих функций. Это избавляет раз­ работчика клиентского кода от необходимости понимать " внутреннюю кyxmo " этих объек­ тов. Имена должны соответствовать терминам ЕДИНОГО ЯЗЫКА, чтобы все члены рабочей группы поним8JПI, о чем идет речь. Нaпиuппе тест для алгоритма, прежде чем писать сам алгоритм, чтобы ввести свое мьшшение в режим разрабогmка клиешского кода .

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

В рuЫiс-интерфейсах уровня предметной области определяйте взаимосвязи и правила, но не способы, которыми они должны осуществляться. О писывайте суть событий и опера­ ци й, но не то, как именно они должны происходить. Формулируйте уравнение, но не чис­ ленный метод его решения. Ставьте вопрос, но не раскрывайте средств поиска ответа .

Пример

Рефакторинг: программа смешивани я красок Программа, предназначенная для обслуживания торговли красками, может показать покупателю результат смешивания стандартных красок. В от первоначальная ее архитек­ тура, включаIОЩая один-единственный класс предметной области .

–  –  –

Итак, этот метод, похоже, смешивает две краски (Paints), в результате чего получа­ ется больший объем и новы й смешанный цвет .

Ч тобы взглянуть на проблему под другим углом, давайте напишем тест для этого ме­ тода. (Код совместим со средой тестирования ] U пi t.)

–  –  –

Пройденны й тест - это наша отправная точка. Н а этом этапе код отталкивает нас своей неинформативностью: он не сообщает, что он делает. Давайте перепишем тест так, чтобы он отражал желаемый способ использования объектов Краска (Paint) - как ес­ ли бы мы писали клиентское приложение. В начале этот тест окончится неудачей. Ф ак­ тически он даже не будет скомпилирован. Мы пишем его только для того, чтобы иссле­ довать интерфейс объекта Краска с точки зрения разработчика клиентского кода .

pub l i c vo i d t e s t Pa i nt ( ) { / / Начинаем с чист ой желтой краски объемом= 100 Paint ourPaint = new Paint ( 100. 0, О, 50, О } ;

/ / Берем чистую синюю краску объемом= 100 Paint Ыuе = new Paint ( 100. 0, О, О, 50} ;

ГЛАВА 1 0. ГИБКАЯ АРХИТЕКТУРА / / Примешиваем синюю краску к желт ой // наша Кра ска .

примеша ТЬ ( СИНЯЯ) i ourPaint. mixln ( blue ) i / / Должно п олучит ь с я 200. 0 единиц зеленой кр а с ки a s s e rtEqual s ( 200. 0, ourPaint. getVolume ( ), 0. 01 ) i a s s ert Equa l s ( 2 5, ourPa int. getB lue ( ) ) ;

as sertEqua l s ( 2 5, ourPa int. getYe l l ow ( ) ) ;

a s s e rt Equa l s ( O, ourPaint. getRed ( ) ) ;

} Не пожалеем времени для того, чтобы написать тест в нужном стиле "общения " с ИН­ тереСУIОЩИМИ нас объектами. После этого ВЫllОЛНИМ рефакторинг класса Краска (Paint), чтобы наконец пройти тест .

–  –  –

Новое имя метода, может, и не расскажет читателю все о б эффекте " примешивания" другой краски (для этого понадобятся УТВЕРЖДЕНИЯ, или ASSERTIONS, о которых вско­ ре будет идти речь). Н о читатель получит достаточную подсказку, чтобы начать исполь­ зовать этот класс, особенно при наличии примера из теста. А читатель клиентского кода сможет интерпретировать смысл, заложенный в код. В нескольких следующих примерах этой главы мы продолжим рефакторинг класса для дальнейшего улучшения его понят­ ности и удобочитаемости .

*** В ыделять в отдельные модули и скрывать за ИНФОРМ АТИВНЫМИ ИНТЕРФЕЙС АМИ можно целые подобласти уровня предметной области. Использование такого приема для конкретизации проектных задач и управления сложностью больших систем будет более подроб но рассматриваться в главе 1 5, при вводе СВЯЗНЫХ МЕХА НИЗМОВ (COHESIVE

MECHANISMS) и ЕСТЕСТВЕННЫХ ПОДОБЛАСТЕЙ (GENERIC SUBDOMAINS ) .

В слеДУIОЩИХ двух архитектурных шаблонах мы попытаемся сделать последствия ис­ пользования того или иного метода как можно более предсказуемыми. Сложные алго­ ритмы можно безопасно реализовать в ФУf-IКЦИЯХ БЕЗ ПОБОЧf-IЫХ ЭФФЕКТОВ (SIDE­ EFFECT-FREE FUNCTIONS). Методы, изменяющие состояние системы, можно характеризо­ вать с помощью УТВЕРЖДЕНИЙ (ASSERTIONS) .

Функции без побочных эффектов В се программные операции можно приблизительно разделить на две категории ­ команды и запросы. З апросы получают информаЦИIО от системы - иногда простым об­ ращением к переменной, иногда через какие-то вычисления над данными. А вот команды (известные также как модификаторы) - это операции, которые вносят в систему какиеЧАСТЬ 1 1 1. УГЛУБЛЯЮЩИЙ РЕФАКТОРИНГ то изменения (в самом простом случае - присваивают значение переменной). В повсе­ дневном языке побочным эффектом (side effect) называется некое непреднамеренное по­ следствие того или иного действия. Н о в программировании этим выражением об озна­ чают любое влияние на состояние системы. Для наших целей давайте несколько сузим это понятие. Назовем поб очным эффектом такое изменение в состоянии системы, кото­ рое влияет на ее будущие операции .

Почему для об означения вполне намеренных изменений принят и при меняется такой термин, как побочный эффект? Я думаю, это следствие практического опыта работы со сложными системами. Б ольшинство операци й зависит от других операций, а те опера­ ции инициируют третьи операции и т.д. Е сли эту вложенность операций не контролиро­ вать, становится очень тяжело предсказать все последствия вызова той или иной опера­ ции. Разработчик клиентского кода может и не осознавать его влияния на операции вто­ рого и третьего уровня вложенности - так они становятся побочными эффектами уже во всех смыслах. Элементы сложной архитектуры взаимодействуют между собой и другими способами, которые тоже способ ны порождать непредсказуемость. В ыражение побочный эффект подчеркивает именно неизб ежность такого взаимодействия .

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

Операции, которые возвращают како й -то результат, не создавая побочных эффектов, называIОТСЯ функциями. Ф ункцию можно вызывать много раз, кажды й раз получая с ее п омощью один и тот же результат. Функция может вызывать другие функции, не беспо­ коясь о глуб ине вложенности операций. Функции гораздо легче тестировать, чем опера­ ции с поб очными эффектами. Поэтому применение функций снижает риск .

Очевидно, в б ольшинстве программных систем нельзя из бежать применения команд, но есть два способа смягчить проблему. В о-первых, можно держать команды и запросы строго разграниченными, оформлять их как разные операции. Сделайте так, чтобы мето­ ды, вызывающие изменения, не возвращали данные с уровня предметно й области и были устроены как можно проще. В ыполняй те все запросы и вычисления в методах, которые не вызывают никаких видимых побочных эффектов [ 1 9] .

Во-вторых, часто можно построить альтернативные модели или архитектуры, в кото­ рых сущеСТВУЮIЦИЙ объект вообще никогда не модифицируется. В место этого создается и возвращается новы й ОБЪЕКТ-ЗНАЧЕНИЕ (VALUE OBJECT), представляющий результат вычислительной операции. Э то распространенны й прием, который будет продемонстри­ рован в следующем примере. О БЪЕКТ-ЗНАЧЕНИЕ можно создать в ответ на запрос, пере­ дать куда следует, а потом заб ыть про него - в отличие от объекта-сУЩНОСТИ ( ENTITY), цикл существования которого строго регламентируется и отслеживается .

ОБЪЕКТЫ-ЗНАЧЕНИЯ по своей природе неизменяемы, и это подразумевает, что все их операции - функции, если не считать инициализаций, происходящих только в момент создания о бъекта. О БЪЕКТЫ-ЗНАЧЕНИЯ, как и функции, безопаснее в применении и проще в тестировании. О перацию, в которой вычисления или выполнение сложного алгоритма смешивается с изменением состояния, нужно факторизовать в две отдельные операции [ 1 2 ]. Но по определению такое выделение поб очных эффектов в простые ко­ мандные методы относится только к СУЩНОСТЯМ. После рефакторинга, отделяющего ГЛАВА 1 0. ГИБКАЯ АРХИТЕКТУРА модификацию от запроса, следует подумать о втором рефакторинге : вынесении сложных вычислений в ОБЪЕКТ-ЗНАЧЕНИЕ. П обочны й эффект часто можно совсем ликвидиро­ вать, произведя на свет новый ОБЪЕКТ-ЗНАЧЕНИЕ вместо изменения какого-либо теку­ щего состояния или передав всю ответственность за операцию в ОБЪЕКТ-ЗНАЧЕНИЕ .

Выносите как можно больше алrоритмической лоrики проrpаммы в функции, т.е .

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

Четко выделяйте команды (методы, которые вносят модификации в наблюдаемые со­ стояния о бъектов) в очень простые операции, которые не возвращают никакой ИН­ формации из уровня предметной области. Дополнительно контролируйте побочные эффекты, вынося сложные вычисления в ОБЪЕКТЫ-ЗНАЧЕНИЯ, если для таких опера­ ций имеются соответствующие концептуальные понятия .

Ф УНКЦИИ БЕЗ ПОБОЧНЫХ ЭФФЕКТОВ (SIDE-EFFECT-FREE FUNCTIONS), особенно ИН­ капсулированные в неизменяемых ОБЪЕКТАХ-ЗI IАЧЕНИЯХ, позволяют безопасно комби­ нировать операции. К огда такая функция предоставляется пользователю через ИНФОРМАТИВНЫЙ ИНТЕРФЕЙС, он может смело применять ее, не зная никаких подроб­ носте й ее реализации .

Пример

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

–  –  –

/ / Много строк сложн о г о ра сче т а смешива ния цве тов, / / ко т ор ый з аканчив а е т ся присв аив анием нов ых з наче ний / / ком п онен т о в r ( красного ), Ь ( син е г о ) и у ( желтого ) .

} методе примешивания mixln ( ) много чего происходит, но в этой архитектуре строго в соблюдается правило отделения модификации от запроса. Одна из проблем, которой мы зай мемся позже, заключается в том, что объем краски 2, аргумент метода mixln ( ), остает­ ся в " подвешенном" состоянии. О бъем краски 2 не изменяется в ходе этой операции, что кажется не совсем логичным в контексте этой концептуальной модели. Для исходных разЧАСТЬ 1 1 1. УГЛУБЛЯЮЩИЙ РЕФАКТОРИНГ работчиков это не было проблемой, потому что, насколько можно судить, объект " краска 2" после операции их больше не интересовал, но все последствия побочных эффектов (или их отсутствие) предвидеть трудно. Мы вскоре вернемся к этому вопросу при рассмотрении УТВЕРЖДЕНИЙ (ASSERTIONS). А пока давайте займемся цветами .

–  –  –

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

–  –  –

Выделение класса ПИгиентНЫЙ цвет (Pigment Color) действительно делает ар­ хитектуру более информативной, чем раньше, но расчет выполняется так же - по­ прежнему в методе примешивания mixln ( ). Выделяя данные о цвете в отдельный объект, было бы неплохо вместе с ними выделить и нужные операции. Но прежде чем мы это сде­ лаем, заметьте, что ПИгментНЫЙ цвет - это ОБЪЕКТ-ЗНАЧЕНИЕ. П оэтому его следует считать неизменяемым. П ри смешивании красок изменялся сам объект Краска (Paint) .

Это была СУЩНОСТЬ с непрерывной историей существования. Н о ПИгментНЫЙ цвет, представляющий определенный оттенок желтого цвета, всегда является именно им, и ничем другим. Смешивание не изменяет его, а дает новый объект ПИгиентНЫЙ цвет, представляющий новый цвет .

–  –  –

Теперь код модификации в классе Краска (Paint) упростился до предела. НОВЫЙ класс ПигментНЫЙ цвет (Pigment Color) заключает в себе знание предметной области и явно выражает его. О н предоставляет программисту-пользователю функцию без побоч­ ных эффектов, результат работы которой легко понятен, nрост в тестировании и безопасен

–  –  –

Утв ержд ения В ыделение сложных вычислений в ФУНКЦИИ БЕЗ ПОБОЧНЫХ ЭФФ ЕКТОВ радикально упрощает проблему, но все-таки и после этого еще остается много команд в объектах­ СУЩНОСТЯХ, которые порождают побочные эффекты. И все, кто пользуется такими объек­ тами, должны понимать последствия этого. УТВЕРЖДЕНИЯ (ASSERTIONS) позволяют сде­ лать побочные эффекты явными и упростить работу с ними .

*** Команду, не содержащую никаких сложных вычислений, сравнительно несложно по­ нять, просто прочитав ее код. Но в архитектуре, где большие структуры собраны из меньших частей, команда может обращаться к другим командам. Разработчик, исполь­ зующий команду высокого уровня, должен нонимать последствия каждой вызываемой ею команды с более низких уровне й. В от вам и инкапсуляция ! П оскольку интерфе й сы объектов не накладывают никаких ограничений на побочные эффекты, два подкласса, реализующих один и тот же интерфей с, могут иметь разные побочные эффекты. Разра­ ботчик, использующий их, должен знать, где какой класс, чтобы правильно предвидеть последствия. Вот вам и абстрагирование с полиморфизмом !

поБочныIe эффекты операций определены в их ре3JПIзации только неявно, то Если в архитектурах с интенсивной передачей управления возникает слоное переплетение причин и следствий. Е.динствеШIЫМ способом понять программу становится трассировка ее вьmолнения по всем возмоным ветвям. При этом теряется смысл инкапсуляции, а необ­ ходимость в трассировке вьmолнения делает беССМblслеШIЫМ также и абстраmрование .

Н еобходимо най ти такой способ для понимания смысла тех или иных элементов ар­ хитектуры и последствий выполнения операций, которы й бы не требовал залезания к ним вовнутрь. ИНФОРМАТИВНЫЕ ИНТЕРФЕЙСЫ частично решают проблему, но не­ формально й передачи смысла и предназначения элементов не всегда бывает достаточно .

Школа " контрактного проектирования " (design Ьу contract) делает следующий шаг, орга­ низуя проверки утверждени й относительно классов и методов, выполнение которых га­ рантирует разработчик. Э тот стиль программирования подробно рассмотрен в кни­ ге [ 19]. К ратко говоря, есть " пост-условия ", описывающие побочные эффекты опера­ ции - гарантированные последствия вызова метода. А есть " предусловия " - аналоги условий в контракте, которые необходимо соблюсти, чтобы пост-условие дало гаранти­ рованный результат. Инварианты классов - это и есть утверждения о состояния объекта в конце любо й операции. Инварианты можно также объявлять для целых АГРЕГАТО В, строго определяя правила сохранения целостности .

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

Формулируйте пост-условия для операций, а TaKe инварианты для классов и АГРЕГАТО В. Если УТВЕРЖДЕНИЯ нельзя непосредственно запрограммировать в среде ва­ шего языка, напишите модульные тесты для их проверки. Включите их в документацию или схемы, есл и это позволяет принятый стиль разработки проекта .

ГЛАВА 1 0. ГИБКАЯ АРХИТЕКТУРА Пытайтесь строить модели со связным набор ом понятий, которые заставляют раз­ работчика ф ор мулировать нео бходимые контрольные УТВЕРЖДЕНИЯ, ускоряя проце сс о бучения и снижая риск появления противоречий в коде .

Хотя во многих современных объектно-ориентированных языках программирования УТВЕРЖДЕНИЯ напрямую не поддерживаются, мыслить в таких категориях все же полезно для архитектуры. Нехватку поддержки в языке можно частично компенсировать автомати­ зированными модульными тестами. УТВЕРЖДЕНИЯ фОРМУЛИРУIОТСЯ в терминах состояний, а не процедур, поэтому тесты для них писать легко. П ри инициализации теста устанавли­ ваются требуемые предусловия; затем, после выполнения теста, проверяется выполнение пост-условий .

Четко сформулированные инварианты, предусловия и пост-условия помогают разра­ ботчику понять последствия использования операции или объекта. Теоретически для работы годится любо й непротиворечивый набор УТВЕРЖДЕНИЙ. Н о процесс мышления у люде й в головах не сводится к компилированию предикатов. Л юди экстраПОЛИРУIОТ и интерполируют понятия моделей, поэтому важно най ти такие модели, которые не только помогают писать программу, но и выглядят осмысленными .

Пример Снова о смешивании красок Н апомню, что в предыдущем примере было не совсем ясно, что происходит с аргумен­ том операции mixln ( Pa int ) в классе Paint (Краска), и это вызывало беспокой ство .

–  –  –

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

Чтобы встать на твердую почву, давай те сформулируем пост-условие для метода mixln ( ) как оно естъ .

По сле pl. mixIn (p2 ) :

pl. volume увеличивае т ся на объем p2. volume p2. volume не изме н я е т с я Б еда в том, что программисты обязательно сделаIОТ здесь ошибку, потому что эти усло­ вия не соответствуют понятиям, которые мы предложили им для обдумывания. Топорным решением будет обнуление объема второй краски. Изменение аргумента - плохой стиль, но зато здесь все просто и интуитивно понятно. Можно сформулировать инвариант .

Об щий объем крас ки не должен изменит ь ся от смешив ани я ЧАСТЬ 111. УГЛУБЛЯIОЩИЙ РЕФАКТОРИНГ Н о погодите-ка ! П ока программисты прорабатывали этот вариант, они поняли, что у исходных разработчиков была веская причина сделать все именно так, как было. П о итогам вычислений программа выдает список nесмешаnnых красок, которые были добав­ лены в смесъ. В конце концов, перед программо й стоит задача помочь пользователю опре­ делить, из каких красок nУЖ1l0 составлять смесъ .

Итак, сделать модель логически непротиворечиво й означает одновременно сделать ее непригодной для выполнения задач программы. В озникает дилемма. Что же, нам остает­ ся только задокументировать странное пост-условие и постараться компенсировать эту странность понятностью изложения. Не все в нашем мире интуитивно понятно, и иногда приходится поступать именно так. Но в данном случае противоречие, скорее всего, ука­ зывает на нехватку некоторых понятиЙ. П опытаемся поискать новую модель .

Теперь все ясно В наших поисках лучшей модели мы имеем преимущество перед исходными разра­ ботчиками, поскольку в промежутке мы уже произвели переработку знаний и рефакто­ ринг по модели. Например, мы вычисляем цвет с помощью ФУНКЦИИ БЕЗ ПОБОЧНЫХ ЭФФЕКТОВ в ОБЪЕКТЕ-ЗI-IАЧЕНИИ. А это значит, что такое вычисление можно повторять сколько угодно раз по мере необходимости. Э тим надо воспользоваться .

Кажется, класс Краска (Paint) имеет две разные базовые обязанности. Давайте по­ пробуем разделить их .

–  –  –

,,,

–  –  –

ГЛАВА 1 0. ГИБКАЯ АРХИТЕКТУРА Теперь у нас только одна команда - mixln ( ) .

О на просто добавляет объект в кол­ лекцию; этот эффект очевиден из интуитивного представления о модели. В се остальные операции являются ФУНКЦИЯМИ БЕЗ ПОБОЧНЫХ ЭФФЕКТОВ .

Тестовый метод, который бы проверял одно из утверждений, перечисленных на рис. 1 0. 1 О, мог бы выглядеть примерно так (с использованием среды тестирования JU nit) .

pub l i c voi d t e s tMixingVolume { P i gmentColor ye l l ow = new Pigment Co lor ( O, 50, О ) ;

PigmentColor Ыие = new P i gment Color ( O, О, 50) ;

–  –  –

Наглядность и описательность ИНФОРМАТИВНОГО ИНТЕРФЕЙСА (INTENТION-REVEALING INTERFACE) в сочетании с четкой предсказуемостью поведения, которую обеспечивают

ФУНКЦИИ БЕЗ ПОБОЧНЫХ ЭФФЕКТОВ (SIDE-EFFECT-FREE FUNCTIONS) и УТВЕРЖДЕНИЯ

(ASSERTIONS), способны сделать инкапсуляцию и абстрагирование вполне безопасными .

Следующая составляющая хорошей системы рекомбинируемых элементов - это эф­ фективное разбиение, или декомпозиция .

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

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

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

С другой стороныI' разбиение на классы и методы может привести к ненужному услож­ неюпо клиентского кода, потому что объектам-юrn:ентам приходится знать, как сочетаются между собой мелкие программные фрагменты. И что еще хуже, нужное понятие может во­ обще потеряться среди всего этого. ПОЛОВlПlа атома урана - это уже не уран. Разумеется, имеет значение не то, каков размер фрагмента, а то, где проходит его граmща .

П ростые наборы стандартных рецептов тут не годятся. Но в большинстве предметных областей заложено глубокое внутреннее логическое единство, иначе они не представляли бы ценности. Нельзя сказать, что всякая предметная область однозначно непротиворечиЧАСТЬ 1 1 1. УГЛУБЛЯЮЩИЙ РЕФАКТОРИНГ ва и последовательна, и уж точно не отличаются этими качествами высказывания поль­ зователей о предметных областях. Но где-то, на каком-то уровне, все-таки существует порядок и гармония, иначе моделирование не имело бы смысла. Э та внутренняя самосо­ гласованность проявляется в том, что если мы находим модель, которая " звучит в уни­ сон " с какой -то из часте й предметной области, то она, скорее всего, будет хорошо согла­ сована и с другими ее частями, которые мы откроем для себя позже. Иногда модель бы­ вает не так-то просто приспособить К новым открытиям, и в этом случае приходится выполнять глубокий рефакторинг, надеясь, что следующее открытие окажется для нее более удобоваримым .

Это одна из причин, почему повторяющи й ся рефакторинг постепенно приводит к гибко й архитектуре. П о мере адаптации кода к новому пониманию теоретических кон­ цепци й или функциональных требовани й возникают КОНЦЕПТУАЛЬНЫЕ КОНТУРЫ (CONCEPTUAL CONTOURS) .

" Близнецы-братья " - высокая внутренняя связность и низкая внешняя зависимость играют роль во всех масштабах архитектуры: от отдельных методов, классов и МОДУЛЕЙ дО крупномасштабных структур (см. главу 1 6). Эти два принципа применимы к понятиям в той же мере, что и к коду. Чтобы избежать сползания в чисто механистический взгляд на них, закаля йте ваше техническое мышление, периодически проверяя его интуитивным по­ ниманием предметной области. П ринимая любое решение, спрашивайте себя: " Что это ­ техническая уловка, основанная на каком-то наборе взаимосвязей в текущем коде и моде­ ли, или же отражение некоего смыслового контура в предметной области ? " .

Найдите концептуальную, смысловую единицу требуемой функциональности, и полу­ чившаяся архитектура станет одновременно гибкой и понятной. Например, если "сложение" двух объектов имеет логичный смысл в предметной области, то реализуйте ме­ тоды именно на этом уровне. Не разбивайте метод сложения add ( ) на два шага. Н е перехо­ дите к следующему шагу в пределах одной операции. В слегка увеличенном масштабе каж­ дый объект должен представлять собой одно законченное понятие, " ЦЕЛОСТНЫЙ ОБЪЕКТ­ ЗНАЧЕНИЕ " (WHOLE VALUE 1 ) .

Аналогичные признаки позволяют выделить в любой предметной области такие по­ добласти, подробности устро й ства которых неинтересны будущим пользователям про­ граммы. П ользователи нашей гипотетической программы смешивания красок не добав­ ляют в смесь красны й или синий пигмент. О ни смешивают готовые краски, в которых содержатся все три пигмента. О бъединение в одно целое того, что не требует реорганиза­ ции или рассечения на части, позволяет избежать хаоса и разглядеть те элементы, кото­ рые де йствительно имеет смысл рекомбинировать. Если бы реальное оборудование на­ ПIИХ пользователе й позволяло добавлять отдельные пигменты, предметная область име­ ла бы друго й вид, и там можно было бы манипулировать пигментами. Химику, занимающемуся разработко й красок, тоже нужен совсем друго й уровень контроля над процессом, и там нужно было бы провести друго й анализ проблемы. В результате могла б ы получиться гораздо более подробная модель создания краски, чем наш абстрактный " пигментны й цвет ". Н о это не имеет никакого значения для участников проекта по раз­ работке программы смешивания .

Разбивайте элементы архитектуры ( оп ерации, интерфейсы, классы и АГРЕГАТЫ) на связные единицы, учитывая свое интуитивное понимание смысловых границ предмет­ ной области. Наблюдайте за направлениями изменений и осями стабильности в х оде последовательного рефакторинга, ищите КОНЦЕПТУАЛЬНЫЕ КОНТУРЫ ( CONCEPTUAL CONTOURS), п о которым происходит расслоение между ними. Прежде Bcero согласуйте

1 Это архитектурный шаблон, автор Уорд Каннингем (Ward Cunningham ) .

ГЛАВА 10. ГИБКАЯ АРХИТЕКТУРА модель с теми логически последовательными и стройными аспектами предметной об­ ласти, которые делают данную область жизнеспособ ной, практически ценной .

Цель это й деятельности - создать простой набор интерфей сов, которые можно логи­ чески сочетать между собой для составления осмысленных утверждений на ЕДИ Н ОМ ЯЗЫКЕ, притом не отвлекаясь на техническое обслуживание маловажных аспектов .

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

Даже если архитектура программы следует КОНЦЕПТУАЛЬНЫМ КО НТУРАМ, модифи­ кации и рефакторинг неизбежны. К огда успешны й рефакторинг имеет тенденцию оста­ ваться локальным, не затрагивая сразу много общих понятий модели, это показатель адекватности модели. Если же встречается требование к программе, которое заставляет вносить серьезные изменения в структуру объектов и методов, это уже сигнал: нашему пониманию предметной области не хватает глубины. Тем самым нам предоставляется возможность углубить модель и сделать архитектуру более гибкой .

Пример

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

Н овая модель содержала всего на один объект больше, чем старая, но разграничение обязанносте й изменилось очень сильно .

Графики (временные), которые в классах Калькулятор (Calculator) реализова­ лись через ветвление, были выделены в отдельные классы для разных видов сборов и процентов. С другой стороны, выплата сборов и процентов, которая раньше была раз­ делена на отдельные процедуры, стала располагаться в одном месте .

Б идя громки й резонанс, вызванны й новыми явными понятиями, И связность ие­ рархии Графиков начислений (Acc rual S c hedu l e ), разработчик стал полагать, что эта модель лучше отражает некоторые из КОНЦЕПТУАЛЬНЫХ КО НТУРО В пред­ метно й области .

Изменение, которое разработчик смог уверенно предсказать, состояло в добавлении новых Графиков начислеНИЙ. Эти требования уже, можно сказать, витали в воздухе .

П оэтому, кроме упрощения и более четкого оформления существующих функций, раз­ работчик выбрал модель, которая б ы позволяла легко добавлять новые графики. Но на­ шел ли он КОНЦЕПТУАЛЬНЫЙ КОНТУР, которы й позволит изменять и расширять архи­ тектуру предметно й области по мере развития программы и ее практических приложе­ ний ? Н евозможно заранее гарантировать, что архитектура адекватно отреагирует на непредвиденные изменения. Но программист считал, что он повысил шансы на успех .

Непредвиденное изменение П о ходу проекта возникло следующее требование к программе: ввести подробные правила обработки досрочных и просроченных платежей. Изучая проблему, програм­ мист с удовольствием обнаружил, что практически те же правила применимы к плате­ жам по процентам и платежам по сборам. Это означало, что новые элементы модели ес­ тественным образом связывались с единственным классом ПЛатеж (Payment) .

–  –  –

в старой архитектуре было бы неизбежно дублирование между двумя классами Ис ­ тории платежей (Payment His tory). ( Кстати, эта трудность могла бы привести раз­ работчика к выводу, что класс ПЛатеж (Payment ) должен использоваться совместно, и тогда он бы пришел другим путем к аналогично й модели.) Расширение прошло легко не потому, что программист предвидел это изменение. И не потому, что архитектура ста­ ла настолько универсальной, что могла бы воспринять любое мыслимое изменение. Все произошло потому, что предыдущий рефакторинг привел архитектуру в соответствие с фундаментальными понятиями предметной области .

*** И НФОРМАТИВНЫЕ ИНТЕРФЕЙСЫ (INTENTION-REVEALING INTERFACES) позволяют клиентам представлять объекты как единицы смысла, а не просто рабочие механизмы .

ФУНКЦИИ БЕЗ ПОБОЧНЫХ ЭФФЕКТОВ (SIDE-EFFECT-FREE FUNCTIONS) и УТВЕРЖДЕНИЯ

(ASSERTIONS) позволяют без опаски пользоваться такими единицами и составлять из них сложные комбинации. В озникновение КОНЦЕПТУАЛЬНЫХ КОНТУРОВ (CONCEPTUAL CONTOURS) стабилизирует деление модели на части, а также делает смысловые единицы более наглядными и удобными в комбинациях .

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

Изолиров анные класс ы Н аличие взаимосвязе й и зависимосте й между элементами делает модели и архитек­ туры трудными для понимания. Трудности возникают также в их тестировании и дора­ ботке. К TOlVlY же взаимосвязи имеют тенденцию накапливаться .

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

Имея одну взаимосвязь, приходится думать одновременно о двух классах, а также о природе зависимости между ними. Имея две взаимосвязи, надо думать о каждом из ЧАСТЬ 111. УГЛ УБЛЯIОЩИЙ РЕФАКТОРИНГ трех классов, о природе каждой зависимости одного класса от других и вообще обо всех возможных взаимоотношениях между ними. Если у них есть свои взаимосвязи с чем-то посторонним, это тоже приходится принимать во внимание. И мея три взаимосвязи.. .

в общем, все заканчивается лавино й .

Ограничение паутины взаимосвязей входит в задачи как МОДУЛЕЙ, так и АГРЕГАТОВ .

Как только высокосвязная предметная подобласть выделяется в отдельный модуль, от cilcTeMbI отрезается целы й набор объектов, внутри которого количество взаимосвязан­ ных понятий сравнительно невелико. Н о даже если не впадать в фанатизм и не пытаться контролировать абсолютно все взаимосвязи в МОДУЛЕ, головной боли, тем не менее, бу­ дет хватать .

Даже в пределах одного МОДУ ЛЯ сложность интерпретации архитектуры быстро возр астает при добавлении новых взаимосвязей. Это приводит к смысловой перегруз­ ке и снижает потенциальную сложность архитектуры, которая была бы понятна раз­ работчику. Наличие неявных понятий дает даже больший вклад в эту перегрузку, чем наличие явных ссылок между элементами .

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

В любой среде программирования есть несколько веще й настолько базовых, что они никогда не выходят из головы у программиста. Например, в программировании на Java существует несколько таких примитивов и элементов стандартных библиотек, как числа, строки, коллекции. С практическо й точки зрения оттого, что программист помнит поня­ тие " целого числа ", интелектуальная нагрузка на его мозг не слишком возрастает. Н о ес­ ли не считать таких случаев, каждое дополнительное понятие, которое нужно удержи­ вать в уме, чтобы понимать объект, дает вклад в интеллектуальную llерегрузку .

Неявные понятия, как осознаваемые, так и неосознаваемые, имеют не меньшее влия­ ние, чем явные ссылки .

Хотя, как правило, мы можем игнорировать взаимосвязи с таки­ ми примитивными значениями, как числа или строки, нельзя игнорировать то, что они представляют. Б первом примере программы смешивания красок объект краска (Paint) содержал три риЫiс-значения, представлявших целочисленные коды красного, желтого и синего компонентов. Создание объекта ПигментНЫЙ цвет (Pigment Color) не увеличивает количество понятий, участвующих во взаимосвязях, но делает уже суще­ ствующие более явными и понятными. С другой стороны, и операция s i z e ( ) объекта Коллекция: (Col lection) возвращает целое число ( int), представляющее собой про­ сто количество - Т.е. то, для чего целые числа и суrцествуют. Здесь тоже не скрыто ника­ ких новых понятиЙ .

Всякая взаимосвязь и зависимость должна находиться под подозрением, пока не до­ казано, что она принципиально важна для понятия, скрытого за объектом. Такое "расследование " должно начинаться с выделения (факторизации) собственно понятий модели. П отребуется пристальное внимание к каждой конкретно й ассоциации и опера­ ции. П роектные и модельные решения, ВlIолне возможно, будут приводить К отсечению одной зависимости за другой - до полного их уничтожения .

Низкая внешняя зависимость - это качество, фундаментальное для проектирова ­ ия архитектуры объектов. Если это возможно, устраняйте лю бую зависимость, как н только возможно. Убирайте все другие понятия из картины. Тогда класс станет полноГЛ АВА 1 0. ГИБКАЯ АРХИТЕКТУРА 239 стью самодостаточным, его можно будет изучать и понимать отдельно от друrих. Лю­ бой такой самодостаточный класс существенно о блегчает бремя понимания модуля .

Зависимость от других классов внутри одного и того же модуля значительно менее вредоносна, чем внешние взаимосвязи. Даже более того - если два объекта имеют есте­ ственную тесную связь друг с другом, большое количество операций с одной и той же паро й объектов может фактически прояснить природу их взаимосвязи. Цель, собственно, состоит не в том, чтобы устранить вообще все взаимосвязи, а в том, чтобы устранить все несущественные. Если можно убрать не все взаимосвязи, а только некоторые, то устра­ нение каждо й из таковых позволяет программисту сосредоточиться на оставшихся КОН­ цептуальных зависимостях .

Старайтесь выделить наиболее сложные и запутанные вычисления в ИЗОЛИРОВАННЫЕ КЛАССЫ(SТАNDАLОNЕ CLASSES) - возможно, путем моделирования ОБЪЕКТОВ-ЗНАЧЕНИЙ, содержащихся внутри более зависимых классов .

Понятие краски неразрывно связано с понятием цвета. Н о цвет, даже цвет пигмента, можно рассматривать и без краски. Делая эти два понятия явными и дистиллируя отноше­ ние между ними, мы создаем такую одностороннюю ассоциацию, которая передает важное утверждение, причем класс ПигиенНЬ1Й цвe (Pigment Color), в котором заключается большая часть сложных вычислений, можно изучать и тестировать автономно .

*** Низкая внешняя зависимость - это основной способ уменьшения смысловой пере­ грузки. ИЗОЛИРОВАННЫЙ КЛАСС - это граничный случай низкой внешне й зависимости .

устранение взаимосвязей не должно означать профанацию модели путем принуди­ тельного сведения всех ее элементов к самым примитивным. Последни й архитектурный шаблон в это й главе, ЗАМКНУТОСТЬ ОПЕРАЦИЙ ( CLOSURE OF OPERATIONS), дает пример того, как устранить лишние взаимосвязи при сохранении богатого и интеллектуального интерфей са.. .

Замкнуто сть опер ац ий Если мы возьмем два действительных числа и nеремножuм ИХ, то получим другое действительное число. [Действительные числа - это все раЦИОНШlьные числа и все ирраЦИОНШlьные числа.] Это верно в любом случае, поэтому мы говорим, что действительные числа "замкнуты относительно операции умножения " - эта операция не может вывести нас за пределы множества .

Комбинируя два элемента из множества, получаем результат, также принадлежащий этому множеству .

The Math Ротт, Drexel University В заимосвязи, Т.е. проявления зависимости, будут существовать всегда. И в этом нет ничего плохого, когда зависимость играет фундаментальную роль для некоторого поня­ тия. Если упростить интерфей сы до того, что в них останутся ссылки только на прими­ тивы, от этого пострадают функциональные возможности. Но тем не менее в интер(рей­ сах встречается много ненужных зависимостей и даже целых лишних поняти й .

Самые интересные о бъекты делают такое, что нельзя охарактеризовать одними тольк о примитивами .

Один из распространенных приемов совершенствования архитектуры основан на достижении ЗАМКНУТОСТИ ОПЕРАЦИЙ ( CLOSURE OF OPERATIONS). ЭТО название пришло из самой тонкой и совершенно й системы понятий из математики. Возьмем соотношеЧАСТЬ 1 1 1. УГЛУБЛЯЮЩИЙ РЕФАКТОРИНГ ние 1 + 1 2. Операция сложения замкнута по отношению к множеству де й ствительных = чисел. Математики упорно избегают введения ненужных, лишних поняти й, а сво йство замкнутости позволяет им определить операцию, не привлекая никаких других понятиЙ .

Мы так привыкли к чистоте и строгости математики, что не всегда осознаем, насколько МОЩНЫМИ являются ее небольшие уловки. Н о эта широко используется и в проектирова­ нии программ. Так, основное применение языка XSLТ - преобразование одного доку­ мента XML в друго й. Э та операция XSL Т замкнута относительно множества докумен­ тов XML. Свойство замкнутости сильно упрощает интерпретирование операции, а также облегчает комбинирование или последовательную реализацию нескольких операций .

Там, где это уместно, определяйте операцию(-и) с тем же типом возвращаемого значения, что и тип аргумента ( - ов). Если реализующий ее объект имеет состояние, ис­ пользуемое в вычислениях, то этот объект фактически является аргументом операции, поэтому аргумент(ы) и возвращаемое значение должны быть того же типа, что и реа­ лизующий объект. Такая операция замкнута относительно множества экземпляров этоrо типа. З амкнутая операция обеспечивает интерфейс высокого уровня без какой­ либо зависимости от других понятий .

Данны й архитектурны й шаблон чаще всего применяется в операциях ОБЪЕКТОВ­ ЗНАЧЕНИЙ. П оскольку цикл существования объекта-сУЩНОСТИ играет важную роль в предметной области, нельзя просто слепить новую СУЩНОСТЬ на скорую руку, чтобы ответить на задаваемы й вопрос. Существуют и операции, замкнутые относительно типа СУЩНОСТИ. Так, можно спросить у объекта Работник (Emp l oyee), кто является его не­ посредственным начальником, и получить в ответ тоже объект Работник. Н о в целом СУЩНОСТИ обычно не принадлежат к тем объектам, которые возникают как результат некое й вычислительно й операции. П оэтому, как правило, нужные возможности следует изыскивать в ОБЪЕКТАХ-ЗНАЧЕНИЯХ .

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

В ходе экспериментирования с методами для уменьшения взаимозависимости и по­ вышения внутренне й связности этот шаблон до определенно й степени возникает сам со­ бой. Аргумент соответствует реализатору, но тип возвращаемого значения отличается или же тип возвращаемого значения соответствует получателю, но тип аргумента - дру­ гой. Такие операции не замкнуты, но и они обладают некоторыми преимуществами ЗАМКНУТОСТИ. Если дополнительны й тип - примитив или базовы й библиотечны й класс, он освобождает от хлопот почти так же хорошо, как ЗАМКНУТОСТЬ .

В предыдущем примере операция mixedWith ( ) класса пигментный цвет (P igment Col0r) была замкнута относительно этого класса; по тексту книги разбросано еще не­ сколько аналогичных примеров. Н иже приведен пример, показывающи й всю полезность этой идеи даже в том случае, когда не достигается полноценная ЗАМКНУТОСТЬ .

Пример

Выбор из коллекций Если нужно выбрать подмножество элементов из Коллекции в языке J ava, следует запросить у нее Итератор ( I terator). Далее с помощью него происходит итерациоп­ ный перебор элементов с проверкой каждого из них, причем подходящие элементы могут накапливаться в новой Коллекции .

ГЛАВА 1 0. ГИБКАЯ АРХИТЕКТУРА S e t emp l oyee s = ( some S e t o f Emp l oyee obj e c t s ) ;

S e t l owPa i dEmp l oye e s = new HashSe t { ) ;

I t e rator i t = emp l oyee s. i t e rator { ) ;

whi l e ( i t. hasNext { ) ) { Emp l oyee anEmp l oyee = i t. next { ) ;

i f ( anEmp l oye e. sa l a ry { ) 40000) l owPaidEmployee s. add { anEmp l oyee ) ;

} концептуальной точки зрения здесь из множества просто выбирается подмножест­ с З ачем для этого нужно лишнее понятие Итератора и вся эта техническая слож­ во .

ность? В языке Srnalltalk я бы вызвал операцию выбора ( s e l e c t ) из Коnnекции, пере­ дав критери й -проверку в качестве аргумента. В результате получилась бы новая Кол ­ лекция, содержащая именно те элементы, которые прошли проверку .

emp l oyee s : = ( some Set of Emp l oyee obj e ct s ) .

l owPai dEmp l oyees : = emp l oyee s s e l e c t :

[ : anEmp l oyee I anEmp l oyee s a l ary 40000] .

Коллекции языка Srnalltalk предлагают и другие подобные Ф у нкции, возвращаю­ щие производные Коллекции, которые могут принадлежать к нескольким конкретным классам. Э ти операции не замкнуты, поскольку в качестве аргумента они принимают " блок ". Но блок - это базовый библиотечный тип в Smalltalk, так что память программи­ ста это не перегружает. В озвращаемое значение соответствует типу реализующего объ­ екта, поэтому их можно выстроить в цепочку, как последовательность фильтров, причем все это легко как писать, так и читать. П ри этом не вводятся лишние понятия, которые несущественны для задачи отбора подмножеств .

*** Шаблоны, представленные в это й главе, иллюстрируют общи й стиль программиро­ вания и способ мышления при разработке программной архитектуры. Если стараться сделать программу понятной, наглядно й, информативно й, предсказуемой в поведении, то абстракция и инкапсуляция станут по-настоящему эффективны. Модели следует фак­ торизовать так, чтобы выделенные в них объекты были просты в использовании и пони­ мании, но тем не менее имели гибкие и развитые интерфейсы .

Чтобы успешно применять такие приемы при проектировании архитектуры, требует­ ся довольно высокая квалификация. Б ез хороших навыков архитектурного проектиро­ вания про грамм иногда не обой тись даже при написании клиентского кода. Э ффектив­ ность подхода ПРОЕКТИРОВАНИЯ ПО МОДЕЛ И (MODEL-DRIVEN DESIGN) сильно зависит от качества детализированной архитектуры и технических решени й при ее реализации .

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

Итак, для программистов, которые готовы развивать свои навыки моделирования и проектирования, изложенные выше шаблоны и отражаемы й ими способ МЫlllл ения от­ крывают путь к успешной разработке, доработке и переработке программного обеспече­ ния, позволяющий создавать программные продукты любой сложности .

Декларативная архитектура С помощью контрольных УТВЕРЖДЕНИЙ (ASSERTIONS) архитектуру программы мож­ но значительно улучшить, даже учитывая сравнительно пеформальный характер этого способа тестирования. Но в программах, написанных вручную, реальных гарантий дать 242 ЧАСТЬ 1 1 1. УГЛУБЛЯЮЩИЙ РЕФАКТОРИНГ нельзя. П роверка УТВЕРЖДЕ Н ИЙ может ничего не дать хотя бы по то й причине, что в ко­ де могут присутствовать побочные эффекты. Пусть даже наша архитектура и спроекти­ рована строго ПО М ОДЕЛИ, в дополнение к ней мы все равно пишем процедуры, имити­ рующие эффект концептуальных взаимосвязей. М ного времени затрачивается на то, чтобы " склепать " код, которы й фактически не добавляет в программу ни смысла, ни опе­ раций. Э то и скучно, и чревато ошибками, а обилие такого кода " затуманивает " смысл само й модели. (Некоторые языки в этом отношении лучше других, но все равно любо й из них заставляет нас делать много нудной работы.) ИНФОРМАТИВНЫЕ ИНТЕРФЕЙСЫ (INTENTION-REVEALING INTERFACES) и другие архитектурные шаблоны из этой главы по­ могают частично решить проблему, но они никогда не придают обычным объектно­ ориентированным программам формальную строгость .

Имеется целы й ряд соображени й и мотивов, приводящих нас к декларативной архи­ тектуре (declarative design). Э тот термин означает много разного для разных людей, но обычно под ним подразумевают способ написания программы или како й -то ее части в виде чего-то вроде выполняемой спецификации. П рограмма фактически управляется очень точным описанием ее свой ств. Э то можно проделать в самых разных формах через механизм отражения или в ходе компиляции с помощью автоматического генерирования кода (при этом на основе декларации создается обычны й код). Такая методика позволяет другому программисту воспринимать декларацию именно так, как она написана. Э то полная и абсолютная гарантия .

Генерирование работающей программы из декларации сво й ств модели - это нечто вроде Святого Грааля для идеологии ПРОЕКТИРОВАНИЯ ПО М ОДЕли 2. Н а практике, впрочем, в этом подходе имеются свои ловушки. В от, например, две конкретные пробле­ мы, с которыми я не раз сталкивался на практике .

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

Средства генерирования кода препятствуют итерационному циклу разработки:

• они вставляют автоматически созданны й код в написанны й вручную таким обра­ зом, что повторное генерирование дей ствует на код разрушительно .

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

Еще один перспективны й подход в декларативно й архитектуре - это логическое про­ граммирование (rule-based programming) с механизмом выводов и базой правил. К сожа­ лению, и эта идея может провалиться из-за некоторых тонкостей .

Хотя программа, основанная на совокупности логических правил, в принципе декла­ ративна, в БОЛЫJlинстве таких систем имеются " управляющие предикаты ", добавленные туда для возможности настрой ки производительности. Этот управляющи й код вносит побочные эффекты, и в результате поведение программы уже не полностью определяет­ ся декларированными правилами. Добавление, удаление и переупорядочение правил может привести к непредсказуемым и неправильным результатам. П оэтому программист 2 Это надо понимать в том смысле, что такой способ давно ищут, о нем мечтают, но пока так и не нашли. Прu.меч. перев .

ГЛАВА 1 0. ГИБКАЯ АРХИТЕКТУРА 243 в логическо й парадигме, как и программист объектно-ориентированны й, должен Тlца­ тельно следить за очевидностью и предсказуемостью поведения кода .

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

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

Специализированные предметные языки Интересны й подход, которы й иногда бывает декларативным - это разработка спе­ циализированного предметного языка (domain-specijic language) для задачи. В этом стиле программирования клиентски й код пишется на языке программирования, специально приспособленном к конкретной модели конкретно й предметной области. Например, язык системы организации грузоперевозок может содержать такие термины, как груз и маршрут, вместе с необходимым синтаксисом. Н аписанная на таком языке программа может транслироваться на обычны й объектно-ориентированный язык, в котором реали­ зацию терминов из специализированного языка обеспечивают библиотеки классов .

Программы на таком языке могут быть чрезвычай но выразительными, находясь в прямо й связи с ЕДИНЫМ ЯЗЫКОМ. Э ТО очень интересная концепция, но у предметно­ специализированных языков есть и недостатки в части знакомых мне подходов, осно­ ванных на объектно-ориентированно й технологии .

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

Э тот прием может быть полезен в работе с очень зрелыми, проработанными моделя­ ми, где клиентски й код, возможно, пишется другой группой разработчиков. Правда, при тако й организации работы может возникнуть опаснеЙJll ИЙ разрыв между искусными технарями-разработчиками среды и технически невежественными авторами собственно приложения, но это вовсе не обязательно случится .

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

244 ЧАСТЬ 1 1 1. УГЛУБЛЯЮЩИЙ РЕФАКТОРИНГ С чистого листа Возможно, для специализированных предметных языков может лучше подойти другая парадигма, нежели объектная. В Scheme, представляющем "функциональное про­ языке граммирование", нечто подобное входит в стандартный стиль программирования, и выра­ зительность специализированного предметного языка может достигаться без разрыва в организации системы .

Декларативный стиль архитектуры Как только в архитектуре вашей программы появляются ИНФОРМАТИВНЫЕ ИНТЕР­

Ф Е ЙСЫ (INTENTION-REVEALING INTERFACES), ФУНКЦИИ БЕЗ ПОБОЧНЫХ ЭФФЕКТОВ

(SIDE-EFFECT-FREE FUNCTIONS) и УТВЕРЖДЕНИЯ (ASSERTIONS), вы уже одно й ногой всту­ паете на декларативную территорию. Многие преимущества декларативной архитектуры на­ чинают проявляться тогда, когда у вас появляются хорошо сочетаемые элементы, четко пере­ дающие свой смысл, побочные эффекты которых известны, очевидны либо отсутствуют .

Гибко спроектированное приложение часто позволяет использовать в клиентском ко­ де декларативный стиль архитектуры. Чтобы проиллюстрировать эту мысль, в следую­ щем разделе сводятся вместе некоторые из шаблонов этой главы, и это позволяет сделаТI) С ПЕ ЦИФИКАЦИЮ более гибкой и декларативной .

Расширение спецификаций в декларативном стиле В главе 9 рассматривалось фундаментальное понятие СПЕЦИФИКА.ЦИИ (SPECIFICATION), которую она может играть в программе, и некоторые особенности ее реализации. Теперь роль, давайте рассмотрим несколько уловок, которые могут оказаться полезными в некоторых си­ туациях, где присутствуют сложные регламентные правила .

СПЕЦИФИКАЦИЯ это разновидность строгого формального утверждения, предиката. У предикатов есть различные полезные свой ства, которыми мы избирательно воспользуемся .

Комбинирование спецификаций в логических операциях Используя СПЕЦИФИКАЦИИ, часто встречаешься с необходимостью комбинировать их в те или иные сочетания. Как только что было сказано, спецификация - это разно­ видность предиката, а предикаты можно сочетать и модифицировать с помощью опера­ ций " И ", " И Л И " и "Н Е ". Э ти логические операции замкнуты относительно множества предикатов, так что комбинации СПЕЦИФИКАЦИЙ демонстрируют ЗАМКНУТОСТЬ О ПЕ РАЦИЙ .

СПЕЦИФИКАЦИИ содержат в себе важные обобщенные возможности, и для их полно­ раскрытия полезно создать абстрактны й класс или интерфе й с, которы й может ис­ го пользоваться для работы со СПЕЦИФИКАЦИЯМИ любого рода. Аргументы методов в нем должны представлять собо й абстрактные классы высокого уровня .

–  –  –

Такая абстракция требует применения предохранительного оператора в начале метода, но в остальном никак не влияет на функциональность. Например, вот как можно бьшо бы моди­ фицировать класс СпецифихaциR :контейнера (Container Speci f ica tion) из главы 9 .

–  –  –

Spec i f i c a t i on and { Spec i f i c a t i on othe r ) ;

Spe c i f i c a t i on or { Spec i f i ca t i on othe r ) ;

Spec i f i cat ion not { ) ;

} Напомним, что одни Специфи:кации :контейнеров требовали вентилируемых (ventilated) Контейнеров, а другие - усиленных (armored). Химикат, являющий ся од­ новременно и летучим, и взрывоопасным, вероятно, должен удовлетворять обеим этим Специфи:кацияи. Э то легко записать, используя новые методы .

Spe c i f i c a t i on vent i l ated = new Cont ainerSpec i f i c at ion { VENTI LATED ) ;

Spec i f i cat ion armored = new Cont a inerSpe c i f i c a t i on (ARMORED ) ;

–  –  –

Такое ограничение позволило бы избежать некоторых неоптимальных реllIений в прототипе программы-складировщика, которы й рассматривался в главе 9 .

ЧАСТЬ 111. УГЛУБЛЯЮЩИЙ РЕФАКТОРИНГ Возможность строить сложные спецификации из простых элементов улучшает вырази­ тельность кода .

А комбинации элементов записываются во вполне декларативном стиле .

Сами операции комбинирования могут быть простыми или сложными В реализации в за­ висимости от того, как именно реализованы СПЕЦИФИКАЦИИ. Далее показана очень простая реализация, которая в одних ситуациях бьша бы неэффективна, а в других - вполне работо­ способна. Здесь она приведена только как наглядный npuмep. На самом деле способов реали­ зации великое множество, как и в случае любого другого архитектурного шаблона .

–  –  –

} { pub l i c bool ean i s Sat i s f i edBy ( Ob j e c t candidate ) re turn ! wrapped. i s S at i s f iedBy ( candidat e ) j } } Э тот код был специально сделан как можно проще для удобства чтения н книге. Как уже говорилось выше, во многих случаях он неэффективен. Но возмо)кны и другие вари­ анты реализации, в которых минимизировалось бы количество участвующих объектов, или оптимизировалось быстродей ствие, или соблюдалась бы совместимость с како й ­ нибудь экзотическо й технологией, используемо й в проекте. Важно лишь помнить о мо­ дели, содержаще й ключевые понятия предметно й области, и о том, что реализация должна придерживаться это й модели. П ри этом остается достаточно места для маневра, чтобы решить проблемы быстродействия .

Кроме того, слишком широкая общность во многих случаях и не ну)кна. В частности, операция И имеет гораздо более широкую применимость, чем две другие, и создает меньше проблем в реализации. Смело реализуй те одну только операцию И, если больше­ го вам не требуется .

В самом начале книги, в главе 2, программисты явно не реализовали операцию "удовлетворяется " (satis/ied Ьу) своей СПЕЦИФИКАЦИИ. ДО того момента СПЕЦИФИКАЦИЯ использовалась только для создания объектов по заказу. Но даже при этом абстрагирова­ ние было соблюдено, и добавление новых функций оставалось сравнительно несложным .

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

Пример

Альтернативная реализация составной спецификации Некоторые исполняемые среды не слишком хорошо спраВЛЯIОТСЯ с большими количе­ ствами очень мелких объектов. Как-то я работал над проектом с объектной базо й данных, где требовалось выдавать объектный идентификатор каждому объекту, а затем отслежиЧАСТЬ 111. УГЛУБЛЯЮЩИЙ РЕФАКТОРИНГ вать его. Каждый объект отнимал много дополнительных ресурсов памяти и процессора, и общее адресное пространство оказалось ограничивающим фактором. В нескольких ключевых точках архитектуры предметной области я применил СПЕЦИФИКАЦИИ, что показалось мне удачным решением. Но я воспользовался несколько более сложно й вер­ сией той реализации, которая описана в этой главе, и это оказалось ошибкой. В системе возникли миллионы мелкомасштабных объектов, что вызвало серьезное замедление ее б ыстродей ствия .

Далее приведен пример альтернативной реализации, в которой составная СПЕЦИФИ­ КАЦИЯ кодируется в виде строки или массива с логическим выражением, интерпретируе­ мым в ходе выполнения программы .

(Не волнуй тесь, если не понимаете, как это реализовать. Самое важное сей час - по­ нять, что существует много способов реализовать СПЕЦИФИКАЦИЮ с помощью логиче­ ских операци й и что если простой способ не работает в конкретной ситуации, то всегда есть выбор.) Содержимое стека спецификации ДЛЯ "дешевого контейнера" Верх AndSpec i f icationOperator (Fly We ight ) [ Оnерация-И (Леzкий) ] NotSpec i f icat ionOperator (Fly We ight ) [ Операция-Не (Леzкий )] Armored ( уСШlеllllЫЙ) Not Spec i f icationOperator r Операция -Не] Vent i lated [ ВентШlируем ЪlЙ] Когда нужно проверить контей нер-кандидат, приходится интерпретировать эту структуру. Э то можно проделать, извлекая кажды й элемент из стека и либо анализируя его значение, либо извлекая следующее в зависимости от того, чего требует операция. В конце концов получится следующее .

–  –  –

+ участвует мало объектов;

+ эффективно используется память;

- требуется высокая квалификация программистов .

Вам придется най ти такую реализаЦИIО, компромиссы которой подходили бы к ваше­ му случаю. Один и тот же UIаблон, одна и та же модель могут лежать в основе самых раз­ ных программных реализаци й .

Сужение В этом последнем из описанных здесь средств редко возникает необходимость, да и реализовать его не так-то просто, но время от времени с его помощью удается решить серьезную проблему. Оно также проливает свет на смысл СПЕЦИФИКАЦИИ .

Снова рассмотрим программу-складировщик химикатов. Напомним, что каждый Хими­ кат (Chemical) имеет свою Спецификацию :контейнера (Container Specification), ГЛАВА 1 0. ГИБКАЯ АРХИТЕКТУРА а служба Ск.nаДИРовщИх (Packer) гарантирует удовлетворение всех спецификаций при по­ мещении Бочек (Drums) в контейнеры (Containers). И все идет хорошо... пока кто-нибудь не изменит нормативные требования .

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

К онечно, можно было бы дать частичны й ответ (причем такой, которы й тоже мог бы понадобиться пользователям), подвергнув проверке по новым СПЕЦИФИКАЦИЯМ каж­ дую Бочку в инвентарно й описи и выбрав те из них, которые больше не удовлетворяют требованиям. Так пользователи узнали бы, какие Бочки в существующем размещении им нужно переместить .

Н о nРОСШlu-то они совсем другое: список всех химикатов, требования к обращению с которыми ужесточились. Может быть, на складе сей час таких химикатов нет вообще или же они случай но помеrцены в более строги й контей нер, чем нужно. В любом из этих случаев они не будут упомянуты в отчете .

Давайте введем новую операцию для прямого сравнения двух СПЕЦИФИКАЦИЙ .

boo l ean subsume s { Spec i f i ca t i on othe r ) ;

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

–  –  –

Н а языке СПЕЦИФИКАЦИЙ мы бы сказали, что новая спецификация есть сужеl-luе (subsuтption) старо й, потому что любой конте й нер, удовлетворяющи й ново й специфи­ кации, также удовлетворяет и старой .

Если каждую из СПЕЦИФИКАЦИЙ рассматривать как предикат, сужение будет экви­ валентом логического следования (импликации). В стандартно й записи А В означает, что из утверждения А следует утверждение В, Т.е. если А истинно, то и В также истинно .

Применим эту логику к нашему распределению химикатов по контей нерам. Когда СПЕЦИФИКАЦИЯ изменяется, мы хотим знать, удовлетворяет ли новы й предложенный вариант всем условиям старого .

–  –  –

Тест для среды jUпi t может содержать такие строки .

drivingAge = new MinirnumAgeSpe c i f icat ion ( 1 6 ) ;

vot ingAge = new MinirnumAge Spe c i f i c a t i on ( 1 8 ) ;

ass ertTrue (vo t ingAge. subsurne s ( drivingAge ) ) ;

Еще один практический частны й случай, подходящи й для решения проблемы Спе ­ цифиKaции контейнера - это интерфей с СПЕЦИФИКАЦИИ, в котором комбинируются сужение и одна логическая операция и .

publ i c interface Spe c i f i ca t i on { bool ean i s S at i s f i edBy ( Obj ect c andidate ) ;

Spec i f i ca t i on and ( Spe c i f i ca t i on othe r ) ;

boo l e an subsurne s ( Spec i f i cat ion othe r ) ;

Доказать импликацию при наличии только операции И легко .

АИВА Можно взять и более сложный случай .

АИВИ САИВ

–  –  –

Э ту процедуру можно усовершенствовать, чтобы можно было сравнивать тщательно отоб ранные параметризованные СПЕЦИФИКАЦИИ-листья и учитывать некоторые другие осложнения. К сожалению, если присутствуют операции ИЛ И и Н Е, эти доказательства становятся намного сложнее. В о многих ситуациях такой сложности лучше из б егать, де­ л ая конкретный вы бор: отказать ся либо от некоторых операций, либ о от сужения. Если же ни б ез того, ни без другого не об ой тись, серьезно подумай те, настолько ли велик ожи­ даемый эффект, чтоб ы оправдать трудности реализации .

–  –  –

Углы атаки В это й главе б ыл о представлено немало разных приемов, помогающих прояснить смысл кода, сделать очевидными последствия его выполнения, уменьшить зависимость между элементами модели. Но проектирование архитектуры программ в таком стиле все равно остается непростым делом. Нельзя взять огромную, сложную программную сис­ тему и сказать: "Давай те-ка сделаем ее ги бкой ". Н ужно правильно поставить цели. Ниже рассказано о несколь ких об щих подходах, а затем приведен б ольшо й пример, где показа­ но, как сочетать архитектурные шаблоны и на их основе строить большую систему .

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

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

П олезнее нанести решающи й удар в одно й области и тем самым сделать часть арх и­ тектуры де й ствительно гиб ко й. О выб оре подобластей и работе с ними подробнее гово­ рится в главе 1 5 .

252 Ч АСТЬ 1 1 1. УГЛУБЛЯЮЩИЙ РЕФАКТОРИНГ Использование сложившихся формальных систем Созданием строгой системы понятий "с нуля " приходится заниматься не так уж часто .

Б ывает, что в ходе проекта удается разыскать и усовершенствовать нечто в этом роде. Но ведь использовать и адаптировать к своим потребностям можно и такие системы понятий, которые давно существуют в данной предметной области или какой -нибудь другой. Неко­ торые из этих систем совеРlпенствовались и дистиллировались в течение столетий. Напри­ мер, во многих коммерческих системах применяется бухгалтерский учет. В бухгалтерском учете существует ХОрОIПО проработанная система объектоВ-СУЩНОСТЕЙ и правил, которые способствуют легкой адаптации к углубленной модели и гибкой архитектуре .

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

Пример

Интеграция шаблонов : кредитная математика главе 8 рассказывалось, как удалось добиться качественного скачка в модели сис­ В темы для о бслуживания синдицированных кредитов. С е й час мы рассмотрим некоторые подробности, сосреДОТОЧИВIII И СЬ всего на одной особенности архитектуры, аналогично й той, которая применялась в УПОl\1инаВlпемся проекте .

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

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

–  –  –

Разделение команд и функций без побочных эффектов Б это й архитектуре уже присутствуют ИНФОРМАТИВНЫЕ ИНТЕРФЕЙСЫ (INTENTION­ REVEALING INTERFACES). НО метод d i s t r i but e Principal Payment ( ) делает опасную вещь: он и вычисляет доли в распределении, и модифицирует объект Кредит (Loan) .

Давай те выполним рефакторинг и отделим запрос от модификации .

–  –  –

Теперь клиентски й код будет выглядеть так .

Мар di s t ribut i on = aLoan. ca l cul ate Principal Payment Share s ( paymentAmount ) ;

aLoan. applyPrincipal Payment Share s ( d i s t r ibut i on } ;

Ч то ж, неплохо. Ф УНКЦИИ инкапсулируют значительную часть сложных вычисле­ НИЙ, скрытых за ИНФОРМАТИВНЫМИ ИНТЕРФЕЙСАМИ. Н о все-таки код начинает уве­ личиваться, когда мы до б авляем методы app lyDrawdown ( ) для вы б орки средств, calcul ateFee PaymentShare s ( ) для расчета долей в полученно й плате за пользо­ в ание кредитом и т.п. К аждое расширение усложняет и утяжеляет код. На этом этапе дроб ление кода, пожалу й, еще крупновато. О бычно вычислительные методы дополни­ тельно раз б иваются на процедуры. Э то и само по се бе может оказаться полезно. Но следует учесть, что нам в конечном счете нужно провести именно естественные, кон­ цептуальные границы, и тем самым углуб ить модель. Л ю б ые нео б ходимые варианты всегда можно составить из элементов архитектуры, раз б иение которых проведено по концептуальным границам .

Выведение неявныx понятОЙ в явные И так, у нас уже достаточно ин формации, чтоб ы начать " нащупывать " новую модель .

Объекты Доля ( Share) в этой реализации будут пассивными, и манипулировать ими мы будем сложными, низкоуровневыми способами. П ричина состоит в том, что б ольшая часть правил и вычислени й, касающихся доле й, относится не к отдельным долям, а к их группам. В модели пропущено важное понятие о том, как именно доли связаны друг с другом -- это части одного целого. Е сли сделать это понятие явным, правила и вычис­ ления можно будет формулировать б олее сжато и точно .

–  –  –

Здесь Распределение долей ( Share Pie) полностью описывает распределение Кредита (Loan) между кредиторами. В се вычисления, касающиеся вопросов распреде­ ления, можно делегировать объекту Распределение долей .

–  –  –

( \1/

–  –  –

И все-таки вычисления пока еще не стали б олее универсальными или простыми в ис­ пользовании .

Распределение долей как объект-значение: цепочка выводов Ч асто практически й опыт по реализации новой архитектуры дает толчок к новым вы­ водам относительно самой модели. В нашем случае тесная зависимость между кредитом (Loan) и Распределением допей (Share Pie) несколько затмевает взаимосвязь ме­ жду Распредеnениеи долей и самими ДолJIИИ ( Shares). Ч то будет, если сделать Распредеnение долей ОБЪЕКТОМ-ЗНАЧЕНИЕМ?

Методы i ncrease ( Мар ) и de crease ( Мар ) станут невозможны, поскольку Рас ­ пределение долей станет неизменяемым объектом. Чтоб ы изменить что-ни б удь в Распредеnении допей, его придется заменить целиком. Поэтому можно использо­ вать операцию наподоб ие addSharesMap ( ), которая бы возвращала целиком новое, б ольшее Распределение долей .

Проделаем остаВlпиеся шаги К ЗАМКНУТОСТИ О ПЕРАЦИЙ (CLOSURE OF OPERA­ TIONS). В место " увеличения " доли в Распределении долей или до бавления к нему дополнительно й Доли б удем просто складывать два Распределения долей и полу­ чать новое - б ольшее .

Ч астично можно замкнуть операцию пропорционального раздела prorate ( ) над Распределением долей, просто изменив тип возвращаемого значения. Переименовав ее в prorated ( ), мы изменяем желаемое на свершивши й ся факт и подчеркиваем отсут­ ствие поб очных эффектов. " Кредитная математика" начинает приобретать форму, пусть пока она и состоит всего из четырех операций .

–  –  –

ЗНАЧЕНИЯ, содержащие ФУНКЦИИ БЕЗ ПОБОЧНЫХ ЭФФЕКТОВ. Б олыпая часть сложных вычислител ьных операци й спрятана в этих неизменяемых о бъектах. П о­ скол ьку Распределения долей являются ОБЪЕКТАМИ-ЗНАЧЕНИЯМИ, математи­ ческие операции могут создават ь новые экземпляры таких объектов, которыми можно свободно заменять устаревшие .

Ни один из методов Распредепения долей ничего не меняет в СУIцеСТВУIощем объекте. Это позволяет свободно пользоваться методами pl us ( ), minus ( ) и prorate ( ) в промежуточных вычислениях, сочетая их как угодно и ожидая от них предсказуемого по их именам результата, но ничего б олее. На основе этих же методов теперь можно развивать аналитические возможности. (Ранее их можно бы­ ло вызывать только после создания фактического распределения, поскольку при каждом вызове данные изменялись.) Операции, изменяющие состояние, просты и характеризуются УТВЕРЖДЕНИЯМИ • (ASSERTIONS). В ысоки й уровень абстрагирования в " кредитно й математике " по­ зволяет записывать инварианты транзакций кратко и в декларативном стиле. На­ пример, отклонение от обязательств равно фактическому распределению долей минус выплаченная сумма Креди-zaа (Loan), разделенная в пропорции на основе Распределения долеЙ (Shаrе Pie) в Предприятии (Fac i l i ty) .

Понятия модели сделаны взаимно независu.мъl.МИ; в операции вовлекается минимум • данных разных типов. Н екоторые методы в Распределении долей (Share Pie) демонстрируют ЗАМКНУТОСТЬ ОПЕРАЦИЙ (методы сложения или вычитания замкнуты относительно таких РаспределеНИЙ). В других методах в качестве ар­ гументов или возвращаемых значений используются просто суммы денег. Эти операции не замкнуты, но дополнительно й концептуал ь ной нагрузки не несут .

Распределение долей (Share Pie) тесно взаимодей ствует только с одним классом - Долей (Share). В итоге класс Распределение долей стал самодос­ таточным, легко понятным, легко тестируемым и столь же легко ком б инируемым в декларативные транзакции. В се эти " черты " унаследованы от математического формализма .

Знакомый характер фОРМШlизации делает рабочий протокол леzко nО1lЯтНblМ .

• Теоретически можно б ыло б ы построить совер шенно оригинальны й протокол об ­ ращения с долями в кредите, взяв за основу финансовую терминологию. В принци­ пе так можно было бы даже построить достаточно гибкую структуру. Н о в такой ар­ хитектуре б ыло бы два недостатка. В о-первых, ее пришлось б ы творчески разраба­ тывать, изобретать, что само по себе задача трудная и неопределенная. В о-вторых, ее ЧАСТЬ 111. УГЛУБЛЯЮЩИЙ РЕФАКТОРИНГ пришлось б ы изучать с нуля всякому, кто захотел бы иметь с ней дело. Л юди же, сталкивающиеся с " кредитной математикой ", узнают в ней уже знакомую им сис­ тему, которая не вводит их в заблуждение благодаря тому, что архитектура тща­ тельно выстроена в соответствии с правилами арифметики .

Отделив ту часть проблемы, которая соответствует математическому формализму, мы получили ги б кую архитектуру Допей (Shares), которая позволяет далее дистилли­ ровать ключевые методы Кредита (Loan) и Предприятия (Fac i l i ty). ( С м. в главе 1 S раздел, посвященный смысловому ядру, или CORE DOMAIN.) Гибкость архитектуры оказывает огромное влияние на способ ность программы адап­ тироваться к изменениям и усложнениям. Как показали примеры из это й главы, она воз­ никает чаще всего благодаря весьма детальному моделированию и тщательному вы бору проектных архитектурных решени й. Э ффект от всего этого может вы й ти далеко за рамки конкретной про блемы моделирования и проектирования. В главе 1 S будет рассматри­ ваться стратегическое значение ги б ко й архитектуры как одного из нескольких инстру­ ментов дистилляции модели предметно й области, позволяющих превратить большо й и сложны й проект в нечто о б озримое, поддающееся о б раб отке .

ГЛАВА 1 0. ГИБКАЯ АРХИТЕКТУРА ГЛАВА 1 1

–  –  –

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

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

По сравнению с фундаментальными Iпаблонами структурных элементов программ, представленными в части 1 1, и принципами проектирования гибкой архитектуры из гла­ вы 1 0, эти шаблоны относятся к более высокому YPOBHIO И более специализированы;

в них для представления некоторо й концепции ком бинируются несколько объектов .

Благодаря им можно " проскочить" этап проб и ОIIIи бок, сразу начав с модели достаточно выразительно й, хорошо реализуеl\10Й и отвечающей тонким неочевидным требованиям, на изучение которых может у йти много усилий. Начиная с это й отправной точки, мы выполняем рефакторинг и :экспериментируем, потому что это еще не готовые стандарт­ ные решения с конвей ера .

Мартин Ф аулер (Martin Fowler) в книге Analysis Patterns: RеиsаЫе Object Models " Аналитические шаблоны: объектные модели многократного использования " ) опреде­ ( ляет такие шаблоны следующим о бразом [ 1 1 ] .

Аналитические шаблоны 1 - это группы nОllятий ШlИ КОllцеnций, nредстав­ ляющие часто исnользуеМУ10 конструкцию (или логическое построение) в моделировании прикладной деяmельuости. Эта КО1lструкция может отuо ­ ситъся как к одной, так и сразу к llесколькu.м предметным областям .

Представленные М. Ф аулером шаблоны возникли из опыта в данно й о бласти, поэто­ му они вполне практичны, если их правильно применить к ситуации. Э ти шаблоны пре­ доставляют тому, кому предстоит работать с непростой предметной о бластью, это - цен­ ные " отправные точки " для запуска итерационного процесса разработки. С амо название 1 Возможно, это и не самый удачный перевод. Иначе это выражение можно толковать как "схема, образец анализа". Анализ в данной книге понимается узко - как аналитическая часть раз­ работки программы, изучение проблемы с цель ю построения модели. Прu.меч. перев .

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

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

Когда мы вuедряем uовую nрактику [в бухгалтерском учете], мы создаем сеть иовьа примеров для того или иuого правила проводки через бухгGJlтер­ ские кuиги. Мы делаем это без nерекомnuляции и пересборки системы - оиа по-прежнему эксплуатируется в рабочем режиме. В иекоторых случаях мы ие можем обойтись без введеuuя иового подтипа правила проводки, ио это очень редкая оказия .

Б зрелом, давно разрабатываемом проекте, из опыта раб оты с приложением часто можно понять, какие именно варианты модели в нем реализованы, какие проектные ре­ шения приняты. В таких случаях апроб ируется много разных реализаци й всевозможных компонентов, некоторые из них б удут работать в финально й версии и даже доживут до стадии доработки в ходе эксплуатации. П ри наличии этого опыта можно из бежать мно­ гих про блем. Аналитические шаблоны способны помочь в переносе этого опыта из дру­ гих проектов. П ри работе с ними наличие углубленных знани й о модели сочетается с ин­ тенсивными дискуссиями по проектным решениям и последствиям тех или иных вари­ антов реализации. Е сли о бсуждать идеи модели вне этого контекста, они становятся сложнее в применении, и возникает риск опасного разрыва между анал изом и проекти­ рованием, а это полная противоположность ПРОЕКТИРОВАНИЮ ПО МОДЕЛИ (MODEL­ DRIVEN DESIGN) .

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

Аналитические шаблоны будут описаны ровно в том о бъеме, который нужен для пони­ мания примеров. Здесь не предпринимается попытка каталогизировать шаблоны этого типа или даже полностью описать те, которые вы браны для примеров. М ы ставим перед собо й цель проиллюстрировать их интеграцию в процесс предметно-ориентированного проектирования программ .

Пример

Получение процентного дохода по счетам В главе 1 0 б ыло рассказано о нескольких способах, которыми разработчик может до­ биться углубления своей модели, созданной для реализации узкоспециализированного финансового приложения. Здесь предлагается еще один сценари й. В этот раз программи­ сту предстоит искать полезные идеи в книге М. Ф аулера ( М. Fowler) A nalysis Pattel1zs ( "Аналитические шаблоны " ) .

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

–  –  –

Рис. 1 1. 1. Первоuачальuая диаграм.ма 1Ulассов Разраб отчик принимает решение прочитать главу 6 из вышеупомянуто й книги под названием " I nventory and Accounti ng" ( " У правление запасами и бухгалтерски й учет " ) .

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

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

–  –  –

Счет можно пополнить до бавлением Записи ( En t ry) в бухгалтерскую книгу. Можно списать сумму со счета, доб авив отрицательную Запись (Entry). Э ти Записи никогда не удаляются из книг, так что сохраняется полная история изменени й. Б ухгалтерский баланс представляет собой совокупны й эффект всех Записей. Б аланс можно по требо­ ванию рассчитать или выдать наличными - это проектное решение инкапсулируется интерфейсом Счет (Account) .

ГЛАВА 1 1. П РИМЕНЕНИЕ АНАЛИТИЧЕСКИХ ШАБЛОНО В

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

Деньги не появляются из ниоткуда и не исчезаIОТ без следа. О ни только переходят с од­ ного Счета на другой .

–  –  –

Э тот закон по сути выражает и известная концепция двойной бухгалтерской записи (двой ной итальянской бухгалтерии): у каждого кредита есть соответствующи й дебет .

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

В книге М. Ф аулера предлагаются более СЛО)КlIые и проработанные виды таких моде­ л ей, а также много говорится о б их относительных преимущсствах и недостатках .

Прочитав все это, программист (Прогр. 1 ) приходит к некоторым новым умозаклю­ чениям. О н2 показывает главу из книги коллеге (Прогр. 2), который работал с ним над реализацией алгоритмов вычисления процентов и написал запускаемы й каждую ночь пакетны й процесс. В месте они наб росали модификации к модели, включив в нее некото­ рые элементы, о которых прочитали .

–  –  –

266 ЧАСТЬ 111. УГЛУБЛЯЮЩИЙ РЕФАКТОРИНГ Прогр. 1. В этой новой модели мы делаем новую Запись (Entry) для проводки по Процентноиу счету ( Intere s t Account), а не просто изменяем величину суммы процентного дохода к поступлению на счет ( intere stDueAmount). З атем для поддер­ жания баланса вносится еще одна Запись, касающаяся выполненного платежа .

Спец. П олучается, теперь мы сможем видеть всю историю процентных начислени й так же, как и историю платежей ? Мы давно хотели получить такую возможность .

Прогр. 2. П о-моему, мы не вполне правильно используем данную "Транзакцию" .

В определении говорится о переводе средств с одного Счета (Account) на друго й, а не о б алансе двух записе й на одном и том же Счету .

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

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

Прогр. 1. То есть, это может быть тупиковый вариант. Я тут подумал, что стоит опреде­ лить некоторые неявные понятия. Так, будет информативнее, если именно :калькулятор процентов ( Intere s t Calculator) будет создавать объекты-Записи (Entry). А Тран­ закция, по-моему, " изящно " связывает вычисляемые проценты с платежами по ним .

Спец. З ачем нам связывать начисления с платежами ? Э то отдельные проводки бух­ галтерской системы. С амое главное - баланс на Счету. Он, да еще наб ор отдельных За ­ писей - вот все, что нам нужно .

Прогр. 2. В ы имеете в виду, что не следите, проведена ли выплата процентов ?

Спец. Н ет, следим, конечно. Но все не так просто, как нарисованная вами схема " одно начисление - один платеж " .

Прогр. 2. В ооб ще-то, если из бавиться от это й взаимосвязи и больше о ней не беспо­ коиться, это многое б ы упростило .

Прогр. 1. Л адно, а что если так? [Берет копию старой диаZРGJИ.М,ы юzассов и начинает набрасывать из.менеuия.] Кстати, вы несколько раз употребили слово " начисления " (accruals). Не могли б ы вы о бъяснить подроб нее?

Спец. К онечно. Начисление - это дей ствие по учету прихода или расхода средств вне зависимости от того, когда именно деньги переходят из рук в руки. Так что мы начисля­ ем проценты кажды й день, а платеж выполняется один раз в конце месяца (к примеру) .

Прогр. 1. Да, дей ствительно, такое слово нам не помешает. И как же это выглядит?

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

–  –  –

Спец. А вот это весьма неплохо !

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

Прогр. 1. Чтоб ы запустить новый калыcлsIторp процентов ( Interest Саlсиlа­ tor), потребуется несколько дней. Н ужно поменять довольно многое в тестах, но, в конце концов, они станут более наглядными .

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

Записи (Entri es) б ыли подразделены на ПЛатежи (Payment) и Начисления (Accrual), поскольку тщательное исследование показало, что у этих категори й записей в приложении несколько разные о бязанности. К тому же и то, и другое - важные поня­ тия предметной области. С другой стороны, между Записями нет никакой принципи­ ально й или функционально й разницы в том смысле, относятся ли они к сборам или про­ центам - они просто соответствуют тому или иному Счету .

К сожалению, получилось так, что разработчики вынуждены б ыли отказаться от это й последней абстракции из соображени й реализации. Д анные хранились в реляционно й таблице, и стандарты проекта требовали, чтоб ы эта таблица поддавал ась интерпретации б ез запуска программы. Это означало, что записи о с борах и о процентах должны был и храниться в отдельных таблицах. Е динственны й спосо б, каким программисты могли это реализовать, используя со бственны й механизм о бъектно-реляционного отоб ражения, это ввести частные подклассы ПЛатеж сбора (Рее Payment), ПЛатеж npоценl1'ОВ ( Interes t Payment) и т.д. Будь у них другая инфраструктура, этого неуклюжего рас­ ширения можно б ыло б ы из б ежать .

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

–  –  –

Новая архитектура оказалась значительно проще для анализа и тестирования, потому что большая часть ее сложных операций была вынесена в ФУНКЦИИ БЕЗ ПОБОЧНЫХ ЭФФЕКТОВ. Оставшаяся командно-директивная часть состоит из самого простого кода (потому что вызывает много ФУНКЦИЙ) и характеризуется контрольными УТВЕРЖДЕ­ НИЯМИ (ЛSSЕRТIОNS) .

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

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

Пример (продолжение )

Изучаем пакетный сценарий После нескольких недель работы модель на основе объекта Счет (Account) стала, наконец, вырисовываться. Как это часто бывает, из-за наглядности новой архитектуры стали более очевидными другие недостатки. Один из разработчиков (Программист 2), которы й адаптировал ночной сценари й для взаимодействия с ново й архитектуро й, начал

ГЛАВА 1 1. ПРИМЕНЕНИ Е АНАЛИТИЧЕСКИХ ШАБЛОНО В

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

Правила бухгалтерской проводки В системах бухгалтерского учета часто предлагается много вариантов представления одно й и той же финансовой информации. Н а одном счету может вестись учет дохода, то­ гда как на другом - расчетного налога на этот доход. Е сли от системы требуется автома­ тически о б новлять налоговы й счет, то реализация этих двух счетов становится в высшей степени взаимосвязанной. СущеСТВУIОТ системы, в которых б ольшинство б ухгалтерских записе й ( проводок) выполняется по таким регламентам; в них сеть взаимосвязе й неиз­ б ежно превращается в кашу. Даже в более скромных по масштабам системах выполнять все эти перекрестные проводки б ывает пепросто. П ервы й шаг к тому, чтоб ы о буздать паутину взаимосвязе й - это сформулировать регламентныIe правила явно, введя для этого новы й о бъект .

–  –  –

Правило проводки (Posting Rule) включается в работу новой Записью (Entry) на ее " входящем " счету. З атем оно порождает новую Запись на основе ее собственного рас­ четного Метода (Method) и добавляет ее на " исходящий" Счет (Account). В системе уче­ та заработной платы добавление Записи на счет фонда зарплаты, например, может активи­ зировать правило проводки, которое начисляет 30% расчетного подоходного налога и помещает эту цифру в виде Записи на Счет, предназначенный для вычета налогов .

Выполнение правил проводки Правило проводки (Po s t ing Rul e) устанавливает концептуальную связь между различными Счетами (Accounts), но если бы на этом аналитически й шаблон и закон­ чился, следовать ему было б ы нелегко. Одна из главных сложностей при проектировании взаимосвязей - это управление о б новлениями, в том числе расчет времени для них .

Ф аулер рассматривает три варианта .

1. "Немедлеuuый запуск" - наи более очевидны й, но на практике не слишком удачный .

Как только Запись (Entry) поступает на Счет, она немедленно активизирует Правило проводки (Po s t ing Rul e), и все об новления выполняются сразу же .

2. "Запуск со Счета" вариант, при котором обработка задерживается. В какой -то мо­ мент о бъекту Счет посылается сообщение, и он активизирует свои Правила про ­ :водки, чтоб ы об работать все Записи, добавленные после предыдушего запуска .

наконец, "uезавuCUМ,ый запуск Правила проводки" инициируется внешним аген ­

3. И том, который отдает распоряжение, когда подключать нужное правило. Правило ЧАСТЬ 1 1 1. УГЛУБЛЯЮЩИЙ РЕФАКТОРИНГ npоводIИ отвечает за то, чтобы найти все Записи, поступившие на " входящие" Сче ­ та с последнего запуска .

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

До бавление трех режимов запуска в ЕДИНЫЙ ЯЗЫК так же важно для успешной реа­ лизации шаблона, как и сами определения о бъектов модели. Этим устраняется неодно­ значность в принятии решений, и оно сводится к четко определенному набору возмож­ ных вариантов. З нание трех указанных режимов позволяет увидеть нетривиальную про­ блему и о богащает словарь нужными терминами для осмысленной дискуссии .

Программисту 2 необходимо б ыло озвучить его новые идеи в устной дискуссии. О н встретился с коллегой (Программистом 1 ), которы й в основном и отвечал за моделиро­ вание начислений .

Прогр. 2. Б какой -то момент пакетный сценарий превратился в нечто наподобие той бы, из которой никогда не выносят сор. Б операциях сценария неявно заключена алго­ из ритмическая логика предметной области, и он становится все сложнее и сложнее. Я уже давно мечтаю перепроектировать этот сценари й на основе модели, выделить в нем уро­ вень предметной области, сделать сам сценарий простым уровнем над предметной обла­ стью. Н о я так и не смог понять, какова, соб ственно, сама эта модель. Кажется, что все сводится к набору неких процедур, которые в виде объектов не имеют особого смысла .

Ч итая главу по Правилам npоводки (Posting Rule) в книге о б аналитических шаб ­ лонах, я пришел к некоторым идеям. Б от что я придумал. [Передает рисунок. ]

–  –  –

Рис. 1 1.9. Попытка реШluзоватъ Правила проводжи (Ров ting Rul ев) в nакетном сценарии Прогр. 1. Ч то такое эта Служба проводки (Posting Servi ce)?

Прогр. 2. Э то ФАСАДНЫЙ МЕТОД (FACADE), который представляет прикладной про­ граммный интерфейс (API) программы бухучета в виде СЛУЖБЫ (SERVICE). Я фактиче­ ски создал его уже довольно давно, чтобы упростить код сценария, и он предоставил мне также ИI-IФОРМАТИВНЫЙ ИНТЕРФЕЙС ( INTENTION-REVEALING INTERFACE) для проводок через старую систему .

–  –  –

ГЛАВА 1 1. П Р И МЕНЕНИ Е АНАЛИТИЧЕСКИХ ШАБЛОНОВ 273 Аналитич еские шаблоны как источник знания Если вам даже и повезло иметь аналитический IпаБЛОII для вашего случая, он вряд ли окажется готовым решением конкретной задачи .

И все же он предлагает ценные "путеводные подсказки", а также XOPOIUO абстрагированный словарь. Кроме того, из ана­ л итического luаблона l\10ЖНО почерпнуть сведения о последствиях его реализации, кото­ рые могут сэкономить лишние усилия .

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

Есть одна разновидность модификации шаблона, которой следует избегать. Исполь­ зуя термин из хорошо известного аналитического [паблона, старайтесь оставить нетро­ нутыми его фундаментальные понятия, пусть даже изменения и кажутся совсем поверх­ ностными. Для этого есть две причины. Во- первых, в rпаблоне может заКЛIочаться такое понимание проблемы, которое поможет вам избежать неприятностей. Во-вторых, что ЕДИI-IЫЙ язык важнее, ваш совершенствуется, когда в него добавляются термины либо широко распространенные, либо хотя бы хорошо описанные. Если определения в вашей модели изменяются в ходе ее естественной эволюции, не забудьте внести изменения и в имена с названиями .

Об объектных моделях написано довольно много. Некоторые из них специализиро­ ваны под один вид приложений в одной отрасли знания, а другие могут быть довольно общими. В большинстве из них содержится зерно некоей идеи, но только в некоторых передан ход рассуждений, стоящий за проектными реIпениями, и последствия этих ре­ шений, а именно это - самое важное в аналитических шаблонах. Было бы неплохо иметь побольше таких усовершенствованных аналитических Iпаблонов - это помогло бы нам и снова. Я буду очень удивлен, если когда-нибудь появит­ не изобретать велосипед снова ся универсальный каталог шаблонов, но по отдельным отраслям знания такие каталоги из вполне могут сформироваться. И JпаБЛОI lЫ некоторых пред:метных областей, где пере­ секается множество приложений, вполне могут получить Illирокое распространение .

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

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

ЧАСТЬ 111. УГЛУБЛЯЮЩИЙ РЕФАКТОРИНГ ГЛАВА 1 2

–  –  –

Понятие о том, что собою представляет и чего не представляет шаблон, индивидуально и зависит от точки зрения. То, что для одного - полноцен­ ный шаблон, другому может nоказаться nримитивным структурным "кирпичиком " nрограм..мы. В этой книге мы занимаемся шаблонами на опре­ деленном уровне абстракции. Говоря об архитектурных шаблонах, мы не имеем в виду такие архитектурные элементы, как связанные списки UJlи хэш-таблицы, которые можно оформить в виде Юlассов и переносить, куда потребуется, в готовом виде. Но это и не сложные специализированные ар­ хитектуры для целого nрШlОЖe1lUЯ UJlи подсистемы. Архитектурные шабло­ ны из этой книги представляют собой описания способов взаимодействия между обьектами и классами, адаптированные для решения общей задачи архитектурного nроектированuя в конкретном контексте [14J .

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

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

В дополнение к шаблонам из книги Design Patterns за много лет накопилось и опубли­ ковано множество других технических шаблонов. Некоторые из них соответствуют уг­ лубленным понятиям, возникающим в разных предметных областях. Хорошо, когда есть возможность пользоваться готовыми результатами. Но чтобы применить такие шаблоны в предметно-ориентированном проектировании программ, необходимо рассматривать их сразу на двух уровнях. На одном уровне это технические архитектурные образцы для на­ писания корректного кода. На другом - это концептуальные структуры в модели пред­ метной области .

Чтобы показать, как шаблон, возникший в качестве архитектурного, может применять­ ся в модели предметной области, а также прояснить разницу между техническим шаблоном и концептуальным шаблоном предметной области, мы воспользуемся конкретными приDesign Patterns. На при мере шаблонов COMPOSITE (КОМПОЗИТ) и мерами из книги (СТРАТЕгия) 1 будет продемонстрировано, как можно применить классический STRATEGY архитектурный шаблон в предметной области, посмотрев на него под другим углом.. .

Стр атегия

–  –  –

Onределuте семейство алгоритмов, uнкаnсулuруйте каждый из них u сделайте их взаuмоза.мен.яемыJUU. СТРАТЕгия2 позволяет изменять алгоритм, 1le влияя па КJlll.e1lmOB, обращающихся к нему [14J

–  –  –

1 В английском язы ке это слово звуч и т несколько менее "высокопарно" и с меньшим размахом, чем по-русс ки - скорее, как система прав ил, рекомендаций, норм, ПРИНЦИПОВ. - Прu.меч. перев .

2 В названии раздела фи гурирует также синоним этого термина - policy, дословно "политика", а п о смыслу набор критериев и требова н и й. - Прu.меч. перев .

276 ЧАСТЬ 1 1 1. УГЛУБЛЯЮЩИЙ РЕФАКТОРИНГ в ражается программной реализации. Потребность в отделении изменчивой, многовари­ антной части процесса от более стабильной его составляющей присутствует и здесь .

Выделите изменчивую часть процесса в отдельный объект- " стратегию " вашей мо­ дели. Отделите правило от операций, которыми оно управляет. Реализуйте правило или подставляемый процесс, следуя архитектурному шаблону СТРАТЕГИЯ ( STRATEGY) .

Несколько версий такого о бъекта представляют различные способы, которыми можно реализовать процесс .

Обычно СТРАТЕГИЮ понимают ЛИllIЬ как технический шаблон, суть которого сос тав­ ляет возможность подставлять разные алгоритмы. Но при его использовании в качестве шаблона предметной области основной интерес представляет его способность выражать или понятие, концепцию -- обычно это процесс нормативное правило .

Пример

Процедуры определения маршрутов ВСлужбу маршрутизации (Routing Service) передается Спецификация мар ­ шрута (Route Speci fication), и там конструируется подробный Путь следования ( I tinerary), удовлетворяющий данной СПЕЦИФИКАЦИИ. Данная СЛУЖБА является ме­ ханизмом оптимизации, который можно настроить на поиск либо самого быстрого, либо самого дешевого маршрута .

–  –  –

.

–  –  –

278 ЧАСТЬ 111. УГЛУБЛЯЮЩИЙ РЕФАКТОРИНГ *** Чтобы использовать технический архитектурный шаблон на уровне предметной об­ ласти, необходимо ввести дополнительную мотивацию, еще один уровень смысла. Если СТРАТЕГИЯ соответствует реальной стратегии, Т.е .

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

последствия Тут в полной мере " включаются" применения архитектурного шаблона .

Например, в книге [ 1 4] подчеркнуто, что клиент должен быть осведомлен о наличии раз­ СТРАТЕГИЙ, а это уже дополнительная проблема в моделировании. Есть и чисто тех­ ных ническая проблема реализации: наличие СТРАТЕГИЙ может увеличить количество объек­ тов в приложении. Если это важно, то дополнительные затраты можно снизить, реализо­ вав СТРАТЕГИИ как объекты без состояния, которые могут совместно использоваться разными контекстами. Здесь применимы разнообразные методики реализации, подробно рассмотренные в упомянутой книге. Но главное, что мы не отказываемся от использова­ СТРАТЕГИЙ .

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

Ко мпозит

–  –  –

Компонуйте обьекты в древовидные структуры, представляя иерархии "от части к целому ". КОМПОЗИТ (COMPOSITE)3 позволяет клиентам единообразно восnринu.матъ как отделъные обьекты, так u их комбинации [14J Часто при моделировании сложных предметных областей нам встречаются важные объекты, составленные из частей, которые в свою очередь составлены из частей, а те тоже составлены из частей и т.д. - иногда вложение может иметь произвольную глубину .

В некоторых областях знания уровни вложенности принципиально отличаются, но ИНО

–  –  –

ГЛА ВА 1 2. ШАБЛОН Ы и МОДЕЛЬ 279 гда бывает так, что любую часть целого можно считать примерно тем же, что и целое, только в меньшем масштабе .

Если в модели не отражена родственная связь между вложенными контейнерами, то на каждом уровне иерархии приходится дублировать одни и те же операции, и тоrда вложенность является жесткой ( например, контейнеры обычно не могут содержать другие контейнеры своего уровня, и количество уровней фиксировано). Клиентам приходится взаимодействовать с разными уровнями иерархии через разные интерфей­ сы, хотя разницы, принципиальной для клиента, между ними может и не быть. Затруд­ нительной является рекурсия по иерархии для сбора агрегированной информации .

Применяя любой из архитектурных шаблонов на уровне предметной области, прежде всего, стоит задуматься о том, насколько хорошо идея шаблона соответствует понятию из этой области. Допустим, нам удобно рекурсивно передвигаться по ассоциированным объектам, но действительно ли они образуют иерархию " от части к целому"? Удалось ли нам найти абстракцию, в которой все части на самом деле принадлежат к одному концеп­ и композит сделает эти аспекты туальному типу? Если да, то модели более четкими яс­ ными, позволяя в то же время проникнуть в глубины тщательно продуманной архитек­ туры и в технические соображения, лежащие в основе данного шаблона .

Определите абстрактный тип, заключающий в себе все члены КОМПОЗИТА. ДЛЯ возвращения агрегированной информации о содержимом ко нтейнеров в них реализу­ ются специальные методы. Узлы-"листья " реализуют эти методы в соответствии со значениями своих собственных атрибутов. Клиенты имеют дело с абстрактным типом и не обязаны отличать контейнеры от "листьев " дерева .

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

Композит (COM POSITE) предлагает одинаковое поведение объектов на каждом струк­ турном уровне. Как к малым, так и к большим частям можно обращаться с запросами, ответы на которые будут отражать их состав. Эта строгая симметрия является ключевой особенностью, придающей шаблону его силу .

Пример

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

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

Маршрут (Route) на Используя эту модель, разработчики могут создавать объекты основании запросов-заказов. У них есть возможность включать Участки (Legs ) в опе­ рационный план пошаговой манипуляции грузом. И тут они кое-что обнаружат .

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

Но оказалось, что специалисты по перевозкам воспринимают маршрут как последо­ вательность из пяти логических сегментов .

–  –  –

/ /

–  –  –

///,//) / \, //)

-

–  –  –

) ___ __

–  –  –

---.-.. .

* *

–  –  –

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

Объектная модель, в которой все это учтено, изрядно усложняется .

–  –  –

--

-- 0-

--

-

–  –  –

Если маршруты состаВЛЯIОТСЯ из других маршрутов, соединяемых друг с другом кон ­ цами с целыо достаВКII груза из одного пункта в другой, это позволяет достичь в про­ грамме любой желаемой степени детализации. МО)lПiО отрезать конец маршрута и при­ к ставить нему другой, l'vIОЖНО вложить маршруты на KaKYIO угодно глубину, можно вве­ сти в модель полезные параметры самого разного свойства .

–  –  –

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

***

–  –  –

я не собираюсь здесь составлять список архитектурных шаблонов, которые могут ис­ пользоваться в качестве lпаблонов уровня предметной области. Хотя трудно себе пред­ ( ИНТЕРПРЕТАТОР) ставить, например, использование шаблона INTERPRETER на уровне предметной области, все же не рискну заявить, что такой предметной области совсем не может быть. Единственное требование к шаблону состоит в том, чтобы он сообщал нечто концептуальное о предметной области, а не был бы просто техническим решением тех­ нической проблемы .

–  –  –

у глубляющи й рефакторинг 1 - это многогранны й процесс. Чтобы свести воедино некоторые основные моменты, остаНОВИl'vIСЯ на l'vI ИНУТКУ и оглянемся на про й ­ денное. Акцент нужно сделать на следующих трех принципах .

1. " Жить " Б преДl'vIетно й области .

П остоянно смотреть на вещи под разными углами .

2 .

П оддерживать непрекращающи йся диалог со специалистами .

3 .

Поиски глубокого ПОНИl'vI ания предметной области всегда расширяют контекст для рефакторинга .

Согласно классическому сценаРИIО рефакторинга, один-два программиста сидят за клавиатурой, ИIДУТ фраГl'vIенты кода, которые можно усовершенствовать, и сразу же вно­ сят в них изменения (конечно, проперяя результаты модульными тестами). Такое нужно практиковать постоянно, однако это еще не все .

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

Инициировани е Углубляющи й рефакторинг может начинаться разными способами. Э то может быть ответ на проблему в коде - какую-то сложность или неудобство. В место того чтобы вне­ сти в код стандартные в таких случаях изменения, разработчики считаlОТ, что суть про­ блемы заКЛlочается в модели преДl'vIетной области. В озможно, пропущено важное поня­ тие, а мо)кет быть, какая-то взаимосвязь организована неправильно .

Если ото й ти от обычного ПОНИl'vIания рефакторинга, такая догадка может возникнуть даже тогда, когда с кодом, на первый взгляд, все в порядке, но язык модели кажется не­ достаточно согласованным со специалистаl'vI И в предметной области или же новые требо­ вания к програl'vIме не удовлеТВОРЯIОТСЯ естественным образом. Рефакторинг l'vI O)KeT стать и результаТОl'vI обучения, когда разработчик, выработавши й углубленное понимание предмета, видит ВОЗl'vI ОЖНОСТЬ построить более ясную или полезную модель .

Ч асто самая трудная и неопределенная задача состоит как раз в то l'vI, чтобы увидеть "очаг" проблемы. Когда это сделано, программисты могут целенаправленно подобрать 1 В оригинале автор пишет "refactoril1g to\vard deeper i nsight", что примерно означает "рефакто­ ринг в направлении более глубокого понимания сути". К сожалению, ВРЯД ли можно найти доста­ точно емкий и краткий русский перевод. Поэтому в книге употреБЛЯIОТСЯ выражения "рефакторинг по модели" и "углубляющий рефакторинг", примерно описываIощие авторский за­ мысел с разных сторон. Примеч. перев .

элементы новой rvIодели, провести " мозгово й штурм " совместно с коллегами и специали­ стами, извлечь пользу из систематизированного знания в виде аналитических или архи­ тектурных lпа блонов .

И сследователь ски е группы К аким б ы ни был источник неудовлетворенности, следующи й шаг - это поиск усо­ вершенствования, которое б ы придало модели eCTecTBeHHYIO и четкую коммуникатив­ ность. Не ИСКЛIочено, что для этого потреб уется самое небольшое изменение, которое лежит на поверхности и вносится в течение нескольких часов. Такие изrvIенения напоми­ HaIOT традиционны й рефакторинг. А вот поиск ново й модели вполне может отнять боль­ ше времени и потреб овать труда многих людей .

Инициаторы изrvIенени й вы б ирают пару-тро й ку програrvIМИСТОВ, которые владеIОТ адекватным проблеме образом мыслей, знакомы с предметно й областью или имеют хо­ РОIIlИ Й навык моделирования. Е сли в деле есть тонкости, о бязательно привлекается спе­ циалист в предrvIетно й о бласти. Группа из четырех-пяти человек идет в конференц-зал или кафе и там ведет " мозгово й штурм " длительностью от получаса до полутора часов .

О ни РИСУIОТ UМ L-диаграммы, пытаются про йти раб очие сценарии с применением объ ­ ектов. О ни до б иваются того, что б ы специалист понял модели и счел их полезными. Ко­ гда наконец в процесс е возникает нечто удовлетворительное, они возвращаются и пишут код. Или же они решаlОТ подождать и подумать над материалом в течение нескольких дней, возвращаются на ра бочие места и берутся за другие дела. Несколько дней спустя группа со бирается снова с той же целыо. В этот раз они уже более уверены в себе, " переварили " свои идеи и пришли к кое-каким заКЛlочениям. О ни возвращаIОТСЯ к ком­ пьютерам и пишут код для ново й архитектуры .

Е сть несколько КЛIочевых принципов, позволяющих сделать такую работу плодотворной .

Самоорганизация. Для исследования про блемы в архитектуре программы можно • на ходу собрать совсем не большую группу, которая пораб отает несколько дней и самораспустится. Н ет необ ходимости создавать долговременные и сложные ор­ ганизационные структуры .

Время и масштаб. Б олее-менее осмыслеННУIО архитектуру можно создать за два­ • три совещания, проведенные в течение нескольких дней. З атягивать дело не имеет смысла. Е сли вы застряли, может б ыть, вы взваливаете на се бя слишком много .

В озьмитесь за менее масштаб ны й аспект архитектуры и сосредоточьтесь на нем .

Единый ЯЗЫК. П ривлечение других членов группы - в частности, специалистов по • предмету - к " мозговому штурму " создает возмо)кность усовершенствоваться в ЕДИНОМ ЯЗЫКЕ ( UБIQUIТОUS LANGUAGE). Конечным результатом этих усилий становится усовершенствование самого этого ЯЗЫКА, которы й программисты бе­ рут на вооружение и формализуют в коде .

В преДЫДУIЦИХ главах книги б ыло приведено несколько диалогов, в которых про­ грамrvIИСТЫ со специалистами пытались найти более удачные модели. П олноценный се­ анс " мозгового штурма " динаrvIичен, не имеет четко й структуры и весьма продуктивен .

Пр едыдущие нара б отки Н е всегда приходится заново изобретать велосипед. В процессе " rvIОЗГОВОГО штурма" в поисках пропущенного понятия или лучшей модели потенциально возможно заимство­ вание идей из Лlо бых источников, которые затем комБИНИРУIОТСЯ с иrvIеющиrvIИСЯ знаниями и " перемалываются " до тех пор, пока не будут найдены ответы на теКУlцие вопросы .

288 ЧАСТЬ 1 1 1. УГЛУБЛЯЮЩИЙ РЕФАКТОРИНГ Можно брать идеи прямо из книг и других источников знани й непосредственно по предметной о бласти. Специалисты в это й о бласти, может быть, и не создали ни одной модели, пригодной для разработки программы, но, тем не менее, они организовали поня­ тия их системы и нашли ряд полезных абстракций. Е сли пустить процесс перераб отки знаний по этому пути, можно быстро получить качественный результат, который к тому же покажется знаКОl'vI ЫМ специалисту .

Иногда можно почерпнуть пользу из опыта предшественников, выраженного в форме аналитического шаблона. П олучение тако й информации в некоторой степени родственно чтению литературы о предметной о бласти, но в данном случае акценты смещены именно в сторону разраб отки программ, и знания основаны непосредственно на опыте внедрения програМl'vIНОГО о беспечения. В аналитических шаблонах могут содержаться тонкие поня­ тия модели, и они помогут вам из бежать многих оши бок. Но это не готовые рецепты " а-ля поваренная книга ", а " сырье " для процесса перераб отки знани й .

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

Аналогично, если в некоторо й части преДl'vIетно й области уместно применение о б ще­ принятого фОРl'vIализма, - например, арифметики или логики предикатов - то эту часть всегда можно выделить в отдельную и адаптировать для нее правила формально й систе­ мы. О тсюда возникают очень строгие и наглядные модели .

Архитектура ДЛЯ разраб отчик ов П рограммное о беспечение существует не только для пользователей, но также и для разработчиков. Разраб отчикам приходится интегрировать свой код с другими частями системы. О ни вносят в него изменения снова и снова в итерационном процессе. Углуб ­ ЛЯIОЩИ Й рефакторинг одновременно и приводит программу к гибко й архитектуре, и об ­ легчается именно такой архитектуро й .

Ги бкая архитектура (sиррlе design) сама передает заложенные в нее цели. Благодаря ей легко предсказать, что произойдет в результате выполнения кода, а следовательно, и что произо й дет в результате изменени й кода. Ги б кая архитектура помогает из б ежать умственного перенапряжения, в основном за счет снижения количества взаимосвязей и побочных эффектов. О на основывается на углубленно й модели предметной о бласти, ко­ торая доведена до самого мелкого мас штаба в местах, особенно критических для пользо­ вателя. Это позволяет до биться ги б кости там, где изменения наиб олее часты, и простоты в остальных местах .

Ра сч ет вр е мени Если вы ждете момента, когда изменение в программе будет безупречно обосновано, то вы ждете уже слишком долго. В аш проект уже влечет за со бо й материальные потери, а откладываемые ИЗl'vIенения будет внести еще тяжелее, поскольку код становится все сложнее, все теснее привязывается к другому коду .

Постоянный рефакторинг уже признан наиболее передовым подходом, best practice, к разработке программ, но большинство групп разработчиков все еще относится к нему на­ стороженно. Они осознают риск изменений в коде и стоимость времени программистов, тре­ буемого на эти изменения. Но труднее осознать риск, заключающий ся в сохранении неудоб­ ной архитектуры, и стоимость усилий по обходу ее неудобств. От разработчиков, которые хоГЛАВА 1 3. УГЛУБЛЯЮЩИЙ РЕФАКТОРИНГ 289 тят выполнить рефакторинг, часто требуют обосновать их желание. Это кажется разумным, но на самом деле такое требование делает и без того трудное дело практически невозможным, на корню пресекая рефакторинг или загоняя его в подполье. Разработка программного обес­ печения не является настолько предсказуемым делоrvI, чтобы преимущества внесения измене­ ний или стоимость отсутствия этих изменений можно бьшо точно подсчитать .

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

Поэтому смело идите на рефакторинг, если:

архитектура не отражает теКУIЦИХ представлени й группы о предметной области;

–  –  –

сделать их явными);

есть возможность сделать ваЖНУIО часть программно й архитектуры более гибкой • в раб оте .

В прочем, эта энергичная позиция не может оправдать совсем уж любое изменение в любое время. Н е занима йтесь рефакторингом за день до выпуска или сдачи программ­ ного продукта. Не внедря й те " гиб ких архитектур ", которые демонстрируют техническую виртуозность, но не передаlОТ самой сути предметной области. Н е вводите " углубленную модель ", в необходимости которой вы не можете убедить специалиста, пусть даже вам она кажется очень красивой. Н е возводите ничего в аб солют, но всегда жертвуй те ком­ фортом в пользу рефакторинга .

Кризис как потенциальная возможн о сть Б олее столетия после Чарлза Дарвина стандартная rvIодель ЭВОЛIОЦИИ заключалась в том, что виды изменялись постепенно, иногда усто йчиво, с течением времени. Н о вне­ запно в 1 970-е годы эту rvIодель вытеснила rvIодель точечного, или кусочного, равновесия (риnсtиаtеd еqиiliЬriиm). В новом взгляде на эволюцию длительные периоды постепенных изменени й или постоянства сменялись сравнительно кратковременными всплесками быстрых изменений. З атем все приходило в новое равновесие. В разработке программна­ го обеспечения есть сознательная направленность, которой не хватает ЭВОЛIОЦИИ (хотя по некоторым проектам этого не скажешь), но и она следует такому же ритму .

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

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

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

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

УглуБЛЯIОIЦИЙ рефакторинг - процесс бесконечный. Обнаруживаются и выводятся на явны й уровень неявные концепции. Тем или иным элементам програrvIМНОЙ архитек­ туры придается гибкость, временами основанная на декларативном стиле. Разработка внезапно приходит на грань прорыва и порождает углубленную модель, а затем вновь начинается rvIедленное, постепенное усовершенствование .

ЧАСТЬ 1 1 1. УГЛ УБЛЯ ЮЩИЙ РЕФАКТОРИНГ IV С т р ат егиче ск ое прое к т иров а ние Когда сложность системы возрастает до того, что ее уже невозможно знать на уровне ОТ­ дельных объектов, появляется потребность в специальных приемах для восприятия больших моделей и манипулирования ими .

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

В идеале корпоративная программная система, если она задумана с размахом, стремится превратиться в тесно интегрированную систему, охватываIОЩУЮ BCIO деятельность в данной отрасли знания. Но модель сразу всей предметной области, скорее всего, ОКaJкется СЛИIПКОМ большой и сложной как в управлении, так и в понимании единого целого для практически любой организации. Систему следует разбивать на меньшие части как с концептуальной точ­ ки зрения, так и для программной реализации. Сложность состоит в том, чтобы добиться та­ кой модульности, 1--te потеряв nрeuмуществ и1tтеграции отдельные части системы должны работать совместно, способствуя координированию различных прикладных операций. Моно­ литная и всеохватываIОЩая модель предметной области БыIаa бы слишком громоздкой, мес­ тами дублирующейся и полной неочевидных противоречий. Но набор небольших отдельных подсистем, соединенных через неединообразные интер{рейсы, " не потянет" решение задач в корпоративном масштабе. Кроме того, в каждой точке сопряжения будут постоянно возни­ кать проблемы совместимости и единообразия. Но ЛОВУUlек обеих крайностей можно избе­ жать, если планировать архитектуру систематически и lIостепенно .

Даже и в этом масштабе предметно-ориентированное проектиропание программ (domain-driven design) не порождает модели, совершенно оторванные от реализапии. I{аж­ дое проектное решение должно иметь прямое влияние на разработку системы, иначе непо­ нятно, зачем его вообще принимать. Конкретные архитектурные решения должны основы­ ваться на принципиальных стратегических решениях, чтобы уменьшить взаимозависи­ мость отдельных частей и улучшить наглядность работы системы, не теряя синергизма и критически важного взаимодей ствия. В се это должно продвигать модель к отражению концептуального ядра системы, ее " видению ". И все это l(1jж1tо делать, не тормозя nроект .

Тому, как достичь этих целей, и посвящена часть IV этой книги, где рассматриваются три обширные темы: контекстность, дистилляция, крупномасштабная структура .

Контекстность представляет собой наименее очевидный из трех принципов, но одно­ временно наиболее фундаментальный. Удачная модель, будь она большая или маленькая, должна быть логически непротиворечивой и единообразной, лишенной противоречий и перекрывающихся определений. Корпоративные системы часто интегрируют I Iодсисте­ мы из различных источников или содержат приложения столь различные, что мало какие элементы предметной области воспринимаются ими в одном свете. Может БыIь,' треб ова­ ние унифицировать модель во всех, даже категорически несоизмеримых, частях системы чрезмерно и невыполнимо. Н о моделировщик все же имеет возможность избежать даль­ ней шего вырождения модели. Для этого нужно явно определить ОГРАНИЧЕННЫЙ КОНТЕКСТ (BOUNDED CONTEXT), внутри которого применима модель, а затем при необхо­ димости определить его взаимосвязи с другими контекстами .

Дистилляция позволяет сосредоточить внимание на том, что НУЖНО. Часто много усили й тратится на второстепенные, перифери й ныс вопросы. Но всеобъемлющая модель цело й предметно й области должна подчеркнуть наиболее значительныI,' особые аспекты системы, и при этом иметь такую структуру, чтобы придать им максимаЛЬНУIО силу. Не­ которые вспомогательные компонентыI' конечно, бывают критически важны, но их сле­ дует ставить на положенное им место. Подобная ориентация моделирования не только позволяет направить усилия на самые важные части системы, но и предотвращаСl потеЧАСТЬ IV рю видения всей системы. С тратегическая дистилляция может сделать большую модель понятнее и нагляднее. А это позволяет спроектировать архитектуру СМЫСЛОВОГО ЯДРА (CORE DOMAIN) системы с наибольшей пользой для дела .

Картину завеРlп ает крупномасштабная структура. В очень сложной модели легко по­ терять лес за деревьями. Проблему частично решает дистилляция, помогая сосредото­ читься на главной, центральной части и представить остальные элементы во вспомога­ тельных ролях. Но взаимосвязи между ними все равно могут остаться слишком слож­ ными, если отсутствует "главная тема", если не применяются архитектурные формы и пrаблоны масштаба целой системы. В нашей книге будет дан обзор нескольких подходов к построению крупномасштабной структуры, а затем мы углубимся в детали одного из соответствующих шаблонов, УРОВНИ РАЗДЕЛЕНИЯ ОБЯЗАННОСТЕЙ (RESPONSIBILITY LAYERS), для изучения последствий применения такой структуры. Будут рассматривать­ ся только частные примеры; исчерпывающего каталога читатель здесь не найдет. Приду­ мывать новые структуры или развивать существующие следует по мере необходимости, эволюционно. Какая-то из этих структур окажется способной привнести в архитектуру такое единообразие, которое ускорит разработку и улучшит интеграцию .

Три перечисленных принципа, полезные даже по отдельности, но особенно мощные при совместном использовании, помогают строить хорошие архитектуры даже в доста­ точно хаотической системе, которую полностью никто не понимает. Крупномасштабная структура придает согласованность трудносовместимым фрагментам и помогает им стать одним целым. С труктуризация и дистилляция позволяют воспринимать и пони­ мать сложные взаимосвязи между отдельныIии частями, при этом удерживая в поле зре­ ния всю картину. ОГРАНИЧЕННЫЕ КОНТЕКСТЫ (BOUNDED CONTEXTS) дают возможность выполнять работу одновременно в разных частях системы без повреждения модели или ее нечаянного фрагментирования. Добавление всех этих понятий в ЕДИНЫЙ ЯЗЫК (UBIQUITOUS LANGUAGE) группы разработчиков поможет им выработать собственные принципиальные решения .

СТРАТЕГИЧЕСКОЕ П РОЕКТИРОВАНИЕ

ГЛАВА 1 4

–  –  –

К ак-то я работал в проекте, в котором новую большую систему параллельно разраба­ тывали несколько рабочих групп. в один прекрасный день группа, работавшая над модулем для выписывания клиентам счетов-фактур, собралась реализовать объект, который они назвали Charge (Платеж). И тут оказалось, что другая группа уже сконструировала та­ кой объект. П ервая группа решила прилежно перенести его к себе. Оказалось, что в нем нет "кода назначения платежа" (expense code), и его добавили. Там уже был нужный им атрибут " проводимая сумма" (posted аmоиnt), и хотя они планировали назвать его " сумма к оплате" (атоиnt dие), но изменили решение - в конце концов, так ли важно конкретное название?

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

Через несколько дней возникли загадочные проблемы в приложении-модуле опла­ ты счетов, для которого изначально был написан объект Charge (Платеж). Всплыли странные Платежи, которых никто не вводил и которые не имели никакого смысла .

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

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

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

Ч то же они сделали, узнав о существовании проблемы? О ни разработали отдельные классы ПЛатеж :клиента (Customer Charge) и ПЛатеж поставщику (Supplier Charge), определив каждый в соответствии с целями и задачами соответствующей группы. Решив непосредственную проблему, они вернулись к тому режиму работы, ко­ торы й практиковали и раньше .

Хотя мы редко задумываемся об этом, caMble фундаментальные требования к м о ­ дели состоят в том, чтобы она была самосогласованной, внутренне непротиворечи­ во й ; чтоБыI ее термины всегда имели одно и то же значение; и чтобы в модели не бы­ ло противоречивых правил. Самосогласованность модели, при которой каждыIй тер­ мин всегда имеет однозначны й смысл и ни одно правило не противоречит другому, называется УlluфuкацuеЙ. Если логической самосогласованности нет, модель как та­ ковая не имеет смысла. В идеальном мире у нас была бы одна модель, охватываIОlцая всю предметную область, в которо й работает корпоративное н риложение. Э та мо­ дель была бы унифицированной, не имела бы в нутрен них противоречи й или пересс­ кающихся определений терминов. Л юбое логическое утвеР)I(дение о предметной о б ­ ласти было бы непротиворечивым .

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

Иногда люди пытаются бороться с этой реальностыо. Большинство видит ту цену, которую приходится платить из-за ограниченной интегрированности и неудобств ком­ муникации между несколькими моделями. Кроме того, наличие нескольких моделей субъективно кажется некрасивым. Э то сопротивление ИСIlользоваНИIО нескольких моде­ лей иногда вызывает к жизни амбициозные попытки унифицировать все программное обеспечение в рамках одного проекта под эгидой единой модели. Я знаю этот грех и за собой. Н о рассмотрим же, чем это чревато .

1. Слишком много уже имеющегося кода придется одноврСl\lенно заменять на новый .

Большие проекты могут затормозиться из-за того, что дополнительная нагрузка по 2 .

управлению ими превзойдет имеIОIдиеся возможности .

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

И напротив, попытка удовлетворить всех одной моделью добавит в нее столько ва­ 4 .

риантов и параметров, что ею станет трудно пользоваться .

Более того, расхождения в моделях могут вызываться не только техническими со­ ображениями, но и политическим размежеванием или разногласиями в управленче­ ских предпочтениях. Возникновение разных моделей может б ыть и результатом орга­ низации группы и процесса разработки. Поэтому да)ке если никакие технические фак­ торы не мешаIОТ полной интеграции, в проекте ВСС равно может появиться набор разных моделе й .

Уже зная, что невозможно поддерживать унирицироваПНУIО модель для всего п р о­ ектного предприятия, тем не менее, не следует отдаваться воле случая. Четкую и еди­ ПУIО картину ПРОИСХОДЯlдего вполне можно построить, если принять ряд превентип

–  –  –

В больших проектах сосуществует сразу много моделей, и во многих случаях это вполне нормально. Разные модели применимы в разных контекстах. Например, вашу но­ вую программу может понадобиться интегрировать с внешней системой, над которой ваша группа не имеет контроля. Б такой ситуации наличие разных контекстов, в одном из которых разрабатываемая модель непригодна, не вызывает сомнений. Но другие си­ туации могут оказаться не столь очевидными. В истории, с которой начинается эта глава, две группы разработчиков занимались разными функциями одной и той же новой систе­ мы. Работали ли они ПО одной модели? В их намерения входило совместное использова­ ние по крайней мере некоторых своих наработок, но нигде не была провсдена граница между тем, чем они собирались и чем не собирались делиться с коллегами. У них также не было готовой процедуры совместного пользования моделью или оперативного выяв­ ления расхождений. О ни поняли, что разошлись в разные стороны, только тогда, когда поведение системы внезапно стало непредсказуемыI • .

Даже одна и та же группа может придти к необходимости нескольких моделей .

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

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

лю б ом крупн ом пр оекте во зн икает н ео бходимость работать с н е сколькими моде ­ В ля ми. Н о при ко мбинировании в одно целое кода, разработанного на осн ове сильно ОТ­ личающих ся моделей, программа становится н енаде жной, трудно й в понимании, склонно й к с боя м. З апутывается ко ммуникация между чл е нами группы. Часто бывает неп оня тн о, в как ом контек сте модель не должна применять ся .

298 Члсть IV. СТРАТЕГИЧЕСКОЕ П РОЕКТИРОВАНИЕ Неспособность организовать все просто и надежно в конце концов обнаруживается, когда получившийся код не хочет работать правильно. Однако проблема коренится еще и в способах организации рабочих групп, взаимодействии между их членами. Поэтому чтобы прояснить контекст модели, нам нужно рассмотреть одновременно и проект, и его конечный результат ( код, структуры баз данных и т.д.) .

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

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

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

Ограниченные контексты - это не модули Эти два понятия часто путают, но на самом деле это два разных шаблона с разной мотива­ цией их применения. Действительно, когда два разных набора объектов явно образуют разные модели, их почти всегда помещают в разные модули. Это позволяет организовать КОНТЕКСТОВ) разные пространства имен (что существенно для разных и создает некото­ рое разграничение .

Но модули также используются и для организации элементов одной модели; они не обя­ КОНТЕКСТЫ. Отдельные пространства имен, зательно выражаIОТ намерение разграничить ОГРАНИЧЕННЫХ КОНТЕКСТОВ, фактически препятствуют создаваемые модуля ми внутри обнаружеНИIО случайной фрагментации модели .

ОГР А НИЧЕННЫЙ КОНТЕКСТ ( BOUNDED CONTEXT) ставит пределы применимости той или иной модели, чтобы разраб отчики четко понимали (и разделяли это понимание ме­ жду собой), в чем следует поддерживать единообразие и согласованность, и как соотно­ сить это с другими КОНТЕКСТА МИ. В нутри данного КОНТЕКСТА старайтесь поддерживать модель в логически унифицированном виде, но не беспокойтесь о ее применимости вне установленных границ. В других контекстах применимыI другие модели, с другой терми­ нологией, понятиями и правилами, а также с другими диалектами ЕДИНОГО ЯЗЫКА. Про­ ведя четкую границу, вы сможете сохранить чистоту модели и, следовательно, ее мощь там, где она применима. Одновременно вы сможете избежать путаницы при переносе внимания на другие КОНТЕКСТЫ. Интеграция через границы неизбежно потребует ка­ кой-то разновидности трансляции, и этот вопрос можно будет проанализировать .

ГЛАВ А 1 4. ПОДДЕРЖАН ИЕ ЦЕЛОСТНОСТИ МОДЕЛИПример

Контекст заказа доставки грузов Компания по доставке грузов открыла свой внутренний проект по разработке нового приложения для заказа доставки. Э то приложение должно строиться на основе объектной модели. Каков ОГРАНИЧЕННЫЙ КОНТЕКСТ (BOUNDED CONТEXT), внутри которого эта мо­ дель будет применяться? Для ответа на этот вопрос надо посмотреть, что же происходит в проекте. Помните, что это взгляд на проект как 01l есть, а не каким он должен быть в идеале .

Одна из групп проекта работает над самим приложением заказа грузов. Э та группа не должна модифицировать объекты модели, но приложение, которое они пишут, должно отображать эти объекты и манипулировать ими. Данная группа разработчиков представ­ ляет собой потребителя модели. Модель является дей ствующей внутри этого приложе­ ния (основного потребителя). Е е границы задает именно это приложение для заказа дос­ тавки грузов .

З аполненные заказы передаются в ранее написанную систему отслеживания перевоз­ ки грузов. З аранее, еще до разработки, было решено, что новая модель будет отличаться от старо й, поэтому старая система находится вне ее границ. Н еобходимая трансляция (перевод понятий ) между новой моделью и старой системой возлагается на группу со­ провождения старо й системы. Механизм трансляции не управляется моделью и не про­ ектируется по ней. О н не находится в данном ОГРАНИЧЕННОМ КОНТЕКСТЕ. ( На самом деле он является частью границы, и об этом будет сказано при обсуждении КАРТЫ КОН­ ТЕКСТОВ, CONTEXT МАР.) ЭТО хорошо, что трансляция находится вне КОНТЕКСТА (не ос­ нована на модели). Б ыло бы непрактично просить группу сопровождения старой систе­ мы каким-либо образом пользоваться моделью, поскольку основные обязанности разра­ ботчиков лежат вне ее КОНТЕКСТА .

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

Еще одна группа работает над моделью и приложением для составления расписания й сов грузовых судов. Группа заказов и группа расписания были организованы одно­ ре временно, и обе группы намеревались построить одну унифицированную систему. Две группы в какой -то мере координировали свои усилия и время от времени "делились о бъ­ ектами ", но все это делалось несистематически. О ни lle работали в пределах одного ОГРАНИЧЕННОГО КОНТЕКСТА. В этом есть риск, поскольку сами они не считают, что ра­ ботают по разным моделям. В ходе интеграции их разработок обязательно возникнут проблемы, если только они не разработают специальные процедуры для решения этой проблемы. ( Хорошим вариантом может оказаться ОБЩЕЕ ЯДРО, SHARED KERNEL, которое рассматривается дальше в это й главе.) Н о первым шагом должно стать принятие ситуа­ ции как 01la есть. Группы не находятся в одном КОНТЕКСТЕ и должны избегать делиться кодом, пока ситуация не изменится .

Данный ОГРАНИЧЕННЫЙ КОНТЕКСТ состоит из всех аспектов системы, которые управ­ ляются этой моделью: объекты модели, структура базы данных, в которой эти объекты со­ храняются, а также само приложение заказа грузов. В этом КОНТЕКСТЕ в основном раб о­ тают две группы: группа моделирования и группа разработки приложения. Со старой системой отслеживания грузов необходимо обмениваться информацией, и на группу со­ провождения этой системы возложена обязанность обеспечивать трансляцию на граниЧлсть IV. СТРАТЕГИЧЕСКОЕ ПРОЕКТИРОВАНИЕ це. Группа моделирования же обязана оказывать им помощь. Между моделыо заказа дос­ тавки и моделыо расписания рейсов нет четко определенной взаимосвязи, и определение этой связи должно стать одной из первых задач обеих групп. А тем временем им нужно крайне осторожно делиться кодом или данными .

KaKYIO же пользу принесло определение данного ОГРАНИЧЕНI-IОГО КОНТЕКСТА?

Группам, работаюпих в этом КОНТЕКСТЕ, оно принесло ясность. Две группы теперь по­ пимаlОТ, что должны придерживаться одной модели. Они принимаlОТ проектные реше­ ния с учетом этого и тщательно следят за возможными расхождениями. Внешним груп­ пам определение KOI-ITEKCTA Ilринесло свободу. Они не должны теперь чувствовать себя в подвеlненном состоянии, не работая по той же модели, но чувствуя себя обязанными это делать. Но наиболее ощутимое достижение в данном случае - это, пожалуй, осозна­ ние риска неформального обмена информацией между группой моделирования заказов и группой моделирования расписания. Чтобы избежать проблем, группам придется взве­

–  –  –

Сами 110 себе границы ЯВЛЯIОТСЯ особыми местами. Взаимоотношения между ОГРАI-IИ­ ЧЕННЫМ КОНТЕКСТОМ (BOUNDED CONTEXT) и его соседями треБУIОТ внимания и осторож­ ности. Расчертить теРРИТОРИIО и ностроить крупномасштабную картину KOI-ITEKCTOB и связей между ними позволяет КАРТА КОНТЕКСТОВ (CONTEXT МАР), а еIце несколько шаб­ лонов опредеЛЯIОТ характер различных взаИМООТНОIIlений между КОНТЕКСТАМИ. Единство же модели внутри ограниченного контекста поддерживается при помощи процесса

НЕПРЕРЫВНОЙ ИНТЕГРАЦИИ (CONTINUOUS INTEGRATION) .

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

Распознавание дефектов внутри ограниченного контекста Временно не обнаруженные различия моделей могут проявляться в виде многих раз­ личных симптомов. Наиболее очевидные из них - несоответствие запрограммирован­ ных интер4)сЙсов. На более тонком уровне верным знаком является непредсказуемое по­ ведение программы. "Выловить" такого рода проблемы позволяет процесс I-IЕПРЕРЫВ­ ной ИНТЕГРАЦИИ (CONTINUOUS INTEGRATION) с автоматизированными тестами. А вот заблаговременным предупреждением может служить путаница в языке .

При комбинировании элементов различаЮIЦИХСЯ моделей возникает две категории проблем: дублирующиеся понятия (концепции) и ложные родственники. Дублирование понятий означает, что в модели есть два элемента (и две соотвеТСТВУЮIЦИХ программных реализации), которые на самом деле предстаВЛЯIОТ одно и то же понятие. Всякий раз, ко­ гда ин(l}ормация об этом понятии обновляется, ее приходится обновлять в двух местах .

Как только новые знания приводят к изменениям в одном из объектов, второй тоже нужно заново проанализировать и изменить. Только вот повторный анализ в реальности не происходит, так что в результате возникаlОТ два варианта одного и того же понятия, которые слеДУIОТ разным правилам и даже содержат разные данные. Помимо этого, раз­ работчикам приходится осваивать не один, а два способа делать одно и то же, ПЛIОС все нужные способы синхронизации между ними .

"Ложные родственники" встречаlОТСЯ несколько реже, но зато они более коварны .

В этом случае двое Лlодей, ПОЛЬЗУIОIЦИХСЯ одним и тем же термином (или программным объскгом), думаlОТ, что имеlОТ в виду одно и то же, а на самом деле это не так. Типичный ГЛАВА 14. ПОДДЕРЖАНИЕ ЦЕЛОСТI-IОСТИ МОДЕЛИ 301 пример приведен в начале главы (две разные прикладные операции ИСПОЛЬЗУIОТ объект ПЛатеж), но конфликт может быть еще менее заметен, если два определения действи­ тельно относятся к одному и тому же аспекту предметной области, но осмыслены и со­ ставлены несколько по-разному. Присутствие "ложных родственников" приводит к тому, что группы разработчиков вмешиваIОТСЯ в код друг друга, в базах данных появляются странные противоречия, а в общении внутри групп возникает путаница. Термин "ложные родственники" обычно применяется к естественным человеческим языкам1, Так, если англоязычный человек изучает испанский язык, он часто ошибается в употреб­ лении слова embarazada, думая по его внешнему виду, что оно означает embarrassed в женском роде (смущенная, пристыженная, сбитая с толку), тогда как на самом деле это "беременная". Ай, как неудобно получается!

Обнаружив TaKYIO проблему, группе разработчиков придется что-то решать. Возможно, понадобится временно "отозвать" модель из работы и усовершенствовать рабочие процеду­ ры, чтобы избежать фрагментирования. Но группы могут тащить модель каждая в свою сторону, вызывая тем самым ее фрагментирование, и по каким-то веским причинам. Тогда не ИСКЛlочено, что им лучше позволить вести разработку независимо. Решение таких во­ просов и составляет суть шаблонов, которые мы рассмотрим далыпе в этой главе .

Непрерывная интеграция

–  –  –

302 ЧАсть IV. СТРАТЕГИЧЕСКОЕ ПРОЕКТИРОВАНИЕ в конце концов приводит к тому, что в ней теряется полезный уровень ин­ КОНТЕКСТЫ теграции и связности .

Иногда программисты не вполне понимаlОТ назначение объекта или взаимосвязи, промоделированных кем-то другим, и изменяют их так, что они становятся непригодны­ ми для первоначального назначения. Иногда они не осознают, что понятие, над которым они работают, уже существует в другой части модели, так что они просто дублируют и само понятие, и его операции (причем неточно). Бывает, что разработчики даже знаlОТ об этих других выражениях нужных понятий, но боятся связываться с ними, чтобь] не по­ ломать то, что работает, и в итоге продолжают дублировать понятия и функции .

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

Но надо также застраховаться и от слишком осторожного поведения, - например, мно­ гократного дублирования функций программистами только из страха испортить рабо­ тающий код .

Именно в такой среде уместен подход экстремального программирования (Extreтe Prograттing, ХР). Многие приемы ХР нацелены на реПlение именно специфической про­ блемы поддержания связной архитектуры при том, что ее постоянно изменяет множест­ во людей. В чистом виде ХР - прекрасная методика поддержания целостности модели в пределах одного ОГРАНИЧЕННОГО КОНТЕКСТА. Однако несмотря на то, используется подход ХР или нет, все равно важно иметь в проекте какую-то процедуру НЕПРЕРЫВНОЙ

ИНТЕГРАЦИИ (CONTINUOUS INTEGRATION) .

НЕПРЕРЫВНАЯ Иl-IТЕГРАЦИЯ означает, что вся работа в пределах контекста сливается воедино и приводится в согласованный вид достаточно часто, чтобы даже при возникно­ вении смысловых дефектов они выявлялись и устранялись достаточно быстро .

I-IЕПРЕРЫВНАЯ :ИНТЕГРАЦИЯ, как и все остальное в предметно-ориентированном проек­ тировании, работает на двух уровнях: (1) интеграция понятий модели и (2) интеграция программной реализации .

Понятия и концепции интеГРИРУIОТСЯ путем постоянной коммуникации между чле­ нами рабочей группы. Такая группа должна культивировать совместное понимание не­ прерывно меняющейся модели. Тут помогает много приемов, но самый фундаменталь­ ный из них - постоянная доработка ЕДИНОГО ЯЗЫКА проекта. Между тем все написан­ ное программистами интегрируется воедино систематически проводимой процедурой сборки-компиляции-тестирования, которая позволяет выявлять дефекты в модели на ранних стадиях.

Для интеграции проекта используется много процедур, но большинство самых эффективных обладает слеДУIОЩИМИ характеристиками:

пошаговая, легко воспроизводимая технология сборки и компиляции;

• наличие наборов автоматизированных тестов;

• правила, опредеЛЯlощие временные рамки (достаточно непроДолжительные) для • существования неинтегрированных в оБЩУIО систему изменений .

Другой стороной медали Б эффективных процедурах интеграции является КОllцеnmу­ аЛЫ--lQЯ интеграция, хотя ее не часто определяют формально:

постоянная практика в ЕДИНОМ ЯЗЫКЕ проекта при обсуждении модели и прило­ • жения .

В большинстве Agile-проектов как минимум раз в день выполняется сборка измене­ ний кода, внесенных разными программистами. Частоту можно приспособить к кон­ кретному темпу разработки, лишь бы любое еlце не интегрированное изменение было

–  –  –

НЕПРЕРЫВНАЯ ИНТЕГРАЦИЯ (CONTINOOUS INTEGRATION) применима внутри любого отдельного ОГРАНИЧЕННОГО КОНТЕКСТА (BOONDED CONTEXT), превосходящего по раз­ меру работу двух человек. Она нацелена на поддержание целостности одиночной модели этого контекста. Но когда сосуществуют несколько ОГРАI-IИЧЕННЫХ КОНТЕКСТОВ, при­ ходится решать, каковы же взаимосвязи между ними, и проектировать соответствующие интерфейсы.. .

–  –  –

'

–  –  –

Ч Асть IV. СТРАТЕГИЧЕСКОЕ ПРОЕКТИРОВАНИЕ ми необходимо наличие связей, эти контексты имеют тенденцию "просачиваться" друг в друга .

Перенос кода из одного ОГРАНИЧЕННОГО КОНТЕКСТА в другой - это рискованное де­ ло. Интеграция функциональности и данных должна выполняться через траНСЛЯЦИIО .

Чтобы уменьшить путаницу, следует определить отношения между разными контекста­ ми и построить глобальный обзор контекстов для всего проекта .

КАРТА KOI-ITEKCTOB (CONTEXT МАР) - это средство, находящееся на стыке управле­ ния проектом и архитектурного проектирования. Естественный ход событий - совпаде­ ние границ контекстов с организационным делением группы. Люди, работаlощие вместе, естественным образом разделяют общий контекст модели. Члены разных групп или лю­ ДИ, не общающиеся между собой даже в составе одной группы, расходятся в различные контексты. Может иметь значение и физическое пространство офиса: так, члены группы, сидящие в разных концах здания, - не говоря уже о разных городах - наверняка разой­ дутся в контекстах, если не приложить особые усилия по интеграции. Большинство ру­ ководителей проектов интуитивно понимают эти факторы и организуют рабочие группы более или менее вокруг программных подсистем. Но простого наличия взаимосвязи ме­ жду организацией группы, моделыо и архитектурой программы еще недостаточно. Как разработчики, так и управленцы должны иметь четкое видение складывающегося кон­ цептуального подразделения модели и архитектуры .

Определите все модели, используемые в проекте, и задайте для каждой свой Учитывайте и неявные модели подсистем, не ЯWIяющихся

ОГРАНИЧЕННЫЙ КОНТЕКСТ .

объектно-ориентированными. Дайте каждому ОГРАНИЧЕННОМУ KOI-ITEKCTY имя и вюпо­ чите эти имена в ЕДИНЫЙ ЯЗЫК проекта .

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

Постройте карту уже существующей территории. Преобразованиями 3аЙметесь потом .

Внутри каждого ОГРАНИЧЕННОГО КОНТЕКСТА У вас будет свой самодостаточный диа­ лект ЕДИI-IОГО ЯЗЫКА. Имена ОГРАН ИЧЕННЫХ КОНТЕКСТОВ сами тоже войдут в ЕДИНЫЙ ЯЗЫК, чтобы можно было недвусмысленно выражаться относительно модели Jllобой из частей архитектуры, ясно задавая контекст разговора .

КАРТУ KOI-ITEKCTOB не обязательно документировать в какой-либо конкретной фор­ ме. Я считаlО, что достаТОЧНУIО выразительность и наглядность имеют схемы и диаграм­ МЫ, приведенные в этой главе. Кто-то другой может предпочесть текстовое представле­ ние или графические схемы другого типа. В каких-то ситуациях достаточно будет ВРО­ стого обсуждения между участниками группы. Детализацию мо)кно варьировать по потребностям. Но какую бы форму ни приняла карта, она должна быть известна и по­ нятна всем в проекте. Она должна задавать четкие имена для всех ОГРАНИЧЕI-IНЫХ КОНТЕКСТОВ, а также ясно обозначать их точки соприкосновения и оБIДИЙ характер .

** * Взаимосвязи и отношения между ОГРАНИЧЕНIIЫМИ КОНТЕКСТАМИ принимаlОТ много разных форм в зависимости как от организации, так и от архитектуры проекта. Позже в этой главе будут представлены различные шаблоны взаимосвязей между КОНТЕКСТАМИ, эффективные в разных ситуациях и предоставляющие терминологию для описания связей из ваших собственных КАРТ. Учитывая, что КАРТА КОНТЕКСТОВ всегда представляет ситуа­ цию такой, какой она есть, обнаруживаемые взаимосвязи вначале могут и не соответство­ вать упомянутым шаблонам. Если близость между ними достаточна, можно взять имя [паблона, но не навязывать его силой. Просто опишите TaKYlo взаимосвязь, KaKYlo вы хоти­ те. Позже можно будет начать двигаться к более стандартным отношениям .

ГЛАВА 14. ПОДДЕРЖАI-IИЕ ЦЕЛОСТI-IОСТИ МОДЕЛИ Итак, что же делать, если вы обнаружили смысловой дефект - все взаимосвязи в мо­ дели установлены, но при этом она содержит противоречия? Сосредоточьтесь на карте и заставьте себя закончить полное описание .

Затем, имея точный общий вид, займитесь местами проявления противоречий. Исправив небольшой дефект, можно ввести специ­ альные процедуры для поддержания целостности. Если какая-то связь не вполне ясна, можно выбрать близкий по смыслу шаблон, а затем "продвигаться" к нему. Ваша первая задача на повестке дня - построить чеТКУIО КАРТУ КОНТЕКСТОВ, а это может включать в себя решение некоторых реальных проблем, с которыми вы сталкиваетесь. Но не по­ зволяйте "мелкому ремонту" перейти в глобальную реорганизаЦИIО. Пока у вас нет чет­ кой КАРТЫ КОНТЕКСТОВ, которая распределяет BCIO ваIПУ работу по ОГРАI-IИЧЕННЫМ КОНТЕКСТАМ и задает явные отношения между всеми взаимосвязанными моделями, ис­ правляйте только самые ВОПИЮlцие противоречия .

Как только у вас появится полная КАРТ А КОНТЕКСТОВ, вы сами увидите места, в ко­ торые нужно внести изменения. Можно будет изменять как организацию групп, так и архитектуру системы. Помните: не вносите изменение в КАРТУ, пока оно не сделано в реальности .

Пример Два контекста в программе доставки грузов Мы снова возвраlцаемся к системе управления доставкой грузов. Одной из основных возможностей программы должна быть автоматическая марIIlрутизация грузов в момент заказа их доставки. СоотвеТСТВУIОlцая модель представляет собой примерно следующее .

–  –  –

ЛИРУlощая механизм, который стоит за ИНФОРМАТИВНЫМ ИНТЕРФЕЙСОМ (INTENTION­ REVEALING INTERFACE) и состоит из ФУНКЦИЙ БЕЗ ПОБОЧ]IЫХ ЭФФ ЕКТОВ (SIDE-EFFECT­ FREE FUNCTIONS). Результаты работы этих функций характеРИЗУIОТСЯ КОI-IТРОЛЬНЫМИ УТВЕРЖДЕНИЯМИ (ASSERTIONS) .

–  –  –

Здесь ничего не говорится о том, как выполнить эту очень СЛОЖНУIО задачу. Давайте заглянем за кулисы, чтобы увидеть механизм .

1lервоначально, работая в проекте, на основе которого построен этот пример, я был чрезмерно догматичен по ОТНОlпеНИIО к внутренней реализации Службы маршрутиза­ ции (Routing Service). Я хотел, чтобы фактическая марIнрутизация выполнялась с использованием расширенной модели предметной области, в которой бы прсдставля­ лись рейсы судов, непосредственно привязанные к Участкам (Legs) Пути следова­ ния (Itinerary). Но группа, работаВlпая над маршрутизацией, сообщила, что решение следует реализовать в виде оптимизируемой транспортной сети, где каждый участок рейса представлялся БЪJ элеllентом V зволяло привлечь ХОрОIПО известные, стандартные алгоритмы. Они настаивали на созда­ нии специальной модели для операций доставки груза в этом случае .

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

По сути, мы создали два отдельных ОГРАНИЧЕННЫХ KOI-ITEKCTA, в каждом из которых операции доставки груза были организованы концептуально по-разному (рис. 14.3) .

Наше требование заКЛlочалось в том, чтобы запрос к Службе маршрутизации (Routing Service) перевести (транслировать) в термины, понятные Службе трас­ сировки по транспортной сети (Network Traversal Service), затем получить от нее результат и транслировать его в (1)OpMY, ожидаСМУIО от Службы маршрутизации Это означает, что нет необходимости устанавливать полное соответствие между дву­ мя моделями, а достаточно определить только две трансляции .

–  –  –

Для этого нужно выяснить назначение элемента в одной модели и найти способ выра­ зить его через понятия другой .

Что касается первой трансляции (Спецификация маршрута Список), необходи­ мо подумать, какой смысл имеет последовательность местоположений в списке. Первый пункт списка - это начало пути; затем маршрут дол)кеll пройти по очереди через все пункты, пока не достигнет последнего в списке. Итак, lVlecTo отправления и место назна­ чения ЯВЛЯIОТСЯ первым и последним пунктами списка, а в середине находятся пункты растаможивания (если таковые есть) .

(К счастыо, две группы использовали одни и те же коды местоположений, так что не нужно вводить траНСЛЯЦИIО хотя бы на этом уровне.) Следует отметить, что обратная трансляция является нсоднозначной, потому что на вход трассировки по транспортной сети можно подавать Лlобое количество промежуточ­ ных пунктов, не обязательно пунктов фактического раС1аможивания. К счастыо, это не проблема, потому что в этом направлении выполнять трансляцию не надо. Но все же следует быть в курсе, почему некоторые трансляции невозможны .

–  –  –

Теперь давайте транслируем результат (Список номеров Узлов ---7 ПУТЬ следова ­ ния). Предполагаем, что для поиска объектов Узел (Node) и Перевозка (Shipping Qperation) 110 полученным нами идентификационным номерам Узлов мы можем вос­ пользоваться ХРАI-IИЛИЩЕМ. Итак, как же Узлы (Nodes) соответствуют Участкам (Legs)? На основе атрибута operationType мы можем разбить список Узлов па пары "пункт отправления пункт прибытия". Каждую пару затем можно поставить в СООТВС1ствие одному участку .

–  –  –

Это и есть концептуальная карта трансляции между двумя моделями. Теперь нужно реализовать в программе что-то, что будет выполнять эту траНСЛЯЦИIО само. В простом случае наподобие этого для такой цели обычно создается специальный объект, а потом находится или создается еще один объект, который будет оказывать эту услугу осталь­ ной части подсистемы .

–  –  –

Неплохо. ОГРАНИЧЕННЫЕ КОНТЕКСТЫ помогли сохранить каЖДУIО из моделей в ОТ­ носительно чистом виде, позволили каждой из групп работать в значительной мере неза­ висимо, и если первоначальные допущения были правильными, то контексты выполни­ ли свою задачу. (Мы еще вернемся к ним в этой главе. ) Интерфейс между двумя контекстами довольно невелик. Интерфейс Службы мар­ шрутизации (Routing Service) изолирует остальную часть архитектуры КОНТЕКСТА заказа грузов от событий, происходящих в мире маршрутизации. Этот интерфейс легко тестировать, потому что состоит он из ФУН КILИЙ БЕЗ ПОБОЧНЫХ ЭФФ ЕКТОВ (SIDE­ EFFECT-FREE FUNCTIONS). Один из секретов комфортного сосуществования с другими КОНТЕКСТАМ И состоит в том, чтобы иметь для всех интерфейсов эффективные наборы тестов. Как говорил президент Рейган во время переговоров о сокращении вооружений, "доверяй, но проверяй" 2 .

Построить набор автоматизированных тестов, которые передаIОТ СпецифИIaциIO мар­ шрута (Route Specification) в Службу маршрутизации (Routing Service), а затем проверить возвращаемый Путь следования (Itinerary), не должно составить труда .

2 РоналЬД Рейган перевел старинную русскую поговорку, которая точно описала происходящее с обеими переговаривающимися сторонами и это еще о дна метафора, выражающая СУТЬ отноше­ ний между контекстами .

ЧАсть IV. СТРАТЕГИЧЕСКОЕ ПРОЕКТИРОВАНИЕ Контексты моделей существуют всегда, но без сознательного внимания к ним они мо­ гут пересекаться и дрейфовать. Определив ОГРАНИЧЕННЫЕ КОНТЕКСТЫ (BOUNDED CONTEXTS) и КАРТУ КОНТЕКСТОВ (CONTEXT МАР), ваша рабочая группа сможет начать управлять процессом унификации моделей и организацией связи между теми из них, ко­ торые должны остаться различными .

Тестирование в границах контекста Особое значение имеет тестирование точек соприкосновения между ОГРАНИЧЕННЫМИ КОНТЕКСТАМИ. Тесты помогают прояснить тонкости трансляции и компенсировать ухуд­ шение коммуникации, которое обычно происходит на границе. Тестирование может слу­ жить системой раннего предупреждения, особенно полезной в случаях, когда вы зависите от подробностей устройства модели, над которой не имеете власти .

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

ОГРАНИЧЕННЫЕ КОНТЕКСТЫ должны иметь имена, чтобы на них можно было ссы­ t .

латься при обсуждении. Эти имена должны войти в ЕДИНЫЙ ЯЗЫК группы разра­ ботчиков .

Бсе разработчики должны знать, где пролегают границы, и уметь распознать 2 .

КОНТЕКСТ ЛIобого фрагмента кода в любой ситуации .

Второе требование можно удовлетворить многими способами в зависимости от уров­ НЯ культуры в рабочей группе. Как только ОГРАНИЧЕННЫЕ КОНТЕКСТЫ определены, ес­ тественным образом происходит распределение кода разных КОНТЕКСТОВ по разным МОДУЛЯМ. Это порождает проблему определения и учета того, какой МОДУЛЬ принад­ лежит к какому КОНТЕКСТУ. ДЛЯ ее решения можно задать правила имен или любой дру­ гой простой механизм, предотвращающий путаницу .

В той же степени важно так описать концептуальные границы, чтобы все разработчики понимали их одинаково. В качестве таких описаний l\ПIе нравятся неформальные схемы, показанные в вышеприведенном примере. Можно составить более строгие схемы или тек­ стовые описания, перечислив все пакеты в каждом КОНТЕКСТЕ вместе с точками соприкос­ новения и механизмами связи и трансляции. Некоторьп..1 группам будет легче работать так, а другим будет достаточно устных договоренностей и активных обсуждений .

В любом случае, если имена контекстов добавляются в ЕДИНЫЙ ЯЗЫК, то и ввести КАРТЫ КОНТЕКСТОВ в обсуждение имеет смысл. Не говорите так: "То, что делает группа Джорджа, изменилось, поэтому и нам надо изменить то у нас, что к нему привязано" .

Выражайтесь так: "Модель Т ра1lсnортной сети меняется, поэтому нам следует внести изменения в транслятор для контекста Заказа грузов" .

Взаимосвязи между ограниченными контекстами в рассматриваемых далее шаблонах предлагаются подходы и методики для установ­ ления взаимосвязей между двумя моделями, которые совместно могут покрыть всю кор­ поративную предметную область. Эти шаблоны ВЫПОЛНЯIОТ сразу две задачи: задают це­ ли для успешной организации процесса разработки и предлагают словарь для описания той организации, которая уже существует в настоящее время .

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

ГЛАВА 14. ПОДДЕРЖАНИЕ ЦЕЛОСТН ОСТИ МОДЕЛИ

терминах, не забывая указать отличия и вариации. Затем постепенно, неболыuими мо­ дификациями, можно п риб лизить эту взаимосвязь к выбранному шаблону .

С другой стороны, может оказаться и так, 4ТО исходная взаимосвязь СЛИIПКОМ неоп­ ределенна или усложнена. Может потребоваться некоторая реорганизация, просто для того чтобь[ построить четкую КАРТУ КО НТЕКСТО В. В этой ситуации или в любой другой, где возникает мысль о реорганизации, описываемые здесь IпаБЛОIlЫ предлагаIОТ набор вариантов, пригодных в тех или иных обстоятельствах. Варьироваться может уровень вашего контроля над каждой из моделей, объем и способ сотрудничества между рабочи­ ми группами, степень интеграции функциональности и данных .

Набор lнаблонов, предлагаемых дanее, охватывает наиболее распространенные и важные случаи, а в других случаях из них можно почеРПНУ1Ь общий подход. ВЬJСОКОКВалифициро­ ванные разработчики, в активном сотрудничестве создаIОIЦИС тесно интегрированный про­ дукт, спосоБныI построить большую унифицироваННУlО модель. I-Iеобходимость удовлетво­ рить потребности разных сообществ пользователей ил:и ограниченные возможности по коор­ динации в группе могут потребовать связей типа ОБIПЕГО ЯДРА (SIIARED KERNEL) или ЗАКАЗЧ1IК-ПОСТАВЩИК (CUSTOMER/SUPPLIER). Иногда, если пристanьно присмотреться к требованиям, то оказывается, что интеграция не так уж 11 нужна 1I что для данныIx копкретных систем более целесообразно ОТДЕЛЬНОЕ СУЩЕСТВОВАНИЕ (SEPAH.ATE WAYS). Большинство lIpoeKToB приходится в какой-то степени интегрировать со старыIии и внеНIНИМИ системами, что приводит К применению ПРЕДОХРАНИТЕЛЬНЫХ УРОВНЕЙ (ANTICOH.H.UPTION LAYRS) и СЛУ)КБ С открыты1M ПРОТОКОЛОМ (OPEN HOST SRRVICRS) .

Общее ядро

–  –  –

lIJИМИ, особенно сли у рабочих групп не хватает квалиq)икации И.IИ организованности, чтобы се поддерживать, или же если единая группа разрабо гчиков СJlИIIIКОМ велика [-l I1судобна в управлении. Тогда можно определить отдельные ОГРАНИЧЕННЫЕ KOflTEKCTbI (BOUNDED CONTEXTS) и сформировать несколько отдельных рабочих групп .

* * * Нескоординированные группы, работающие над близко связанными прило жения­ ми, могут поначалу взять хороший темп, но затем результаты их работы могут н е со­ сгыковаться. Тогда они потратят бол ьше времен и на трансляционные уровни и реорга­ н изацию кода, чем с самого начала потратили бы на I-IЕПРЕРЫВНУЮ ИJ-JТЕГРАЦИЮ, к тому же дубл ируя усилия и утратив пре имущества обладания ЕЛИНЫМ языкоrvl .

Члсть IV. СТРАТЕГИЧЕСКОЕПРОЕКТИРОВЛНИЕ Во многих проектах я видел, как инфраструктурный уровень использовался совмест­ но ГРУI[паlИ, которые n остальном работали независимо. Аналогично можно работать и в пределах предметнuй области. Полная синхронизация всей модели и базы кода может потребовать СJlИШКОf MHOl'O усилий, а вот Тlцательно отобранное ее подмножество может сохранить многие преимущества при снижении затрат .

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

Выполняйте интеграцию функциональной системы достаточно часто, но не так час­ то, как IIЕПРЕРЫВНУК) ИНТЕГРАНИЮ внутри групп. При каждой такой интеграции за­ пускайте тесты обеих групп .

Так создается разумный баланс. ОБЩЕЕ ЯДРО (SHARED KERNEL) нельзя изменять так часто, как другие части архитектуры. Принятие решений не может обходиться без кон­ сультаций с другой группой. Наборы аВТОIатизироваJlНЫХ тестов следует интегрировать в одно целое, потому что при внесении изменений должны выполняться все тесты обеих групп. Обычно рабочие группы вносят изменения в разные копии ЯДРА, выполняя инте­ грацию между собой через некоторые интервалы. (Например, для группы, выполняющей HElIPEPbIBHYIO ИНТЕГРАЦИIО ежедневно или чаще, нормальный ритм слияния измене­ ний в О БlJ{Еl\tl ЯДРt еженедельный. ) Но вне зависимости от графика интеграции кода, чем чаlце группы обсуждают свои изменения, тем лучше .

* ** ОБЩЕЕ ЯДРО (SHARI:'..D KERNt:L) часто представляет собой СМ ЫСЛОВОЕ ЯДРО предмет­ ной области (CORE [)OMAIN ), набор ЕСТЕСТВЕННЫХ ПОДОБЛАСТЕЙ (GENERIC SUB­ DOMAINS ) или то и другое одновременно (см. главу 15). Но в принципе оно может пред­ ставлять собой любую часть модсли, которая требуется каждой из двух рабочих групп .

Здесь ставится цель умеНЫIIИТЬ дублирование работы (но не полностью устранить его, как это было бы в случае одного ОГРАНИЧЕННОI'О КОНТЕКСТА) и сделать интеграцию между двумя подсистемами сравнительно простой .

Группы "заказчик-поставщик" Часто бывает так, что одна подсистема фактически подает что-то на вход другой, снабжает ее данными. "НИ){(lIИЙ" КОМIIОНСНТ выполняст анализ или другие функции, КОЛАВА 14. ПОДДЕРЖАНИЕ JЕЛОСТI-IОСТИ МОДЕЛИ торые мало что передают в "верхний" компонент, так что все зависимости и взаимосвязи идут в одном направленииЗ. Две подсистемы обычно предназначены для очень разных сообществ пользователей, которые занимаются разной деятельностью, моделируемой разными способами. Различными могут быть и средства разработки, так что код таких приложений невозможно переносить, объединять, совместно использовать .

* * * Верхняя и нижняя подсистемы естественным образом разделяются на два различных ОГРАI--IИЧЕННЫХ КОНТЕКСТА (BOUNDED CONTEXTS). Особенно верно это для случаев, ко­ гда два компонента требуют разных навыков или реализуются разными программными средствами. Трансляция в одну сторону проще, чем в обе. I-Io в зависимости от взаимо­ отношений между двумя группами могут возникать и проблемы .

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

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

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

В проектах, выполняемых по методике экстремального программирования, уже есть механизм точно для этой цели: процесс итерационного планирования. Все, что нужно сделать, - это определить отношения между двумя группами с точки зрения процесса планирования. Представители нижней группы могут выступать в качестве представите­ лей пользователя: присутствовать на сеансах планирования, непосредственно обсуждать преДСТОЯlцие задачи как полноправные "заказчики" продукции, сопоставлять преимуще­ ства и недостатки решений. Так возникает итерационный план для группы-поставщика, содержащий задачи, как первоочередные для нижней группы, так и отложенные, по ко­ торым пока не ожидается результата .

Если используется отличная от экстремального программирования методология, можно взять какую-нибудь аналогичную методику для балансирования lIотребностей разных пользователей и усовершенствовать ее так, чтобы учесть потребности ПРИJIоже­ ния нижней группы .

Определите четкие отношеlDlЯ "заказчик-поставщик" между двумя группами. На сеан­ сах планирования нижняя группа должна играть роль закаЗ'ПIКа по отношенmo к верхней .

нижней Обсуждайте и распределяйте задачи согласно требованиям гpymIыI' чтобы каждый в группе имел представлеlDlе об обязательствах и временном графlШе раБотыI .

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

–  –  –

3 14 Члсть IV. СТРАТЕГИЧЕСКОЕПРОЕКТИРОВАНИЕ В ходе итерационного процесса члены нижней группы разработчиков должны быть так же "доступны" верхней группе для контакта, как обычные заказчики для оперативно­ го ответа на вопросы и решения проблем .

Автоматизация приемочных тестов - важнейшая часть отношений такого вида. Даже в проекте с самым тесным сотрудничеством, где заказчик может определить и сообщить поставщику все нужные взаимосвязи, а поставщик изо всех сил пытается донести до за­ казчика сделанные изменения, без тестов все равно случаются сюрпризы. Эти сюрпризы меПlают работе нижних разработчиков, а верхних заставляют срочно вносить исправле­ ния, не предусмотренныIe графиком. Вместо этого нужно сделать так, чтобы группа­ заказчик, совместно с группой-поставщиком, разработала автоматические приемочные тесты, проверяющие на правильность требуемый интерфейс. Верхняя группа должна выполнять эти тесты в составе своего стандартного набора тестов. Любые изменения в этих тестах требуют согласования с другой группой, поскольку изменения в тестах тре­ буют изменений в интерфейсе .

ОТНОIIlения "заказчик-постаВIЦИК" также возникают между проектами в отдельных компаниях - в тех ситуациях, когда какой-то один заказчик очень важен для дела постав­ щика. Здесь хвост начинает вилять собакой: влиятельный заказчик может выдвигать такие требования, которые важны для успеха верхнего проекта, но они также могут нарушить процесс разработки верхнего проекта. Обе стороны выигрывают от формализации процес­ са отклика на требования, потому что соотношение затрат и выгоды еще труднее разглядеть в отношениях с внешними партнерами, чем внутри одного IТ-проекта .

В этом стратегическом шаблоне есть два ключевых момента .

ОТНОIIlения заказчика и поставщика подразумевают, что потребности заказчика од­ 1 .

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

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

Должен существовать набор автоматизированных тестов, который позволяет верх­ 2 .

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

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

Пример

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

ГЛАВА 14. ПОДДЕРЖАНИЕ ЦЕЛОСТНОСТИ МОДЕЛ И 315 Для подобного анализа специалисты используют свои собственные сложные модели .

Для вычислительной реализации они пользуются хранилищем данных (data warehouse) со средствами построения аналитических моделей. И им требуется очень много инфор­ мации из приложения оформления заказов (Booking) .

С самого начала было ясно, что это два отдельных ОГРАНИЧЕННЫХ КОНТЕКСТА (BOUNDED CONTEXTS), потому что в них используются разные средства программной реализации и, что еще важнее, разные модели предметной области. Каковы же должны быть отношения и связи между ними?

Может показаться логичным ввести ОБЩЕЕ ЯДРО (SHARED KERNEL), потому что в анализе доходности потребуется какое-то подмножество модели заказа, к тому же в их собственной модели имеются пересекающиеся понятия грузов, цен и т.п. Но ОБЩЕЕ ЯДРО малопригодно в случаях, когда используются разные технологии реализации. Кро­ ме того, запросы у группы анализа доходности очень специфические, они все время экс­ периментируют со своими моделями и вводят альтернативные. Может быть, им будет лучше транслировать все необходимое из КОНТЕКСТА приложения заказа в свой собст­ венный. (С другой стороны, если бы они смогли воспользоваться ОБЩИМ ЯДРОМ, бремя трансляции значительно облегчилось бы. Конечно, потребовалось бы реализовать мо­ дель заново и транслировать данные в новую реализаЦИIО, но если модель одна и та же, этот переход не должен оказаться слишком сложным.) Приложение заказа грузов никак не зависит от анализа доходности, потому что ника­ кая автоматическая коррекция деловой стратегии здесь не предусмотрена. Специалисты­ люди принимают решения и сообщают их соответствующим работникам и программным системам. Так что у нас четко присутствует отношение "сверху-вниз". Внизу от "верхов" требуется следующее .

Кое-какие данные, ненужные ни для каких операций заказа/резервирования .

1 .

Определенная стабильность в структуре базы данных (или, по крайней мере, на­ 2 .

дежная система оповещения об изменениях) или же наличие утилиты экспортиро­ вания .

К счастью, руководитель проекта по разработке приложения заказа грузов заинтере­ сован помочь группе анализа доходности. Здесь могла бы возникнуть проблема, по­ скольку операционный отдел, который выполняет повседневную работу по резервирова­ НИIО заказов, подотчетен не тому вице-президенту, которому подчинена группа анализа доходности. Но более высокое начальство выказывает заинтересованность в таком ана­ лизе. Поэтому данный проект организован таким образом, чтобы руководители обеих групп были подотчетны одному и тому же ответственному лицу .

Итак, все требования для применения шаблона, именуемого ГРУППЫ РАЗРАБОТЧИКОВ "ЗАКАЗЧИК - ПОСТ АВI1ИК " (CUSTOMER/SUPPLIER DEVELOPER TEAMS), удовлетворены .

Я видел в нескольких местах, как события развивались именно по этому сценарию, т.е. разработчики аналитической и операционной подсистем вырабатывали именно от­ НОIIlения "заказчик-поставщик". Когда члены верхней группы разработчиков считали, что их задача -.. обслуживать заказчика, все шло неплохо. Почти всегда взаимосвязи но­ сили неформальный характер и в значительной степени зависели от личных отношений руководителей двух проектов .

В одном проекте по экстремальному программированию я видел формализацию та­ ких ОТНОIIIений в том смысле, что на каждой итерации представители нижней группы ра­ зыгрывали "игру планирования" в роли заказчиков, устраивая совещания совместно с обычными заказчиками (потребителями прикладных функций программы), и обсуж­ дали с ними, какие задачи нужно решить на очередном этапе итерации. Этот проект ВЫ

–  –  –

хорошо работают в тех случаях, когда обе ГРУПIIЫ ГРУП П Ы " 3АКА3 Ч И К-I I ОСТАВ llLИ К" находятся 110/( ед и н ы м руководством (т.е., в конце концов, преслеДУIОТ одни и те же це­ ли), или же тогда, когда они относятся к разным организациям, но сами эти организации фактически находятся в таких взаимоотношениях. Если же мотивировать верхнюю группу печем, то ситуация рсзко отличается.. .

–  –  –

Когда две группы разработчиков с отнотпениями типа "верх-низ" 4 не имеют эффек­ тивного руководства из одного источника, такой типовой образец сотрудничества, как ЗАКАЗЧИ К И П ОСТАВllИК, пеIIрименим. Если наивно попытаться воспользоваться им, нижняя группа окажется в беде. Это может случиться в большой компании, где две груп­ пы находятся далеко друг от друга в управленческой иерархии или где общий куратор проектов безразличен к отношениям между группами. Возможно подобное также и меж­ ду группами в разных компаниях, если деятельность заказчика не представляет особой, индивидуальной ценности для поставщика. Возможно, у постаВIцика есть много мелких заказчиков или же постаВllИК меняет направление своей деятельности и старые клиенты его БОЛЫll С не интересуют. Поставщик может иметь плохо налаженную систему управ­ ления. Он вообще может уйти из своего бизнеса. Как бы там ни было, группа-заказчик вдруг оказывается наедине со своими проблемами .

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

4 В верху (uрsfгеаm) и внизу (dО7.lnstге(Jm) "по течеI-IIПО ", соответственно. 11местся в виду, как и ранее, односторонний ноток данных и кода от верхней группы к нижней. - П римеч. перев .

ГЛАВА 14. ПОДДЕРЖАlf ИЕ ЦЕЛОСТl-I 0СТlf lVIОДЕЛИ Из этой ситуации есть три возможных выхода .

Один - это вообще отказаться от по­ мощи сверху. Этот вариант следует рассмотреть реалистично, не предполагая, что верх­ няя группа обязательно станет удовлетворять потребности нижней. Иногда мы преуве­ личиваем ценность или недооцениваем цену такой зависимости. Если нижняя группа решает перерезать свой поводок, то обе группы начинают вести ОТДЕЛЬНОЕ СУЩЕ­ СТВОВАНИ Е (SEPARATE WAYS), о чем будет речь идти далее в этой главе .

Иногда ценность использования программ сверху настолько велика, что зависимость от них приходится поддерживать (или, допустим, принимается политическое решение, которое разработчики изменить не в силах). В этом случае остаются два выхода, выбор между которыми зависит от качества и стиля архитектуры, предлагаемой верхними раз­ работчиками. Если с ней очень трудно работать, например, из-за недостаточной инкап­ суляции, неудобного абстрагирования или моделирования в парадигме, которую другая группа не может использовать, то нижним разработчикам все равно придется строить свою собственную модель. Им придется нести полную ответственность за создание трансляционного уровня, который, скорее всего, окажется сложным. (См. ПРЕДОХРА­ НИТЕЛЬНЫЙ УРОВЕНЬ, ANTICORRUPTION LAYER, позже в этой главе.) С другой стороны, если архитектура неплоха по качеству и стиль более-менее совмес­ тим, то имеет смысл, может быть, вовсе отказаться от независимой модели. В этих об­ стоятельствах уместен шаблон КОНФОРМИСТ (CONFORl\!l IST) .

Устраните сложность трансляции между ОГРАНИЧЕННЫМИ КОI-IТЕКСТАМИ ( BOUNDED CONTEXTS), придерживаясь модели верхней группы разработчиков. Конечно, это ставит архитекторов нижней rруппы в стесненные обстоятельства, да и модель может оказаться неидеальной для приложения. Но все-таки действия в духе КОНФОРМИЗМА позволяют очень сильно упростить интеграцию. К тому же с группой-поставщиком можно будет ЕДИНОМ ЯЗЫКЕ .

Управляет-то процессом именно поставщик, поэтому разrоваривать на есть смысл сделать общение удобным для Hero. И тоrда ero альтруизма может оказаться достаточно, чтобы он поделился нужной информацией .

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

Следовать за кем-то не всеrда плохо Используя готовый компонент с обширным интерфейсом, обычно приходится rrодстраи­ (conjo1m) под заложеННУIО в него неявную модель, Т.е. действовать как конФормист .

ваться Компонент и приложение, очевидно, являются разными ОГРАН ИЧЕННЫМИ КОНТЕКСТАМИ (BOUNDED CONTEXTS) с точки зрения организации и управления, поэтому для незначитель­ ных изменений формата могут потребоваться какие-то адаптеры-переходники, но модель должна быть эквивалентной. В противном случае нужно поставить под сомнение ценность использования данного компонента. Если от него есть польза, значит, в его архитектуре со­ держится какое-то переработанное знание. В своей узкой сфере он может содержать значи­ тельно больше, чем вы об этом знаете. Ваша модель, предположительно, простирается за пре­ делы сферы действия этого компонента, и ваlПИ собственные концепции будут развиваться там соответственно. Но в точках контакта ваlпа модель представляет собой КОНФОРМИСТА за (CONFORMIST), следующего ведущей моделыо моделью компонента. Может даже слу­ читься, что вам насильно навяжут лучшую архитектуру, чем ваша собственная .

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

318 Ч Асть IV. СТРАТЕГИЧЕСКОЕ ПРОЕКТИРОВАНИЕ Если такие компромиссы пеприемлемы, но зависимость от верхней группы неизбеж­ на, то еще остается второй вариант: изолировать себя, насколько это возможно, с помо­ щью П РЕДОХРАНИТЕЛЬНОГО УРОВНЯ (ANTICORRUPTION LAYER). ЭТО агрессивный подход к реализации карты трансляции, о котором мы поговорим позже .

* * * Шаблон КОI IФОРМИСТ напоминает ОБЩЕЕ ЯДРО (SHARED KERNEL) тем, что у них есть: перекрывающаяся область, в которой модель одна и та же; области, в которых ваша модель аддитивно расширена; области, где вторая модель никак на вас не влияет. Разни­ ца между шаблонами состоит в процессе принятия решений и ходе разработки. Если ОБЩЕЕ ЯДРО это сотрудничество между двумя тесно скоординированными группами, то КОНФОРМИСТ представляет интеграцию с группой, которая фактически не заинтере­ сована в сотрудничестве .

Мы рассмотрели целый спектр вариантов сотрудничества при интеграции между ОГРАНИЧЕННЫМИ КОНТЕКСТАМИ ( BOUNDED CONTEXTS): от достаточно тесного двусто­ роннего сотрудничества типа ОБllЕГО ЯДРА (SHARED KERNEL) или ГРУПП РАЗРА­ БОТЧИКОВ "ЗАКАЗЧИК-ПОСТАВllИК" (CUSTOMER/S UPPLIER DEVELOPER TEAMS) до одно­ сторонней работы КОI-IФОРМИСТА (CONFORMIST). Теперь мы сделаем последний шаг к еще более пессимистическому взгляду на взаимоотношения и предположим, что с другой стороны нас не ожидает ни полезная архитектура, ни желание сотрудничать.. .

ГЛАВА 14. ПОДДЕРЖАНvIЕ ЦЕЛОСТНОСТvl МОДЕЛИПредохранительный уровень

системы почти всегда приходится интегрировать со старыми или сторонними IIoBbIe системами, у которых есть свои собственные модели. Трансляционные уровни для них могут быть простыми И даже "изящными", если они соединяют хорошо спроектирован­ ные О ГРАНИЧЕI IIIЫЕ КОНТЕКСТЫ (BOUNDED CONTEXTS) сотрудничающих групп разра­ ботчиков. Но если с другой сторонь] границы начинаются "протечки", трансляционный уровень rvrO)I(eT стать линией обороны .

* * * Коrда строится новая система, которая должна иметь обширный интерфейс с дру­ rой системой, трудность соотнесения одной модели с друrой мо ж ет в конце концов на­ чисто перечеркнуть всякий смысл новой модели, так как ее придется подстраивать ПОД модель второй системы прямо на ходу. Модели старых, уже не поддерживаемых, сис­ тем обычно посредственны, но даже какое-нибудь высококачественное исключение может не удовлетворять потребности текущеrо проекта. Тем не менее интеrpация с та­ кими системами может иметь ценность, а иноrда она выдвиrается как катеrорическое требование .

Избегать вообще всякой интеграции - это не выход. Мне приходилось работать с та­ кими проектами, где участники с энтузиазмом брались за полную замену всего старого кода. Но это слишком большой объем работы, чтобы вот так в нее бросаться. Кроме того, интегрирование с суrцествующими системами - это полезная разновидность повторного использования программного кода. В больших проектах одна подсистема часто должна взаимодействовать с несколькими другими, независимо разработанными подсистемами через какие-то интерфейсы. Те подсистемы отражаIОТ предмеТНУIО область проблемы п о­ другому. При комбинировании систем, основанных на разных моделях, потребность н о ­ вой системы в принятии семантики других систем может привести к порче собственной модели новой системы. Даже если та, другая система хорошо спроектирована, она все равно не основана на той же модели, что ее клиент. К тому же другая система нечасто бывает XOPOlllO спроектированной .

Взаимодействие с впеПIней системой через интерфейс не так-то просто наладить. На­ пример, инq)раструктурный уровень должен обеспечить средства коммуникации с дру­ ГОЙ систмой, которая может работать на другой платформе или по другим протоколам .

Типы данных другой системы приходится транслировать в типы нашей собственной. Но 320 ЧАсть IV. СТРАТЕГИЧЕСКОЕ ПРОЕКТИРОВАНИЕ о чем часто забывают, так это о том, что в другой системе наверняка используется другая концептуальная модель предметной области .

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

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

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

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

* ** Эти обсуждения разных механизмов связи между двумя системами напоминают о та­ ких проблемах, как перенос данных из одной программы в другую или с одного сервера на другой. Вскоре мы рассмотрим использование технических механизмов коммуникации. Но это все мелочь по сравнению с ПРЕДОХРАНИТЕЛЬНЫМ УРОВНЕМ (ANTICORRUPTION LAYER), который не представляет собой механизма пересылки сообщений от одной системы к др гой. Скорее это механизм, который транслирует концептуальные объекты и операции из одной модели и протокола в другую модель и протокол .

ПРЕДОХРАНИТЕЛЬНЫЙ УРОВЕНЬ может сам по себе быть немалой программной раз­ работкой. Ниже представлены некоторые соображения, которыми надо руководство­ ваться при его планировании и проектировании .

Проектирование интерфейса предохранительного уровня Открытый интерфейс ПРЕДОХРАНИТЕЛЬНОГО УРОВНЯ ( ANTICORRUPTION LAYER) обычно построен как набор СЛУЖБ (SERVICES), хотя иногда он может принимать вид объекта-СУЩНОСТИ ( ENTITY). Построение целого нового уровня для того, чтобы обеспе­ ч ить трансляцию между семантикой двух разных систем, дает нам возможность заново абстрагировать операции другой системы и предложить как ее услуги, так и данные на­ шей системе в согласованном с нашей моделью виде. В нашей модели, может быть, даже не всегда есть смысл представлять внешнюю систему в виде одного компонента. Бывает лучше представить ее в виде нескольких СЛУЖБ, а иногда и СУЩНОСТЕЙ, каждая из ко­ торых имеет четко определенные обязанности в терминах нашей модели .

ГЛАВА 14. ПОДДЕРЖАНИЕ ЦЕЛОСТНОСТИ МОДЕЛИ

Реализация предохранительного уровня Один ИЗ способов организации архитектуры ПРЕДОХРАНИТЕЛЬНОГО УРОВНЯ (ANTICOR­ представить его в виде набора ФАСАДНЫХ ОБЪЕКТОВ (FACADES), RUPTION LAYER) АДАПТЕРОВ (ADAPTERS) [14] и трансляторов, а также механизмов коммуникации и перено­ са, обычно необходимых для связи между системами .

Часто приходится интегрироваться с системами, имеющими большие, сложные, бес­ порядочные интерфейсы. Это проблема программной реализации; она не вызвана на­ ПрЯМУIО различиями в концептуальных моделях, которые делают необходимым приме­ нение ПРЕДОХРАНИТЕЛЬНЫХ УРОВНЕЙ. Но именно при попытке создания таких уровней эта проблема и возникает. Трансляция из одной модели в другую (особенно если одна из них нечеткая) - сама по себе достаточно сложная работа, а тут приходится иметь дело еще и с "невразумительным" интерфейсом подсистемы. К счастью, именно для этого су­ ществуют ФАСАДНЫЕ ОБЪЕКТЫ (FACADES) .

ФАСАДНЫЙ ОБЪЕКТ это альтернативный интерфейс некоторой подсистемы, кото­ рый упрощает обращение к ней со стороны клиента и вообще облегчает ее использова­ ние. Нам известно в точности, какие функции другой системы мы хотим использовать, вот мы и пишем ФАСАДНЫЙ ОБЪЕКТ, который упрощает и спрямляет доступ к ним, скрывая все остальное. ФАСАДНЫЙ ОБЪЕКТ не изменяет модель представляемой им сис­ темы. Он должен быть написан в строгом соответствии с ее моделью, иначе мы в ЛУЧllIем случае разбросаем ответственность за трансляцию на много объектов и перегрузим сам ФАСАДНЫЙ ОБЪЕКТ, а в худшем - построим еще одну модель, которая не относится ни к другой системе, ни к нашему собственному ОГРАНИЧЕНI-IОМУ КОНТЕКСТУ. Между тем ФАСАДНЫЙ ОБЪЕКТ относится К ОГРАНИЧЕННОМУ КОНТЕКСТУ другой системы. Это ее представитель, дружественно настроенный и специально ПРИСl10собленный к нашим по­ требностям .

АДАПТЕР (ADAPTER) представляет собой объект-оболочку, позволяющую клиенту пользоваться не тем ПРОТОКОЛОМ, который понятен реализатору операции, а каким­ нибудь другим. Когда клиент посылает сообщение АДАПТЕРУ, оно преобразуется в се­ мантически эквивалентное сообщение и пересылается "адаптанту". Ответ оттуда опять преобразуется и пересылается назад. Термин "адаптер" (что по сути означает "переходник") используется здесь несколько произвольно; в [14] специально подчерки­ валось, что с его помощью оборачиваемый в оболочку объект делают соответствующим стандартному интерфейсу, которого ожидает клиент. А мы тут выбираем пользоваться адаптированным интерфейсом, и при этом не исключаем, что "адаптант" - вооБIJе не объект. Наша цель - организовать трансляцию между двумя моделями, но я думаю, что "дух" АДАПТЕРА при этом сохраняется .

Для каждой определяемой нами СЛУЖБЫ (SERVICE) необходим АДАПТЕР, который поддерживает интерфейс этой СЛУЖБЫ и умеет делать эквивалентные запросы к другой системе или ее ФАСАДНОМУ ОБЪЕКТУ .

Остается еще такой элемент, как транслятор. Задача АДАПТЕРА состоит в ТОМ, что­ бы делать запросы. Фактическое преобразование концептуальных объектов или дан­ ных - это совсем другая сложная задача, которую можно передать отдельному объек­ ту, отчего обе задачи станут понятнее. Транслятор может быть небольшим объектом, создаваемым и инициализируемым по необходимости. Ему не нужно собственное со­ стояние, и его не надо распределять, поскольку он должен находиться там же, где и 06служиваемый( -е) им АДАПТЕР( Ы ) .

–  –  –

Рис. 14.8. Структура ПРЕДОХРАНИТЕЛЬНОГО УРОВНЯ (ANТICORRUPTION LAYER) Вот из таких основных элементов строится ПРЕДОХРАНИТЕЛЬНЫЙ УРОВЕНЬ (ANTI­ CORRUPTION LAYER). Есть и еще несколько соображений по этому поводу .

Как правило, операцию инициирует проектируемая система (наша подсистема) .

• Именно это подразумевается на рис. 1 4.8. Но бывают и случаи, когда другой подсис­ теме может понадобиться сделать какой-то запрос к нашей подсистеме или извес­ тить ее о каком-нибудь событии. ПРЕДОХРАНИТЕЛЬНЫЙ УРОВЕНЬ может быть дву­ сторонним: определять СЛУЖБЫ с собственными АДАПТЕРАМИ на обоих интерфей­ сах, с возможностью использования одних и тех же трансляторов симметрично в обе стороны. Реализация ПРЕДОХРАНИТЕЛЬНОГО УРОВНЯ обычно не требует изменений в другой системе. Но в этом случае кое-какие изменения все же могут понадобиться, чтобы другая система вызывала службы ПРЕДОХРАНИТЕЛЬНОГО УРОВНЯ .

Обычно для связи между двумя подсистемами, которые могут находиться даже на раз­ • ных серверах, требуется какой-то коммуникационный механизм. В этом случае прихо­ дится решать, где разместить средства коммуникации. Если к другой подсистеме нет доступа, эти связующие звенья придется поместить между ФАСАДНЫМ ОБЪЕКТОМ и другой подсистемой. Но если ФАСАДНЫЙ ОБЪЕКТ можно интегрировать с другой под­ системой напрямую, то хороший вариант - поместить связующее коммуникационное звено между АДАПТЕРОМ и ФАСАДНЫМ ОБЪЕКТОМ, потому что протокол ФАСАДНОГО ОБЪЕКТ А должен быть проще, чем то, что он скрывает. Бывают также случаи, когда весь ПРЕДОХРАНИТЕЛЬНЫЙ УРОВЕНЬ может размещаться вместе с другой подсисте­ мой, располагая механизмы коммуникации или распределения между вашей подсис­ темой и СЛУЖБАМИ, образующими интерфейс ПРЕДОХРАНИТЕЛЬНОГО УРОВНЯ. ЭТИ решения по реализации и установке приложений нужно принимать сугубо прагмати­ чески; они не влияют на концептуальную роль ПРЕДОХРАНИТЕЛЬНОГО УРОВНЯ .

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

Если требования к интеграции очень строги, стоимость трансляции сильно воз­ • растает. Тогда в модели проектируемой подсистемы придется выбирать такие ре­ шения, чтобы приблизить ее к внешней системе и тем самым облегчить трансля­ цию. Это нужно делать осторожно, не подвергая опасности целостность модели, и притом избирательно, только в тех случаях, когда трансляция представляет осо­ бые трудности. Если такой подход кажется самым естественным решением для значительной и важной части проблемы, то подумайте, не стоит ли применить в подсистеме архитектуру КОНФОРМИСТ и убрать трансляцию вовсе .

–  –  –

ФАСАДНЫЙ ОБЪЕКТ может не понадобиться .

В ПРЕДОХРАНИТЕЛЬНЫЙ УРОВЕНЬ можно добавить некоторые рабочие функции, • если они специфичны именно для взаимосвязи между двумя подсистемами. На ум приходят такие две полезные возможности, как отслеживание использования внешней системы или трассировка для отладки обращений к интерфейсу .

Помните, что ПРЕДОХРАI-IИТЕЛЬНЫЙ УРОВЕНЬ - это средство связи между двумя ОГРАНИЧЕННЫМИ КОНТЕКСТАМИ. Обычно в таком случае мы представляем себе систему, написанную кем-то другим; мы не полностью понимаем ее и практически не контролируем .

Но это не единственная ситуация, в которой бывает нужна "прокладка" между системами .

Бывает так, что имеет смысл соединить через ПРЕДОХРАНИТЕЛЬНЫЙ YPOBEI-Ib да:ке две системы своей собственной разработки, если в основе их лежат разные модели. Предполо­ жительно, в таком случае вы имеете полную власть над обеими сторонами и можете обой­ тись простым уровнем трансляции. Все же, если два ОГРАI IИЧЕННЫХ КОНТЕКСТА ведут ОТДЕЛЬНОЕ СУUIЕСТВОВАНИЕ, но между ними требуется некоторая интеграция, ПРЕДОХРАI IИТЕЛЬНЫЙ УРОВЕНЬ может уменьшить возникающие трения .

Пример

Старое приложение заказа грузов Чтобы первая версия системы была небольшой и вышла в свет быстро, мы напишем минимально необходимое приложение, которое позволяет задать параметры поставки груза и передать их в старую систему резервирования через трансляционный уровень, поддерживаЮIЦИЙ оформление заказа и разные вспомогательные операции. Поскольку наш трансляционный уровень строится специально для того, чтобы защитить новую мо­ дель от влияния устаревшей архитектуры, он является именно ПРЕДОХРАНИТЕЛЬНЫМ

УРОВНЕМ (ANTICORRUPTION LAYER) .

В первоначальном варианте ПРЕДОХРАI-IИТЕЛЬНЫЙ УРОВЕНЬ принимает объекты, представляющие поставку груза, преобразует их, передает в старую систему и делает за­ каз. Затем он получает подтверждение и транслирует его обратно в объект подтвержде­ ния из новой архитектуры. Такая изоляция позволит нам разработать новое приложение практически независимо от старого, хотя в трансляцию придется вложить много усилий .

С выходом каждой новой версии новая система может либо брать на себя все больше функций старой, либо добавлять новые, не заменяя имеющиеся - это уж как будет ре­ шено. Подобная гибкость, а также возможность непрерывно пользоваться комбиниро­ ванной системой, при этом продолжая вносить изменения, вероятно, оправдывает расхо­ ды на построение ПРЕДОХРАНИТЕЛЬНОГО УРОВНЯ .

Поучительная история Чтоб ы защитить свои границы от набегов воинственных кочевых племен, древние ки­ тайцы построили Великую стену. Она не выполнила свою задачу как непроницаемый барьер, но позволила урегулировать торговлю с соседями и стать препятствием для вра­ гов. Две тысячи лет она определяла границу и отгора)кивала аграрную китайскую циви­ лизацию от царящего снаружи хаоса, чем и помогла ей сформироваться .

Хотя Великая китайская стена и способствовала становлеНИIО китайской самобытной культуры, все же ее строительство потребовало огромных расходов и разорило как ми­ нимум одну династию. Преимущества стратегии изоляции следует соизмерять с ее це­ ной. Бывает, что нужно проявить прагматизм и внести в модель тщательно выверенные исправления, чтобы состыковать ее с внешними системами .

324 Члсть IV. СТРАТЕГИЧЕСКОЕ ПРОЕКТИРОВАНИЕ Любая интеграция требует затрат: и полноценная НЕПРЕРЫВНАЯ ИНТЕГРАЦИЯ (CON­ TINUOUS INTEGRATION) внутри одного ОГРАНИЧЕННОГО КОНТЕКСТА (BOUNDED CONТEXT), и несколько менее тесная связь через ОБЩЕЕ ЯДРО (SHARED KERNEL) или в ГРУППАХ "ЗАКАЗЧИК-ПОСТАВЩИК" (CUSTOMER/SUPPLIER DEVELOPMENТ TEAMS), и односторонний КОНФОРМИСТ (CONFORMIST), и перестраховочный ПРЕДОХРАНИТЕЛЬНЫЙ УРОВЕНЬ (ANТI­ CORRUPTION LAYER). Интеграция может быть очень ценной и полезной, но она всегда дорого стоит. Поэтому не помешает уверенность в том, что она действительно необходима.. .

Отдельное существование

–  –  –

Интеграция всегда обходится дорого, а отдача от нее не всеrда велика .

Интеграция не только требует обычных затрат на координирование групп разработ­ чиков, но еlце и заставляет идти на компромиссы. Простая специализированная модель, которая могла бы послужить конкретной цели, "вынуждена уступить дорогу" более абст­ рактной модели, способной справиться с любыми ситуациями. Возможно, какая-нибудь совершенно другая технология могла бы обеспечить нужные функции очень легко, но ее было бы трудно интегрировать. А может быть, с какой-то группой так трудно работать, что Лlобые попытки других разработчиков сотрудничать с ними кончаются неудачей .

Во многих обстоятельствах СУlцествепной отдачи от интеграции получить не удается .

Если две функциональные части системы не нуждаются в операциях друг друга или взаимодействии между объектами, с которыми соприкасаются они обе, или совместном использовании данных, то интеграция даже через трансляционный уровень может ока­ заться необязательноЙ. Функциональные возможности не обязаны интегрироваться в одно целое только потому, ЧТО они совместно используются в каком-то случае .

Объявите ОГРАНИЧЕННЫЙ КОНТЕКСТ ( BOUNDED CONTEXT) никак не связанным с другими контекстами. Это позволит разработчикам найти простые узкоспециализи­ рованные решения в данном ограниченном пространстве .

Нужные ФУНКЦИИ могут быть объединены на уровне ПО среднего уровня (middleware) или на уровне интерфейса, но совместного использования алгоритмической

ГЛАВА 14. ПОДДЕРЖАНИЕ ЦЕЛОСТНОСТИ МОДЕЛИ

логики не будет, и пересылка данных между трансляционными уровнями сведется к ми­ нимуму - хотя лучше к нулю .

Пример "Урезание " проекта по обслуживанию страхования Одна группа взялась за разработку новой программы по управлению страховыми претензиями, которая бы интегрировала в единую систему все, что нужно агенту по об­ служиванию клиентов или оценщику страховых убытков. Год напряженных усилий ни к чему не привел. Их победило сочетание "мандража" S и слишком тщательное заблаго­ временное выстраивание инфраструктуры - в результате ИМ оказалось практически не­ чего предъявить нетерпеливому начальству. Если же говорить серьезнее, разработчики не рассчитали масштаба и размаха того, что они пытались сделать .

Новый руководитель проекта загнал всех в комнату на неделю и заставил писать но­ вый план. Вначале было составлено техническое задание, Т.е. список требований. Разра­ ботчики попытались оценить их трудность и расставить по важности, после чего самые трудные и маловажные были безжалостно выброшены. В оставшемся списке стали наво­ дить порядок. За неделю было принято много остроумных решений, но в конце концов важным оказалось только одно. В какой-то момент наступило понимание, что есть такие функции nрограм.мы, которые мало что выигрывают от интеграции. Например, оценщи­ кам ущерба требовался доступ к некоторым существующим базам данных, а их текущий способ доступа был очень неудобным. Но хотя пользователям эти данные были HyJlcllы' никакие остальные функции предложенной nрограм.мноЙ системы ими не nолъзовались .

Члены группы предложили самые разные способы для облегчения доступа к данным .

В ОДНОМ варианте ключевой отчет экспортировался в HTML и выкладывался во ВНУТ­ ренней сети. В другом варианте оценщикам предлагался специальный запрос к базе дан­ ных, написанный с использованием одного стандартного пакета программ. Все эти функции можно было интегрировать, организовав ссылки на странице в сети или доба­ вив кнопки на рабочий стол пользователя .

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

Все могло бы так и произойти, но, К сожалению, группа скатилась к старым привычкам и снова впала в ступор. В конце концов от них только и осталось ценного, что те несколько маленьких приложений, которые первыми получили ОТДЕЛЬНОЕ СУIЦЕСТВОВАНИЕ .

* * * Принятие решения об ОТДЕЛЬНОМ СУЩЕСТВОВАНИИ сразу же исключает некоторые вариаНТЬJ выбора. Хотя при непрерывном рефакторинге рано или поздно отменяется любое решение, все-таки трудно интегрировать в одно целое модели, развивавшиеся в полной ИЗОЛЯЦИИ друг от друга. Если интеграция со временем оказывается нужной, то приходится создавать трансляционные УРОВНИ, иногда очень сложные. Впрочем, с этим любом случае приходится сталкиваться .

5 Автор употребляет звучную игру слов analysi..() paralysis, которая ДОСЛОВНО означает "паралич анали­ за", а по суги то же самое: невозможность ДВИНУТЬСЯ С места из-за пустых стра хов. Прuмеч. перев .

–  –  –

Службы с открытым протоколом Как правило, в любом ОГРАНИЧЕННОМ КОНТЕКСТЕ ( BOUNDED CONTEXT) определяется по одному трансляционному уровню для каждого компонента за пределами КОНТЕКСТА, с которым необходимо интегрироваться. Если интеграция делается "на один раз", то подход с добавлением одного трансляционного уровня для каждой внешней системы позволяет пре­ дохранить свою модель с минимальными издержками. Но если ваша подсистема вдруг ста­ новится широко востребованной, может потребоваться более гибкий подход .

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

Бывает, что разработчики делают одно и то же много раз, снова и снова. Если с под­ системой требуется какая-то интеграция, то не исключено, что ее можно описать в виде набора СЛУЖБ (SERVICES), отвечаЮlIJ:ИХ стандартным потребностям других подсистем .

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

Определ ите протокол, который бы предоставил доступ к вашей подсистеме как к СЛУЖБ ( SERVICES ). Сделайте протокол открытым, чтобы все желающие интег­ набору рироваться смогли бы им воспользоваться. Совершенствуйте и расширяйте протокол для учета новых интеграционных требований, кроме тех случаев, когда у отдельных групп возникают особо экзотические запросы. В таких случаях можно дописать одно­ разовый транслятор в дополнение к протоколу, чтобы основной общий протокол оста­ вался простым и единообразным .

* * * Такая формализация коммуникации подразумевает, что у разных моделей имеется не­ кий общий словарь - основа для интерфейсов соответствующих СЛУЖБ. В результате сто­ ронние подсистемы оказываются привязанными к модели с ОТКРЫТЫМ ПРОТОКОЛОМ (OPEN HOST), и это вынуждает их разработчиков изучать конкретный диалект, используе­ мый группой разработки протокола. В некоторых случаях снизить зависимость и облегчить взаимопонимание можно, если применить в качестве промежуточной модели достаточно известный и ОБЩЕДОСТУПНЫЙ ЯЗЫК (PUBLISHED LANGUAGE).. .

Общедоступный язык Трансляция между моделями двух разных ОГРАНИЧЕННЫХ КОНТЕКСТОВ (BOUNDED CONTEXTS) требует наличия какого-то общего языка .

* * * Если двум разным моделям предметных областей необходимо сосуществовать и об­ мениваться информацией, процесс трансляции сам по себе может усложниться, плохо

ГЛАВА 14. ПОДДЕРЖАНИЕ ЦЕЛОСТНОСТИ МОДЕЛИ

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

А вот другая ситуация. Если два предприятия (или две отрасли, или два вида деятель­ ности) должны обмениваться информацией ме)кду собой, как им это делать? Предполагать, что одна сторона примет модель предметной области другой, во-первых, нереалистично, а во-вторых, может быть, и нежелательно для обеих сторон. Модель предметной области разрабатывают, для того чтобы она решала задачи своих пользователей. Она может содер­ жать такие средства, которые без нужды усложнят коммуникацию с другой системой. Так­ же, если модель одного из приложений используется как среда коммуникации, ее нельзя будет легко изменить под какие-либо новые потребности. Наоборот, ей придется быть как можно стабильнее, чтобы выполнять свою роль средства коммуникации .

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

Для многосторонней интеграции СЛУЖБА С ОТКРЫТЫМ ПРОТОКОЛОМ (OPEN HOST SERVICE) использует стандартизированный протокол. В ней для коммуникации между системами применяется модель предметной области, даже если она внутри самих систем и не задействована. Теперь нужно сделать шаг вперед и вывести язык этой модели на общедоступный уровень или же найти такой язык, который уже общедоступен. Под 06rцедоступностью следует понимать наличие свободного доступа к нему со стороны сооб­ щества, заинтересованного в пользовании им, а также документированность, достаточ­ ную для того, чтобы совместить его независимые интерпретации .

В недавние годы мир электронной коммерции с энтузиазмом воспринял НОВУЮ техно­ логию: язык Extensible Markup Language (XML), обещаВПIИЙ значительно облегчить обмен данными6. Бесценное свойство этого языка состоит в ТОМ, что посредством определения ти­ па документа (Dоситеnt" Туре Definit"ion, DTD) или шаблонных схем XML можно ввести формальную спецификацию специализированного профессионального языка, на который могут транслироваться (переводиться) данные. Уже начали создаваться различные отрас­ левые группы разработчиков, ставящие своей целыо создание единого стандартно! о DTD дЛЯ своей отрасли - чтобы, скажем, химическую q)ормулу или генетический код мо)кпо было свободно передавать заинтересованным сторонам. Такие группы фактически создал и совместную модель предметной области в виде определения ее языка .

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

Такой язык не обязательно создавать с нуля. Много лет назад меня подрядила на работу компания, в программном продукте которой, написанном на Smalltalk, данные хранились в СУБД DB2. Компания хотела расширить возможности сбыта своего программного обеспе­ чения, продавая его пользователям без лицензии на DB2. Поэтому они наняли меня соз­ дать интерфейс к Btrievc - менее тяжеловесной СУБД, лицензия на пользование исполни ­ тельным механизмом которой предоставлял ась бесплатно. Btricvc - - не полностью реляци

–  –  –

328 ЧАсть IV. СТРАТЕГИЧЕСКОЕ П РОЕКТИРОВАНИЕ онная СУБД, но мой КlIиент все равно пользовался только небольшой частью возможно­ стей DB2 и как раз попадал в наименьший общий знаменатель двух СУБД. Программисты компании надстроили над DB2 кое - какие абстракции, реализующие хранение объектов. Я реПIИЛ воспользоваться их результатами как интерфейсом для моего компонента Btrieve .

Этот подход сработал. IlporpaMMa четко интегрировалась с системой моего клиента. Од­ нако отсутствие формального технического задания или документации на абстракции посто­ янно существующих объектов в архитектуре К7Iиента потребовало большой работы по состав­ лению технического задания на новый компонент. Невелик был и шанс перенести этот ком­ понент куда-нибудь с целыо Ilеревода других приложений с DB2 на Btrieve. Новое нроrpаммное обеспечение еще глубже закрепило модель поддержания постоянного сущест­ вования объектов, принятую в компании, что затруднило ее потенциальный рефакторинг .

ЛУЧUlе для них БыIоo бы определить, какое подмножество интерфейса DB2 фактически используется компанией, и реanизовать его поддержку. Интерфейс DB2 состоит из языка SQL и нескольких закрыIыыx протоколов. Он очень сложен, но четко специализирован и под­ робно документирован. Но проблема с его сложностью не стояла бы так остро, поскольку ис­ пользоваться должна была только небольшая часть интерфейса. Если бы бьш разработан компонент, эмулирующий нужное подмножество интерфейса DB2, его можно было бы фак­ тически документировать для разработчиков, просто указав, какое именно подмножество реализуется. Приложение, в которое оп иптегрировanся, уже "общалось" с DB2, так что пона­ добилось бы совсем немного дополнительной работы. В будущем перепроектировании уров­ ня постоянного хранения объектов разработчики были бы связаны только использованием подмножества DB2 - точно так же, как и до начanа своих усовершенствований .

Интерфейс DB2 - это пример ОБIЦЕДОСТУПНОГО ЯЗЫКА (PUBLISHED LANGUAGE) .

Б данном случае две модели не находятся в одной предметной области, но все принципы все равно применимы. Поскольку одна из сотрудничающих моделей уже является носи­ телем ОБЩЕДОСТУПНОГО ЯЗЫКА, нет необходимости вводить еще и третий язык .

Пример

в Общедоступный язык химии Для каталогизации, анализа и манипулирования химическими формулами использу­ ется бесчисленное множество программ как в промышленности, так и в науке. Обмен данными всегда был делом нелегким, потому что практически каждая программа имеет свою модель предметной области для представления химических структур. К тому же БОЛI)IIIИНСТВО из них написано на таких языках, как FORTRAN, которые в Лlобом случае не слишком точно отображают модель предметной области. Когда кто-нибудь хочет об­ меняться или поделиться данными, ему приходится разбираться в подробностях устрой­ ства базы данных из другой системы и вырабатывать какую-то схему трансляции .

И тут "на сцене" появляется язык химического кодирования Chemical Markup Language (CML). Этот диалект языка XML задуман как общий язык обмена данными в этой сфере, а разработан и сопровождается он группой, которая представляет и науч­ ные, и производственные круги [20 ] .

Химическая информация характеризуется большой сложностью и разнообразием .

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

После того как язык опубликован и стал общедоступным, можно заняться разработкой программ, с которыми раньше не стоило и возиться, раз они все равно годились только для

ГЛАВА 1 4. ПОДДЕРЖАНИЕ ЦЕЛОСТНОСТИ МОДЕЛИ

одной базы данных. Например, было разработано приложение на Java под названием JUMBO Browser, которое генерирует графические представления химических структур, записанных на языке CML. Таким образом, если хранить данные в формате CML, появля­ ется возможность пользоваться подобными средствами визуализации .

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

Ниже показан небольшой пример в формате CML. В нем мало что поймет неспециа­ лист наподобие меня, но основной принцип все же понятен .

CML. ARR I D= " а rrауЗ " EL. TYP E = FLOAT

NAМE = " ATOMIC ORBITAL ELECTRON POPULATIONS "

SIZE=3 0 GLO. ENT = CML. THE. AOEPOPS 1. 17947 0. 95091 0. 97175 1. 00000 1. 17947 0. 95090 0. 9 7 1 74 1. 00000 1. 17946 0. 98215 0. 94 0 4 9 1. 00000 1. 17946 0. 95091 0. 9 7 1 74 1. 00000 1. 17946 0. 95091 0. 9 7 1 74 1. 00000 1. 17946 0. 98215 0. 94 0 4 9 1. 00000 0. 89789 0. 89790 0. 89789 0. 89789 0. 89790 0. 89788 / CML. ARR ** *

–  –  –

330 Ч Асть IV. СТРАТЕГИЧЕСКОЕ ПРОЕКТИРОВАНИЕ В зависимости от того, какие цели преследуются во взаимодействии со слоном, раз­ ные слепцы могут даже продвинуться в решении своих задач, пусть они и не достигли со­ гласия по поводу сущности слона. Если интеграция не требуется, то отсутствие унифи­ кации в моделях не имеет никакого значения. Если же какая-то интеграция все-таки нужна, то даже если слепцы по-прежнему не согласны друг с другом, сам факт отсутст­ вия согласия уже может оказаться ценным знанием. По крайней мере, играя в "испорченный телефон ", слепцы будут осознавать это .

-

–  –  –

Диаграммы на рис 14.9 это UМL-представления моделей слона, которые построили слепцы. После организации отдельных ОГРАНИЧЕНIIЫХ КОНТЕКСТОВ (BOUNDED CONTEXTS) ситуация, в которой они находятся, прояснилась настолько, что появился смысл общаться друг с другом о некоторых аспектах слона, которые могут интересовать сразу всех, например о его местонахождении .

–  –  –

Если слепцы захотят обменяться дополнительной информацией о слоне, появится СМIIСЛ В использовании обrцего ОГРАНИЧЕННОГО КОНТЕКСТА. НО унификация в корне отличных, несоизмеримых моделей - нетривиальная задача. Ни один из слепцов не хо­ чет отказаться от своей модели и принять чужую. Ведь человек, ухвативший слона за хвост, 31-laeт, что слон не похож на дерево, и такая модель будет для него бессмысленной и бесполезной. Унификация нескольких моделей почти всегда означает создание новой .

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

Для каких-то целей может оказаться достаточно считать слона стеной, стоящей на ство­ лах деревьев, с веревкой на одном конце и змеей на другом .

ГЛАВА 14. ПОДДЕРЖАНИЕ ЦЕЛОСТI-IОСТИ МОДЕЛИ

Стена

–  –  –

Унификация различных моделей слона п роще, чем большинство подобных вариан­ тов. К сожалению, это, скорее, исключение, когда две модели просто описывают разн ые части целого; чаще всего это лишь один из аспектов различия между н ими. Все усложня ­ ется, когда разные модели воспринимают одну и ту же часть целого по - разному. Если бы двое потрогали хобот, и один описал бы его как змею, а другой - как пожарный шлан г, ситуация усложнилась бы. Н и один не принял бы модели другого, поскольку она проти ­ воречила бы его собственному опыту. Фактически им нужна новая абстракция, которая бы объединила "живость " змеи с функцией подачи воды, п рисущей шлангу. Пр ичем в этой абстракции должны быть исключены неподходящие к случаю характеристики мо­ делей: например, наличие ядовитых зубов или способность отделяться от тела, скр учи ­ ваться в кольцо и укладываться в пожарную маш ину .

Хотя нам удалось объединить части в целое, итоговая модель получилась гру бой и неуклюжей. Она несвязна и никак не обозначает контуры лежащей в ее основе пред­ метной области. Но процесс непрерывного и постеп енного ее совершенствования может п ривести к новым выводам, на основе которых можно будет углубить модель. Стим ули ­ ровать движение к новой модели может также новое техническое задание. Если слон начнет двигаться, теория "дерева " развалится, и н аши слепые моделировщики м огут скачкообразно п ридти к понятию "ног" .

–  –  –



Pages:     | 1 | 2 || 4 | 5 |


Похожие работы:

«Закрыть Справка Мартынов Алексей Иосифович Торможение КВТ Схема тормозного оборудования тепловоза ТЭМ 7 выпуска после 1981года Красноярск 2015г Оглавление Вперёд Закрыть Справка Оглавление 1. Общие сведения о схеме 2. Система СОВ 3. Си...»

«УСТРОЙСТВО КОМПЛЕКТНОЕ РАСПРЕДЕЛИТЕЛЬНОЕ Каталог-265-2018-01 ПОСТОЯННОГО ТОКА ОТРИЦАТЕЛЬНОЙ ШИНЫ РУОШ-825 УСТРОЙСТВО КОМПЛЕКТНОЕ РАСПРЕДЕЛИТЕЛЬНОЕ ПОСТОЯННОГО ТОКА ОТРИЦАТЕЛЬНОЙ ШИНЫ РУОШ-825 В Каталог – 265 ООО НИИЭФА-ЭНЕРГО Факс: (812) 464-46-34 www.nfenergo.ru 196641, Санкт-Петербург, Телефон: (812) 464-45-92 E-mail: Info@nfen...»

«Acronis True Image 2019 РУКОВОДСТВО ПОЛЬЗОВАТЕЛЯ Содержание 1 Введение 1.1 Что такое Acronis® True Image™ 1.2 Новое в данной версии 1.3 Системные требования и список поддерживаемых носителей 1.3.1 Минимальные системные требования 1.3.2 Подде...»

«Описание типа средств измерений для Государственного реестра СОГЛАСОВАНО Руководитель ГЦИ СИ Генеральный директор Ф ГУ о И i )) т^1t^^1 Ул '^ Внесен в Государственный реестр средств измерений Прибор счётный одноканальный дб О 9 Регистрационный ПСО2-4 И Взамен N2 Выпускается по техническим условиям еМ 2.801.02...»

«Министерство образования и науки Российской Федерации федеральное государственное автономное образовательное учреждение высшего образования "НАЦИОНАЛЬНЫЙ ИССЛЕДОВАТЕЛЬСКИЙ ТОМСКИЙ ПОЛИТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ" Школа Инженерная школа природных ресурсов Направление подготовки 21.04.01 Нефтегазовое дело Отделение школы (НОЦ) ОНД...»

«МЕЖГОСУДАРСТВЕННЫЙ СОВЕТ ПО СТАНДАРТИЗАЦИИ, МЕТРОЛОГИИ И СЕРТИФИКАЦИИ (МГС) INTERSTATE COUNCIL FOR STANDARDIZATION, METROLOGY AND CERTIFICATION (ISC) ГОСТ МЕЖГОСУДАРСТВЕННЫЙ IEC 60730-2-13СТАНДАРТ А в то м ати чески е эл ектрические уп р авл яю щ ие устр о й ств а б ы тово го и ан ал о ги чн о го назначения Ч а с т ь 2-13 ЧАСТНЫЕ ТРЕБОВАН...»

«www.vidal.ru ЛЮКСФЕН® (LUXFEN) BRIMONIDINE зарегистрировано ВАЛЕАНТ ООО (Россия) произведено SANITAS AB (Литва) ЛЕКАРСТВЕННАЯ ФОРМА, СОСТАВ И УПАКОВКА Капли глазные 0.2% в виде прозрачного раствора зеленовато-же...»

«Печатается по решению редакционно-издательского совета Пятигорского государственного университета Данилова Е.С. Рабочая программа дисциплины "Конфликтология в социальной работе". – Пятигорск: ПГУ, 2018. 42 с. Рабочая программа дисциплины составлена на основании Федерального государственного образовате...»

«Санкт-Петербургский Государственный Университет Математико-механический факультет Кафедра системного программирования Минаев Александр Сергеевич Использование линейного дискриминантного анализа в задаче предсказания оттока абонен...»

«ГАЗИЗУЛЛИН РАМИС РАШИТОВИЧ СТИМУЛИРОВАНИЕ РЕАКЦИЙ ФРАГМЕНТАЦИИ АРЕНОВ И ГЕТАРЕНОВ НИЗКОВОЛЬТНЫМИ ЭЛЕКТРОННО-ИМПУЛЬСНЫМИ РАЗРЯДАМИ В ЖИДКОЙ ФАЗЕ Специальность 02.00.04 "Физическая химия" (технически...»

«ИНСТРУКЦИЯ ПО ЭКСПЛУАТАЦИИ m2 multi ПСП (AAD) Может спасти вам жизнь. Больше, чем вы думаете. 09.17.03 RU СОДЕРЖАНИЕ 9. Обслуживание 5. Управление СОДЕРЖАНИЕ ПРЕДУПРЕЖДЕНИЕ 9.1. Замена резака 5.1. Основы управления 1. Введение 9.2. Замена фильтра 5.2. Включение и выключение прибора 1.1...»

«УДК 621.315.5 С.Л.Нагорный(1), Т.В.Критская, Л.Я.Шварцман(1) ОСНОВНЫЕ ТРЕБОВАНИЯ К ТЕХНОЛОГИЧЕСКИМ СХЕМАМ ПОЛУЧЕНИЯ КРЕМНИЯ СОЛНЕЧНОГО КАЧЕСТВА (1) Казенное предприятие "Запорожский титано-магниевый комбинат", Запорожская государственная инженерная академия Роз...»

«Л 202редакт Галимов Эрик Михайлович Феномен жизни: между равновесием и нелинейностью. Происхождение и принципы эволюции. — М.: Едиториал УРСС, 2006. — 256 с. ISBN 5-354-01143-4 Книга посвящена одной из наиболее фундаментальных проблем естествознания — проблеме происхождения жизни и законам...»

«ТКП 474-2013 (02300) ТЕХНИЧЕСКИЙ КОДЕКС УСТАНОВИВШЕЙСЯ ПРАКТИКИ КАТЕГОРИРОВАНИЕ ПОМЕЩЕНИЙ, ЗДАНИЙ И НАРУЖНЫХ УСТАНОВОК ПО ВЗРЫВОПОЖАРНОЙ И ПОЖАРНОЙ ОПАСНОСТИ КАТЭГАРЫРАВАННЕ ПАМЯШКАННЯЎ, БУДЫНКАЎ І ВОНКАВЫХ УСТАНОВАК ПА ЎЗРЫВАПАЖА...»

«Приложение № 1 к пр. №33 от 13.07.2018 г. заседания Президиума ВСС ВСЕРОССИЙСКИЙ СОЮЗ СТРАХОВЩИКОВ ВНУТРЕННИЙ СТАНДАРТ Утвержден постановлением Президиума Всероссийского союза страховщиков протокол № 33 от 13 июля 2018 г. СТАНДАРТ СТРАХОВАНИЯ РИСКА ОТВЕТСТВЕННОСТИ ЗА НАРУШЕНИЕ ЧЛЕНАМИ САМОРЕГУЛИРУЕМОЙ ОРГАНИЗАЦИИ УСЛОВИЙ Д...»

«ООО "Завод Теплосила"МОДУЛЬ УПРАВЛЕНИЯ МНОГОФУНКЦИОНАЛЬНЫЙ TTR-01A (Исполнение для узла подпитки в системе отопления) Руководство по эксплуатации. ЮНСК . 421232.001-24 РЭ _ Содержание 1 Назначени...»

«Министерство образования и науки Российской Федерации Федеральное государственное автономное образовательное учреждение высшего образования "НАЦИОНАЛЬНЫЙ ИССЛЕДОВАТЕЛЬСКИЙ ТОМСКИЙ ПОЛИТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ" Инженерная школа новых производственных технологий (ИШНПТ) Научно-образовательный центр Н.М. Кижнера (Н...»

«Российская Федерация Тюменская область ГОСУДАРСТВЕННОЕ АВТОНОМНОЕ УЧРЕЖДЕНИЕ ТЮМЕНСКОЙ ОБЛАСТИ "УПРАВЛЕНИЕ ГОСУДАРСТВЕННОЙ ЭКСПЕРТИЗЫ ПРОЕКТНОЙ ДОКУМЕНТАЦИИ" (ГАУ ТО "УГЭПД") УТВЕРЖДАЮ Директор А.А. Кучерявый 01 ноября 2018 г. ПОЛОЖИТЕЛЬНОЕ ЗАКЛЮЧЕНИЕ № 72 1 0231 18 Объект капитального строительства "СНТ "Светло...»

«Министерство науки и высшего образования Российской Федерации Министерство образования и науки Пермского края Пермский государственный национальный исследовательский университет Институт механики сплошных сред УрО РАН Пермский государственный гуманита...»

«ГОСТ Р 50267.49-2004 (М ЭК 60601-2-49-2001) НАЦИОНАЛЬНЫЙ СТАНДАРТ РОССИЙСКОЙ ФЕДЕРАЦИИ И ЗД Е Л И Я М Е Д И Ц И Н С К И Е ЭЛЕКТРИЧЕСКИЕ Часть 2 Частные требования безопасности к многофункцио...»

«Подобаев Александр Николаевич АДСОРБЦИОННОЕ ВЗАИМОДЕЙСТВИЕ ВОДЫ С МЕТАЛЛАМИ И ЕГО РОЛЬ В ПРОЦЕССАХ ЭЛЕКТРОХИМИЧЕСКОЙ КОРРОЗИИ Специальность 05.17.03 технология электрохимических процессов и защита от коррозии Автореферат диссертации на соискание ученой степени доктора химических наук Москва 2008 Работа выполнена в Федеральном Г...»

«О ЕРЖЕНИН РОМАН ВАЛЕРЬЕВИЧ ИННОВАЦИОННАЯ МОДЕЛЬ ОРГАНИЗАЦИИ БЮДЖЕТНОГО УЧЕТА В МУНИЦИПАЛЬНЫХ ОБРАЗОВАНИЯХ Специальность: 08.00.05 — Экономика и управление народным хозяйством: управление инновациями АВТОРЕФЕРАТ диссертации на соискание ученой степени кандидата экономических наук 1 7 МАЙ Ш Иркутск 2012 Работа выполнена, обсуждена и рекомендо...»

«PRO БЕЗОПАСНОСТЬ Pro Электромагнитный импульс В. И. Гуревич, кандидат технических наук Аннотация: Владимир Игоревич Гуревич (р. 1956, Харьков, УкраПроблемы, связанные с воздействием электромагнитного импульса инская ССР, СССР) – известный ученый-электротехвысотного ядерного взрыва (ЭМИ ЯВ) на электронное и электротехническое ник, кандидат...»

«SAFETY2018, Екатеринбург, 4–5 октября 2018 г. ЭКСПЕРТИЗА И УПРАВЛЕНИЕ В СТРОИТЕЛЬСТВЕ АНАЛИЗ ЗАРУБЕЖНОГО ОПЫТА УПРАВЛЕНИЯ ЖИЛОЙ НЕДВИЖИМОСТЬЮ Абрамова М. И., 1Кожевникова М. К . Уральский федеральный университет им. первого Президента России Б. Н. Е...»







 
2019 www.librus.dobrota.biz - «Бесплатная электронная библиотека - собрание публикаций»

Материалы этого сайта размещены для ознакомления, все права принадлежат их авторам.
Если Вы не согласны с тем, что Ваш материал размещён на этом сайте, пожалуйста, напишите нам, мы в течении 1-2 рабочих дней удалим его.