- •Часть 1. Планирование архитектуры
- •Заключение
- •Дополнительная литература
- •4.10. Дискуссионные вопросы
- •Глава 8. Моделирование условий полета. Конкретный пример архитектуры, ориентированной на интегрируемость
- •8.4. Заключение
- •Дополнительная литература
- •Дискуссионные вопросы
- •Глава 9. Документирование программной архитектуры
- •Заключение
- •Дополнительная литература
- •Дискуссионные вопросы
- •Глава 10. Реконструкция программной архитектуры
- •Заключение
- •Дополнительная литература
- •Дискуссионные вопросы
- •Глава 6. Управление воздушным движением. Пример разработки, ориентированной на высокую готовность
- •Глава 7. Проектирование архитектуры
- •Глава 11. Метод анализа компромиссных архитектурных
- •Заключение
- •Дополнительная литература
- •Дискуссионные вопросы
- •Глава 12. Метод анализа стоимости и эффективности — количественный подход к принятию
- •Заключение
- •Дополнительная литература
- •Дискуссионные вопросы
- •Глава 13. Всемирная паутина. Конкретный пример реализации способности к взаимодействию 374
- •Глава 14. Линейки программных продуктов.
- •Заключение
- •Дополнительная литература
- •Глава 15. CelsiusTech. Конкретный пример разработки
- •Заключение
- •Дополнительная литература
- •Дискуссионные вопросы
- •Заключение
- •Дополнительная литература
- •Дискуссионные вопросы
- •Заключение
- •Дополнительная литература
- •Дискуссионные вопросы
- •Заключение
- •Дополнительная литература
- •Заключение
- •Часть 1. Планирование архитектуры
- •Часть 2. Создание архитектуры
- •Часть 3. Анализ архитектуры
- •Часть 4. От одной системы к множеству
- •Часть 1
- •Глава 1
- •1.1. Откуда берутся варианты архитектуры?
- •1.2. Программный процесс и архитектурно-экономический цикл
- •1.3. Из чего складывается «качественная» архитектура?
- •1.4. Заключение
- •1.5. Дискуссионные вопросы
- •Глава 2
- •2.1. Чем является программная архитектура и чем она не является
- •2.2. Другие взгляды на архитектуру
- •2.3. Архитектурные образцы, эталонные модели и эталонные варианты архитектуры
- •2.4. Почему программная архитектура так важна?
- •2.5. Архитектурные структуры и представления
- •2.6. Заключение
- •2.7. Дополнительная литература
- •2.8. Дискуссионные вопросы
- •Глава 3
- •3.1. Связь с архитектурно-экономическим циклом
- •3.2. Требования и атрибуты качества
- •3.3. Архитектура авиационной электронной системы а-7е
- •3.4. Заключение
- •3.5. Дополнительная литература
- •3.6. Дискуссионные вопросы
- •Часть 2
- •Глава 4
- •4.1. Функциональность и архитектура
- •4.2. Архитектура и атрибуты качества
- •4.3. Атрибуты качества системы
- •4.4. Практическое применение сценариев атрибутов качества
- •4.5. Другие атрибуты качества системы
- •4.6. Коммерческие атрибуты качества
- •4.7. Атрибуты качества архитектуры
- •4.8. Заключение
- •4.9. Дополнительная литература
- •4.10. Дискуссионные вопросы
- •Глава 5
- •5.1. Определение тактики
- •5.2 Тактики реализации готовности
- •5.3. Тактики реализации модифицируемости
- •5.4. Тактики реализации производительности
- •5.5. Тактики реализации безопасности
- •5.6. Тактики реализации контролепригодности
- •5.7. Тактики реализации практичности
- •5.8. Взаимосвязь тактик и архитектурных образцов
- •5.9. Архитектурные образцы и стили
- •5.10. Заключение
- •5.11. Дополнительная литература
- •5.12. Дискуссионные вопросы
- •Глава 6
- •6.1. Связь с архитектурно-экономическим циклом
- •6.2. Требования и атрибуты качества
- •6.3. Архитектурное решение
- •6.4. Заключение
- •6.5. Дополнительная литература
- •6.6. Дискуссионные вопросы
- •Глава 7
- •7. 1. Архитектура в контексте жизненного цикла
- •7.2. Проектирование архитектуры
- •1. Выбор модуля для декомпозиции
- •2А. Выбор архитектурных мотивов
- •2Ь. Выбор архитектурного образца
- •2D. Задание интерфейсов дочерних модулей
- •7.3. Формирование рабочих групп
- •7.5. Заключение
- •7.6. Дополнительная литература
- •7.7. Дискуссионные вопросы
- •Глава 8
- •8.1 Связь с архитектурно- экономическим циклом
- •8.2. Требования и атрибуты качества
- •8.3. Архитектурное решение
- •8.2 Заключение
- •8.5 Дополнительная литература
- •8.6. Дискуссионные вопросы
- •Глава 9
- •9.1. Варианты применения архитектурной документации
- •9.2. Представления
- •9.3 Выбор значимых представлений
- •9.4. Документирование представления
- •9.5. Перекрестная документация
- •9.6. Унифицированный язык Моделирования
- •9.7. Заключение
- •9.8. Дополнительная литература
- •9.9. Дискуссионные вопросы
- •Глава 10
- •10.1. Введение
- •10.2. Извлечение информации
- •10.3. Создание базы данных
- •10.4. Объединение представлений
- •10.5. Реконструкция
- •10.6. Пример
- •10.7. Заключение
- •10.8. Дополнительная литература
- •10.9. Дискуссионные вопросы
- •Часть 3
- •Глава 11
- •Результаты проведения оценки по методу атам
- •Этапы atam
- •1 Источник: приводится по изданию [Clements 02а] (адаптированная версия).
- •11.4. Система Nightingale: конкретный пример проведения оценки по методу атам
- •11.5. Заключение
- •Дополнительная литература
- •Дискуссионные вопросы
- •Глава 12
- •Результаты оценки по методу свам
- •Заключение
- •Дополнительная литература
- •Дискуссионные вопросы
- •Глава 13
- •13.1. Отношение к архитектурноэкономическому циклу
- •13.4. Еще одна итерация архитектурноэкономического цикла: эволюция вариантов веб-архитектуры систем электронной коммерции
- •13.7. Заключение
- •13.8. Дополнительная литература
- •13.9. Дискуссионные вопросы
- •Часть 4
- •Глава 14
- •За счет чего работают линейки программных продуктов?
- •Варианты архитектуры линеек продуктов
- •Факторы, усложняющие применение линеек программных продуктов
- •Заключение
- •Дополнительная литература
- •Дискуссионный вопрос
- •Глава 15
- •Связь с архитектурноэкономическим циклом
- •Требования и атрибуты качества
- •Архитектурное решение
- •Заключение
- •Дополнительная литература
- •Дискуссионные вопросы
- •Глава 16
- •Связь с архитектурноэкономическим циклом
- •16.3. Архитектурное решение
- •16.4. Решения по размещению системы
- •Заключение
- •Дополнительная литература
- •Дискуссионные вопросы
- •Глава 17
- •17.2. Требования и атрибуты качества
- •17.3. Архитектурное решение
- •17.4. Механизм реализации атрибутов качества в архитектуре Luther
- •Заключение
- •Дополнительная литература
- •Дискуссионные вопросы
- •Глава 18
- •18.1. Воздействие компонентов на архитектуру
- •18.2. Архитектурное несоответствие
- •18.3. Компонентное проектирование как поиск
- •18.4. Пример приложения aseilm
- •18.5. Заключение
- •18.6. Дополнительная литература
- •Глава 19
- •19.1. Снова архитектурноэкономический цикл
- •19.2. Создание архитектуры
- •19.3. Архитектура в рамках жизненного цикла
- •Влияние коммерческих компонентов
- •Заключение
- •8 Все перечисленные специалисты работают в корпорации Inmedius (Питтсбург, сша).
10.6. Пример
Процесс реконструкции мы проиллюстрируем типичным набором сегментов кода, составленных инструментарием Dali при восстановлении архитектуры UCMEdit - системы формирования и редактирования use case карт по Буру Мы покажем, за счет чего специалисту проводившему реконструкцию, удалось на основе необработанных данных, относящихся к нескольким извлеченным представлениям, составить простую и в то же время четкую картину программной архитектуры.
Извлечение информации
В табл. 10.2 представлены элементы и отношения, которые на первом этапе реконструкции удалось извлечь из исходного кода UCMEdit. Обращения к переменным — иными словами, отношения function_reads_variable и function_assigns_ variable — здесь не упоминаются. С другой стороны, поскольку эти отношения потенциально важны в контексте установления архитектурного сцепления, для их фиксации была проведена вторая операция извлечения. Для извлечения отношений file depends_on file проведена обработка выходных данных утилиты GNU make, запущенной со сборочным файлом приложения.
После извлечения необходимых представлений фильтруются «неинтересные» функции — в частности, встроенные функции наподобие return и стандартные функции из библиотек С, такие как scanf и printf.
Создание базы данных
Теперь извлеченными отношениями наполняется база данных SQL. Как мы уже говорили в разделе 10.3, в целях каталогизации элементов и отношений в базе данных создаются две добавочные таблицы: в одной идентифицируются все определенные элементы, а в другой перечисляются все идентифицированные типы отношений. В одном из полей таблицы элементов (под именем type) хранится информация о типе элемента (файл, функция и т. д.).
Объединение представлений и реконструкция
На рис. 10.9 показана необработанная извлеченная модель, состоящая из 830 узлов (элементов) и 2507 отношений. Теперь наша первоочередная задача попытаться как-то структурировать весь этот хаос, то есть приступить к исполнению сегментов кода.
Надежнее всего сначала сгруппировать функцию и все определяемые в ней локальные переменные в новый составной элемент. После исполнения показанного в листинге 10.2 сегмента кода модель UCMEdit все еще являет собой странного вида паутину из узлов и ребер, но она уже заметно проще, чем извлеченные представления (см. рис. 10.9) до исполнения сегментов кода группировки функций. Теперь в модели UCMEdit 710 узлов и 2321 отношение.
Как
мы знаем, UCMEdit является объектно-ориентированной
системой; этим знанием следует
воспользоваться при исполнении следующего
низкоуровневого сегмента кода. Схожий
по своему характеру с сегментом свернутых
функций, этот сегмент кода сводит воедино
классы, их переменные-члены и функции-члены,
отображая их в виде единого узла класса.
Модель, полученная по результатам его
исполнения, показана на рис. 10.4; в ней
всего 233 узла и 518 ребер — это значительное
визуальное упрощение, однако обработка
модели в такой форме все еще непрактична.
Элементов, не относящихся к какому бы то ни было извлеченному классу, до сих пор хватает. Причин для этого может быть две: дефект задействованных средств извлечения или отклонение решений от классического объектно-ориентированного проектирования. В данном случае справедливо и то и другое.
По результатам детального анализа выясняем, что ошибки исходят от сегментов кода извлечения, — вызовы функций-членов они выдают за вызовы глобальных функций. Кроме того, ряд функций, которые действительно являются глобальными, не обнаруживают принадлежности ни к одному из определенных в системе классов. Некоторые глобальные функции, выраженные в форме системных вызовов или примитивов системы управления окнами, естественно, необходимы. О том, как подобного рода «остаточные» явления отделить от остальной архитектуры, мы и поговорим далее.
На данном этапе модель UCMEdit представляет собой совокупность файлов, классов, остаточных функций и глобальных переменных. Локальные переменные сгруппированы с определяющими их функциями, а функции-члены и переменные-члены — с соответствующими классами. Глобальные переменные и функции теперь можно компоновать в файлы, в которых они определены, — делается это примерно так же, как компоновались функции и классы. В показанной на рис. 10.10 результирующей модели осталось три группы элементов: файлы, классы и остаточные функции. Прогресс в визуальном отображении опять налицо, но ,„-тинного удобства манипулирования еще далеко.
Все исполненные до настоящего момента сегменты кода, с одной стороны, независимы от конкретного применения, но с другой — связаны со специализированными методиками извлечения и предметной областью программ C++. В следующих наборах сегментов кода, которые нам предстоит исполнить, задействуются экспертные знания, связанные с архитектурой UCMEdit. Таким образом, процесс реконструкции отходит от механического анализа, подразумевающего применение готовых сегментов кода, в пользу методики адаптивного распознавания и определения образцов, использующей информацию об архитектуре системы, которой должны обладать ее проектировщик и опытные программисты.
Специализированные знания, которые мы применяем к рассматриваемой системе в первую очередь, можно сформулировать следующим образом.
♦ Это интерактивное графическое приложение.
♦ В ней реализуется попытка инкапсулировать обращения к нижележащей подсистеме управления окнами и графикой в рамках одного уровня.
♦ Функции, входящие в задействованные графические библиотеки (Xlib, X Forms и Mesa), придерживаются характерных соглашений по присваиванию имен.
Исходя из этих наблюдений разумно предположить существование архитектурных образцов — возможно, подсистем или отдельных образцов взаимодействия. По большому счету, эти предположения носят характер гипотез, для проверки которых мы должны убедиться в наличии или отсутствии образцов. Если результат упростит картину и окажется в согласии с нашими предположениями, значит, гипотеза верна и мы угадали ход мыслей архитектора. Даже если окажется, что мы заблуждались, в нашем распоряжении будет справедливая и полезная посылка к пониманию системы.
В представленных в листинге 10.5 сегментах кода, которые ориентированы на выявление графической подсистемы, внешние функции дополняют приложение функциональностью, связанной с отображением и взаимодействием. Рассмотрим первый сегмент кода — отфильтровывая все функции, являющиеся членами классов (тех, что выражены в виде поля tDefines в кортеже отношения defines_fn), он конструирует из таблицы elements новую таблицу. Затем он выбирает из новой таблицы все те функции, которые вызываются функциями, определенными в подклассах класса Presentation. Интересно, что этот сегмент кода ссылается на подклассы Presentation. Таким образом, он скрыто идентифицирует уровень, который, по мысли проектировщиков исходной системы, должен был инкапсулировать обращения к графической подсистеме. Эту информацию необходимо использовать в наших целях. Второй, третий и четвертый сегменты кода — именно в такой последовательности, — специфицируя сами себя именами функций, идентифицируют функции, определенные в библиотеках Mesa, XForms и Xlib соответственно.
Листинг 10.5. Сегменты кода графической подсистемы UCMEdit
# 1: Выявление вызовов с уровня доступа к графическим данным.
DROP TABLE tmp;
SELECT * INTO TABLE tmp FROM elements;
DELETE FROM tmp
WHERE tmp.tName=defines_fn.tDefines;
SELECT tl.tName
FROM tmp tl, calls cl, defines_fn dl, has_subclass si, has_subclass s2 WHERE tl.tName=cl.tCallee AND cl.tCaller=dl.tDefines AND dl.tDefined_by=sl.tSubclass AND sl.tSuperclass=’Presentation';
print "Graphics $fields[0]+ null\n";
# 2: Выявление вызовов функций Mesa.
SELECT tName
FROM elements
WHERE tType='Function' AND tName LIKE 'gl%'; print "Graphics $fields[0]+ null\n";
# 3: Выявление вызовов функций XForms.
SELECT tName
FROM elements
WHERE tType='Function' AND tName LIKE *f1_%1; print "Graphics $fields[0]+ null\n";
выявление вызовов функций XIib TABLE tmp;
0 SELECT * INTO TABLE tmp FROM elements;
DELETE FROM tmp
WHERE tmp.tName=defines_fn.tDefines-
SELECT cl.tName FROM tmp cl
WHERE tType='Function'
AND tName LIKE ’X%';
print "Graphics $fields[0]+ null\n";
Взятые в целом, сегменты кода 2, 3 и 4 идентифицируют архитектурный элемент Graphics, который не прослеживается среди извлеченной информации, но в то же время присутствует в проектной архитектуре. Это хороший пример сопоставления реализованного и проектного вариантов архитектуры, проводящегося путем последовательного исполнения сегментов кода. Его результаты применительно к модели UCMEdit показаны на рис. 10.11.
Го Тратите внимание: имена элементов, группируемых в рамках архитектурно- элемента Graphics, содержат символ «+», присоединенный представленны и на рисунке сегментами кода. Согласно этой методике, обращение к ранее сконструированным составным элементам производится без подачи со стороны сегментов кода явного запроса в базу данных.
На рис. 10.11 всего две остаточные функции: fabs и []; последняя, очевидно, появилась в результате ошибки при извлечении, а вот первая — это функция математической библиотеки, которую следовало отфильтровать раньше, вместе со стандартными функциями библиотек С и встроенными функциями. Как бы то ни было, ни одна из них не представляет для нас интереса, а значит, их можно безболезненно удалить из модели.
Распределение функций по категориям «интересные» и «неинтересные» зависит от задач реконструкции. Если специалиста по реконструкции интересует конкретный аспект системы — например, зависимость подсистем от библиотек для конкретной платформы или операционной системы, вряд ли он будет удалять упомянутые функции из конкретной модели; более вероятно, что он сгруппирует их на отдельном уровне, с тем чтобы проанализировать их применение остальной частью приложения. Но наша задача заключается в том, чтобы построить архитектурное отображение прикладной части системы, и поэтому мы можем себе позволить от них избавиться.
Второй общий прикладной сегмент кода основывается на знаниях об отношении между классами и файлами в рассматриваемых приложениях. Во-первых, в исходном файле (.сс) не могут содержаться функции, относящиеся к нескольким классам; во-вторых, в заголовочном файле (.h) не может быть определений для нескольких классов. Отсюда возможность установить уникальное отношение вложенности: любой класс состоит из заголовочного файла, в котором содержится его определение, и исходного файла, определяющего его функции. Сегмент кода, генерирующий эти группировки, показан в листинге 10.6
Листинг 10.6. Сегменты кода, направленные на установление вложенности классов/файлов SELECT DISTINCT tDefined_by FROM defi nes_fn;
print “$fields[0]+ $fields[0]+ Class $fields[0]++\n";
SELECT DISTINCT dl.tDefined_by, cl.tContainer FROM defines_fn dl, contains cl
WHERE cl.tContai nee=dl.tDefi nes ;
print "$fields[0]+ $fields[l]+ Class\n";
SELECT dl.tClass, dl.tFile FROM defines dl:
print "$fields[0]+ Sfields[1] Class\n";
Тот же пример иллюстрирует дополнительную характеристику подобных спецификаций — последнее поле в выражении peri, ассоциированном с первым сегментом кода ($fields[0]++), устанавливает переименование группируемого элемента. В этом сегменте кода происходит группировка классов в составные элементы (наличие в их именах замыкающих символов «+» связано с рассматриваемыми в разделе 10.4 сегментами кода для свертывания классов). Они получают имена
«eclass»*'. исходные композиты классов при этом переименовываются в <class>++. {V.ty-lbiaT показан на рис. 10.12.
UCMEdit замышлялась как макетная система, демонстрирующая преимущества компьютерного редактирования use case карт. Поскольку «реберное» архитектурное решение этого приложения в начале разработки не рассматривалось, идентификацию архитектурных элементов из конкретной модели приходится проводить исходя из структуры приложения на момент завершения разработки. Методом непосредственного манипулирования, изложенным ниже, мы постараемся экстраполировать наше понимание приложения на его модель.
Во-первых, нам известно (эти знания подтверждаются по результатам наблюдения за моделью), что центральным элементом в структуре приложения является callbacks.cc, — в нем содержатся все обработчики событий системы и большая часть реализации пользовательского интерфейса. Во-вторых, наблюдаются явные взаимосвязи между двумя оставшимися файлами и классами, с которыми они соединены: interpolate.сс ассоциируется исключительно с BSpline, а к fisheye.cc обращаются только Box и Component. В-третьих, мы можем еще раз задействовать знания 0 структуре уровня инкапсуляции графики, или представления (presentation); °н, как известно, выражается в классе Presentation и его подклассах. В-четвертых, по нашим наблюдениям, между классами List, Listltem и Listlterator существует функциональная связь, и, кроме того, к ним обращаются почти все остальные классы.
Все эти наблюдения реализуются путем:
♦ идентификации файла callbacks.сс с архитектурным элементом Interaction- + агрегирования файла interpolate.cc в элемент BSpline;
♦ агрегирования класса Presentation и его подклассов в элемент Presentation;
♦ агрегирования классов List, Listltem и Listlterator в элемент List, его сокрытия и трактовки в качестве «обслуживающего уровня».
Результаты внесения в модель всех этих изменений показаны на рис. 10.13.
На данном этапе следует тщательно обдумать варианты дальнейшего упрощения модели. Автоматическая кластеризация на основе теоретико-графовых свойств наподобие силы связей в нашем случае бесполезна. Есть и другой вариант - попытаться построить уровни исходя из организации, сгенерированной алгоритмом компоновки графа (рис. 10.13), однако в этом случае функциональная согласованность в рамках уровней оставляет желать лучшего. Другими словами, обе выдвинутые гипотезы не подтверждаются системой, и поэтому мы не настаиваем на их правомерности. Однако, с оглядкой на предметную область use case карт, мы возьмемся выдвинуть еще одну гипотезу.
Проанализировав понятия в use case картах, мы обнаружили, что элементы делятся на две широкие категории: одни связаны с компонентами, а другие — k ;Л I ими, и именно эти две основные конструкции составляют use case карту. rjynamicArrow, Path, Point, Responsibility, Segment, Stub и BSpline связаны с путями; gox. Component, Dependent, Handle и fisheye.ee — с компонентами. Результат кластеризации этих элементов на два архитектурных элемента — Path и Component — покапан на рис. 10.14.
По результатам проверки соединений между элементами все еще обнаруживайся большое количество взаимосвязей. В принципе, ничего страшного, однако этообстоятельство наводит на мысль о том, что архитектуре UCMEdit не хватает функциональной согласованности в рамках элементов и их соединений. f К сожалению, никаких более значительных усовершенствований в модель ' нам внести не удастся. У этой системы есть такой недостаток, как сложность отображения функциональности на программную структуру. Отсюда невозможность абстрагирования функционально связных элементов высокого уровня в- рамках архитектуры.
С другой стороны, накопленные знания позволяют сделать ряд предложений но усовершенствованию архитектуры и составить документацию. Последняя возможность представляет особую ценность, поскольку, как мы выяснили, системе UCMEdit не хватает концептуальной целостности, а это зачастую выводит на первый план интуитивное понимание.
