Использование IBM Rational Unified Process (RUP) для переработки устаревших систем

Philippe Dugerdil, Департамент информационных систем, HEG, Университет прикладных наук

Оригинал статьи: http://www.ibm.com/developerworks/rational/library/sep06/dugerdil/index.html?S_TACT=105AGX15&S_CMP=EDU

Картинка статьи об использовании IBM Rational Unified Process (RUP) для переработки устаревших систем

От журнала Rational Edge: Множество техник и инструментов предложено для переработки устаревших систем. Но все они редко описываются в контексте четко формализованного процесса. В этой статье показывается, как можно применить IBM Rational Unified Process для перепроектирования и, в особенности, для восстановления информации об архитектуре существующей системы.

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

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

Альтернативным путем становится их переработка, которая может быть поделена на два подпроекта: обратное проектирование или реинжиниринг (получение представления о существующем коде) и прямое проектирование (рефакторинг и/или переработка некоторых частей кода). В частности, одним из важнейших направлений при реинжиниринге является идентификация архитектуры системы. А это как раз то, где и силен RUP. В этой статье описывается ситуация, когда исходные разработчики устаревшей информационной системы по тем или иным причинам не могут предоставить информацию об изначальной структуре программы и отсутствует достоверная документация на нее. В этом случае наш процесс должен помочь в построении моделей на основе Unified Modeling Language (UML), которые позволят сформировать представление об архитектуре системы.

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

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

Процесс

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

  1. Оценка границ переработки
  2. Формирование абстрактных моделей
  3. Восстановление описания архитектуры системы

Рисунок 1 показывает, где на традиционном двухразмерном представлении жизненного цикла RUP расположены задачи, связанные с этими стадиями.

Задачи реинжиниринга на традиционной диаграмме IBM Rational Unified Process (RUP)

Рисунок 1: Три ключевых стадии нашего процесса по отношению к дисциплинам и фазам RUP

Если смотреть шире, то при проведении работ по переработке системы за проектом по реинжинирингу должен был бы последовать проект по ее рефакторингу, нацеленный на частичную или полную реструктуризацию/перепроектирование/переработку кода (redevelopment). Как раз именно здесь могла бы быть с успехом применена новая для многих устаревших систем парадигма -- сервис-ориентированная архитектура (service-oriented architecture или SOA). Несмотря на то, что эта статья акцентируется именно в области обратного проектирования, тем не менее, потенциально перспективные платформы или парадигмы всегда должны оцениваться на предмет их применимости к системе, подвергнутой реинжинирингу.

Оценка границ переработки

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

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

Как и в любом проекте, первоначальной задачей является разработка Концепции перерабатываемой системы (Vision). В частности, такой документ должен раскрыть необходимость самого проекта переработки, описать ограничения на перерабатываемую систему, а также осветить вопросы выбора технологий. Например, документ "Концепция" мог бы постановить, что целевой архитектурой должна быть SOA. В зависимости от размеров проекта информация из Концепции может быть развита в документе "Экономическое обоснование" (Business Case), в котором может быть выполнена точная оценка экономической актуальности этого проекта. Это есть результат выполнения задачи "Разработать экономическое обоснование" (Develop Business Case) в составе дисциплины "Управление проектом" (Project Management). Как альтернатива, целевые критерии качества системы, подвергаемой реинжинирингу, а также детализация технологических ограничений могут быть зафиксированы в документе "Дополнительные спецификации" (Supplementary Specifications), который появляется в результате выполнения задачи "Найти действующих лиц и сценарии использования" (Find Actors and Use Cases) дисциплины "Управление требованиями" (Requirements). Так как эти спецификации в нашем проекте распространяются на перерабатываемую систему, то результирующую систему (которая получается в результате всей работы) необходимо сравнивать на соответствие этим спецификациям. Далее в Списке рисков (Risk List) следует зафиксировать риски, когда указанные критерии не могут быть достигнуты, и действия для смягчения этих рисков. Список рисков создается в задаче "Идентифицировать и оценить риски" (Identify and Assess Risks) дисциплины "Управление проектом" (Project Management, Рисунок 2).

Оценка границ проекта на основе IBM Rational Unified Process (RUP) 

Рисунок 2: Оценка границ проекта

Следует отметить, что спецификация целевого критерия качества для обратно проектируемой системы не является спецификой нашей работы. Например, такой подход лежит в корне модели Horseshoe (SEI's Horseshoe model). Однако, выработать такой критерий в явном виде не так просто.

Формирование абстрактных моделей

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

Для иллюстрации данного парадокса Kazman и Carrière даже вводят понятие "разделяемая галлюцинация" (shared hallucination), чтобы описать процесс поиска архитектуры в устаревших системах (R. Kazman and J. Carrière, "Playing Detective: Reconstructing Software Architecture from Available Evidence," Software Engineering Institute, Carnegie Mellon University, Tech Report CMU/SEI-97-TR-010. Oct. 1997). Разумеется, программные системы промышленного применения являются крайне сложными продуктами. Строительство архитектурной модели требует понимания самой системы, т.к. часто нельзя получить большой пользы от исходного кода. Как дополнительное средство в развитии понимания системы, можно создать гипотетическую модель архитектуры, которая потенциально представлена кодом. Но эта архитектура должна быть до некоторой степени абстрактна, чтобы соответствовать широкому диапазону возможных вариантов модели уровня проектирования (design model), которые, по всей вероятности, мы обнаружим. Системная модель анализа (analysis model) RUP может решить эту проблему, потому что классические UML стереотипы классов анализа (для сущностных объектов -- entity, для интерфейсных или граничных -- boundary, для управляющих -- control) представляют три зоны ответственности, которые можно найти почти в любой информационной системе.

Пользователи обычно видят хорошие перспективы по отношению к устаревшей системе. И хотя у них может быть узкое представление о том, как система была спроектирована, они обычно хорошо знакомы с ее бизнес контекстом и актуальностью для бизнеса. Хотя они в целом не могут рассказать ничего о внутренней работе программного обеспечения, они обычно хорошо осведомлены о назначении программы и степени ее востребованности в бизнесе. Они хорошо знают, какая информация должна быть введена в систему и когда это лучше всего делать. Собирая информацию об эксплуатации системы от работающих с ней людей, мы можем восстановить цепочки процессов на бизнес уровне. Если говорить короче, то мы можем визуализировать бизнес процессы, для поддержки которых система создана, а также создать предполагаемую Концептуальную модель бизнеса (Domain model). Используя термины RUP, мы перестраиваем Модели бизнес сценариев (Business Use Case Model) и бизнес анализа (Business Analysis Model). Это делается при выполнении работ "Детализировать модель бизнес процессов" (Detail a Business Use Case), "Идентифицировать внутренних бизнес актеров и бизнес сущности" (Find Business Workers and Entities) и "Детализировать бизнес сущность" (Detail a Business Entity) дисциплины "Бизнес моделирование" (Business Modeling) из RUP. При этом происходит детализация описания бизнес процесса с помощью ролей и сущностей бизнеса.

Документирование поддерживаемого бизнес процесса и модели бизнес концепций 

Рисунок 3: Документирование поддерживаемого бизнес процесса и модели бизнес концепций

Для того, чтобы построить корректную концептуальную бизнес модель, необходимо проанализировать таблицы актуальной базы данных и зафиксировать их в Модели данных (Data Model). Это результат выполнения задачи "Выполнить анализ базы данных" (Database Analysis), которая не входит в стандартный RUP, но тесно связана с задачей "Выполнить проектирование базы данных" (Database Design) в рамках дисциплины "Анализ и проектирование" (Analysis & Design, Рисунок 4).

Анализ архитектуры актуальной базы данных 

Рисунок 4: Анализ архитектуры актуальной базы данных

В то же самое время кто-то занимается выявлением сценариев использования (use cases) системы, которые выполняются работающими в ней пользователями. Это позволяет оптимизировать Модель сценариев использования (Use-Cases model) в ходе задачи "Найти актеров и сценарии использования" (Find Actors and Use Cases) в дисциплине "Управление требованиями" (Requirements, Рисунок 5).

Построение модели сценариев использования 

Рисунок 5: Построение модели сценариев использования

Рисунок 6 объединяет первоначальные модели, которые мы на текущий момент сформировали. Сверху показаны актуальные пользователи (актеры системы) вместе с идентифицированными сценариями использования. Эти актеры соответствуют внутренним бизнес актерам (business workers), определенным в Модели бизнес анализа (Business Analysis Model). Совместно, задачи, выполняемые бизнес актерами, представляют шаги бизнес процесса, который автоматизирован нашим исходным программным обеспечением. Внизу рисунка показаны задокументированные таблицы базы данных системы. Некоторые из них соответствуют бизнес сущностям Модели бизнес анализа.

Первоначальные варианты моделей 

Рисунок 6: Первоначальные варианты моделей

Перед тем, как приступить к детализации сценариев использования, нам необходимо наметить план работы в соответствии со Списком рисков и Экономическим обоснованием проекта. Далее следует определить приоритеты для восстановленных требований (сценариев использования), что выполняется в соответствующей задаче RUP "Определить приоритеты для сценариев использования" (Prioritize the Use Case) дисциплины "Управление требованиями" (Requirements), и сформировать рабочий продукт "Атрибуты требований реинжиниринга" (Reverse-Engineering Requirement Attributes), который подобен репозиторию "Атрибуты требований" (Requirement Attributes) из RUP (Рисунок 7). По аналогии с традиционным RUP, Список рисков обновляется после окончательной оценки результатов текущей итерации и регистрации возникших трудностей (рабочий продукт "Оценка итерации" или "Iteration Assessment", который создается в рамках задачи "Оценить результаты итерации" или "Assess Iteration" из дисциплины "Управление проектом" или "Project Management").

Определение приоритетов рисков 

Рисунок 7: Определение приоритетов рисков

Следующая задача -- "Детализировать сценарий использования" (Detail a Use Case) из дисциплины "Управление требованиями" (Requirements) -- необходима для описания выбранных сценариев использования в виде потоков событий. Однако, поскольку сценарии использования создаются с помощью конечных пользователей, а не разработчиков, вряд ли стоит рассчитывать на их полноту. Но, тем не менее, они все же представляют основную часть функционала системы. Как только некоторые сценарии использования детализированы, мы переходим к Модели анализа из стандартной задачи "Выполнить анализ сценариев использования" (Use-Case Analysis) из дисциплины "Анализ и проектирование" (Analysis & Design) RUP (Рисунок 8).

Детализация сценариев использования и их анализ 

Рисунок 8: Детализация сценариев использования и их анализ

В этой аналитической работе мы используем техники преобразования понятий, документированные в RUP, и особенно, методы эвристического анализа для выявления объектов анализа (analysis objects) из системных сценариев использования. Чаще всего, бизнес сущности становятся сущностными объектами системы (entity objects), интерфейсы для действующих лиц (например, экранные формы приложения) становятся граничными объектами (boundary objects) и то, что отвечает за координацию выполнения сценария использования, представляется в виде управляющего объекта (control object). Рисунок 9 показывает взаимосвязи между элементами модели. Данная Модель анализа отображает гипотетическую архитектуру системы. Это, пожалуй, наилучшее предположение об архитектуре системы, которое мы можем сделать на текущий момент времени. В актуальном исходном коде мы могли бы найти программные элементы, которые наделены ответственностью граничных и сущностных объектов в той или иной форме. Однако, ответственности объектов управления будут разбросаны среди многих программных элементов. Суммируя вышесказанное, эта Модель анализа используется лишь для того, чтобы зафиксировать наши предположения по разделению ответственностей среди рассматриваемых элементов.

Модель анализа сценариев использования и ее трассировочные связи с другими элементами моделирования 

Рисунок 9:Модель анализа сценариев использования и ее трассировочные связи с другими элементами моделирования. Эти связи строятся на основе стандартного эвристического подхода RUP

Восстановление описания архитектуры системы

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

Этот шаг включает следующие задачи:

  • Выполнить анализ модели реализации (Implementation Model)
  • Запустить сценарии использования
  • Выполнить анализ графика вызовов
  • Выполнить мэппинг функций на Модель реализации
  • Проверить гипотетическую архитектуру на корректность
  • Перестроить высокоуровневую архитектуру

Выполнить анализ модели реализации

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

Частичная Модель реализации  

Рисунок 10: Частичная Модель реализации

В привычном RUP Модель реализации (Implementation Model) является результатом задачи "Структурировать Модель реализации" (Structure the Implementation Model) дисциплины "Реализация" (Implementation) (Рисунок 11). Однако, в нашем процессе архитектор движется к конечному результату в обратном направлении -- от кода (или от Модели реализации). В дальнейших задачах эта модель будет доработана.

Структурирование Модели реализации 

Рисунок 11: Структурирование Модели реализации

Запустить сценарии использования

В рамках данной задачи мы начинаем идентифицировать участки кода, ответственные за выполнение конкретных сценариев использования. При этом, во-первых, для продолжения работы мы должны выбрать бизнес процесс и связанные с ним сценарии использования в соответствии со списком установленных приоритетов. Так как не представляется возможным запустить в системе сценарии использования с применением всевозможных вариантов входных данных, мы должны ограничиться лишь типовыми значениями, которые рекомендованы конечными пользователями системы. Эта информация фиксируется в Сценарии запуска (Execution Case), который является результатом задачи "Определить детали запуска" (Define Execution Details). Здесь указываются входные параметры и условия выполнения сценариев использования. Эти рабочий продукт и задача названы по аналогии со Сценарием тестирования и задачей "Определить детали тестирования" (Define Test Details) из RUP. Далее мы запускаем выбранные сценарии использования и параллельно выполняем трассировку программного обеспечения, т.е. идентифицируем последовательность выполняемых функций или методов. Рисунок 12 представляет внутреннего бизнес-актера с соответствующим сценарием использования системы. Когда этот сценарий использования выполняется в соответствии со Сценарием запуска, происходит трассировка выполнения. Это делается либо с помощью дебаггера, либо с помощью специального инструмента, позволяющего фиксировать результаты трассировки в реальном времени. Указанные задачи выполняются новой ролью -- Аналитиком сценариев использования (Use-Case Analyst, Рисунок 13).

Трассировка выполнения сценария использования зафиксирована 

Рисунок 12: Трассировка выполнения сценария использования зафиксирована

Запуск сценариев использования 

Рисунок 13: Запуск сценариев использования

Выполнить анализ графика вызовов

Как было отмечено ранее, потоки событий сценариев использования, описанные по результатам интервью с конечными пользователями, скорее всего, будут неполными. Вряд ли мы получим, таким образом, полноценные альтернативные потоки событий. Соответственно, трассировка выполнения такого сценария использования не запустит все функции, которые реализуют этот сценарий. Чтобы их дополнить, мы должны последовательно определить все функции, которые вызываются трассируемыми функциями. Затем потребуется провести статический анализ кода и построить обобщенный граф вызовов, в направлении от функций трассировки. Такой граф вызовов является парой (N,R), где узлы в наборе N являются функциями и R -- отношениями вызова; т.е. существует связь между функциями f1 и f2, если реализация функции f1 включает вызов к f2 независимо от условий такого вызова. Обнаруженные таким образом функции являются расширенным набором функций сценария использования, а также функций, которые с большой долей вероятности выполняются при запуске сценариев использования во всевозможных случаях. По факту, промежуточный продукт "Расширенный набор функций" (Extended Set of Functions) будет включать значительно большее число функций, чем это действительно необходимо. Их можно, до некоторой степени, упорядочить по реализуемым ими сценариям использования.

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

Граф вызовов, представляющий расширенный набор функций 

Рисунок 14: Граф вызовов, представляющий расширенный набор функций

Данная задача выполняется новой ролью -- Аналитик реализации (Implementation Analyst, Рисунок 15).

Анализ графа вызовов функций трассировки 

Рисунок 15: Анализ графа вызовов функций трассировки

Выполнить мэппинг функций на Модель реализации

Как только зафиксирован расширенный набор функций для конкретного сценария использования, необходимо выполнить их мэппинг на элементы сформированной ранее Модели реализации. В основном, все функции должны быть определены в рамках либо некоторого класса, либо файла. Этот мэппинг позволит нам найти такие элементы Модели реализации, которые участвуют в реализации сценариев использования в рамках предопределенного бизнес процесса. На рисунке 16 показано, что все желтые классы и пакеты реализуют Сценарий использования 1 (Use Case 1), т.е. Участвуют в бизнес процессе, выполняемом Пользователем 1 (User 1).

Мэппинг от расширенного набора функций к Модели реализации 

Рисунок 16: Мэппинг от расширенного набора функций к Модели реализации

Для необъектно ориентированных программных систем вместо классов участвуют файлы. Результат выполнения этой задачи сохраняется в скорректированном документе "Описание архитектуры системы" (Software Architecture Document). Данная задача выполняется Аналитиком реализации (Рисунок 17).

Анализ мэппинга функций на Модель реализации 

Рисунок 17: Анализ мэппинга функций на Модель реализации

Проверить гипотетическую архитектуру на корректность

В этой точке процесса нам известны функции/процедуры/классы/файлы/пакеты, которые реализуют сценарии использования. Теперь мы должны использовать эту информацию для проверки гипотетической архитектуры системы (Модели анализа), которую мы представили на более раннем шаге. Во-первых, мы детально просматриваем исходный код расширенного набора функций на предмет их доступа к какой-либо таблице базы данных или файлу. В них могут быть представлены реальные (или потенциальные) данные, используемые при выполнении сценария использования. Во-вторых, как только соответствующие таблицы или файлы идентифицированы, классы или файлы с функциями для работы с указанными таблицами или файлами сравниваются с тем, что присутствует в Модели анализа. При необходимости вносятся соответствующие коррекции в эту модель. В зависимости от технологии реализации анализируемой системы, таблицы или файлы могут быть объявлены как вне программного кода (например, в пакетной программе COBOL, запущенной под управлением IBM MVS, ресурсные файлы объявляются на языке управления заданиями JCL) и/или непосредственно внутри нее. Техники поиска этой информации крайне специфичны для той или иной реализации системы, но в целом все же могут быть применены, т.к. каждый язык включает специфические операторы ввода-вывода, которые вполне можно поискать в коде. Рисунок 18 представляет процедуру проверки валидности сущностных объектов. С одной стороны, расширенный набор функций помогает нам в поиске целевых таблиц базы данных. С другой стороны, эти функции ввода-вывода (методы) содержатся в классах реализации. Затем связываем все вместе через предполагаемые сущностные объекты.

Проверка сущностных объектов 

Рисунок 18: Проверка сущностных объектов

Далее работаем с граничными объектами (экранами и интерфейсами). В этом случае ищем любые функции в исходном коде, имеющее отношение к выводу данных на экран. После этого обнаруженные классы или файлы сравниваются с содержимым Модели анализа и, если потребуется, последняя корректируется. Эти функции работы с экраном являются крайне специфичными к среде и языку разработки. В лучшем случае они достаточно хорошо документированы в системных руководствах и их идентификация не должна представлять особенной сложности. Рисунок 19 представляет проверку валидности граничных объектов. Справа находится расширенный функций и в нем с помощью документации на систему осуществляется поиск экранных функций. Затем происходит идентификация обнаруженных классов. Эти классы сравниваются на соответствие ожидаемым граничным объектам, находящимся слева.

Проверка валидности граничных объектов 

Рисунок 19: Проверка валидности граничных объектов

Теперь мы можем сделать начальное допущение, что оставшиеся классы (полученные после мэппинга функций расширенного набора на Модель реализации) связаны с управляющим объектом, как это показано на Рисунке 20. Точечные линии отображают обнаруженные трассировочные связи от Модели анализа к Модели реализации. Результатом этой задачи является обновленный документ "Описание архитектуры системы". Выполняется такая задача Аналитиком реализации (Рисунок 21).

Карта связей классов анализа на классы реализации 

Рисунок 20: Карта связей классов анализа на классы реализации

Проверка валидности гипотетической архитектуры 

Рисунок 21: Проверка валидности гипотетической архитектуры

Перестроить высокоуровневую архитектуру

На этом этапе нам требуется упорядочить элементы кода по сценариям использования и перестроить соответствующие части верхнеуровневого описания архитектуры. Сначала мы должны работать на уровне классов и файлов. Затем следует углубиться в код. Давайте рассмотрим набор сценариев использования UC, который мы получили в результате реинжиниринга UC= {UC1...UC2}, и определим следующие три функции:

  • classes(UCi): возвращает набор всех классов, связанных со сценарием использования UCi, и, кроме всего прочего, включающих расширенный набор функций этого сценария.
  • specific(UCi): возвращает набор классов , включающих только специфичные функции для сценария использования UCi.
  • common({UC1...UCk}): возвращает набор классов с общим функционалом для набора сценариев использования {UC1...UCk}.

Тогда мы получаем:

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

Набор общих классов для набора сценариев использования просто определяется, как:

Набор общих классов для набора сценариев использования  

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

Анализ специфических и общих классов реализации сценариев использования 

Рисунок 22: Анализ специфических и общих классов реализации сценариев использования

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

  • Группировку по типам объектов анализа (например, по граничным классам)
  • Группировку по сценариям использования (например, отбираем классы, которые реализуют тот или иной сценарий использования)
  • Группировку по источнику информации (например, группируем по классам, которые работают с конкретной базой данных)
  • Группировка по актерам (например, разделяем на классы, которые отвечают за взаимодействие с тем или иным типом или ролью конечных пользователей)

Более того, мы можем одновременно использовать несколько критериев. В результате этого шага получаем эскиз верхнеуровневой архитектуры в соответствии с принятыми критериями группировки. Например, Рисунок 23 представляет группировку по сценарям использования, где общим является сценарий использования (подфункция) и для сценария "UseCase1", и для "UseCase2" (Subfunction Use Case 1). Однако, рисунок также показывает, что некоторый общий код совсем необязательно должен принадлежать реализации вспомогательного сценария использования (UC-common 1-2).

Группировка классов реализации по сценариям использования 

Рисунок 23: Группировка классов реализации по сценариям использования

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

Группировка классов реализации по сценариям использования и ответственностям 

Рисунок 24: Группировка классов реализации по сценариям использования и ответственностям

Важно отметить, что если какая-то, пусть даже небольшая, логическая группировка была давно сделана еще в начале разработки целевой системы, может быть и такое, что эти методы группировки не соблюдались в течение многих лет сопровождения (P. Tonella and A. Potrich, Reverse-Engineering of Object Oriented Code. Springer 2005). В этом случае некоторая очевидная группировка может включать классы, которые не соответствуют критерию. Результат выполнения данной задачи фиксируется в обновленном Описании архитектуры системы. Эта задача по восстановлению описания архитектуры выполняется Архитектором (Software Architect, Рисунок 25).

Перестройка верхнеуровневой архитектуры 

Рисунок 25: Перестройка вырхнеуровневой архитектуры

Резюме нашего процесса

Таблица 1 суммирует основные задачи и рабочие продукты нашего процесса. Элементы, окрашенные в зеленый цвет, взяты из RUP. Так как третий шаг нашего процесса связан с анализом реального кода, то в RUP не существует эквивалентной дисциплины. Поэтому, новая задача "Анализ базы данных" проводится в рамках дисциплины "Анализ и проектирование" (Analysis & Design). С другой стороны, реконструкция верхнеуровневой архитектуры из запуска сценариев использования проводится в рамках дисциплины "Реализация" (Implementation). Это ведет нас к необходимости определения двух новых ролей в процессе: Аналитик сценариев использования и Аналитик реализации, а также семи новых задач.

Таблица 1: Основные задачи и рабочие продукты нашего процесса

Дисциплина

Задача

Рабочий продукт

Бизнес моделирование

Детализировать модель бизнес процессов

Экономическое обоснование

Бизнес моделирование

Идентифицировать внутренних бизнес актеров и бизнес сущности

Модель бизнес анализа

Бизнес моделирование

Детализировать бизнес сущность

Бизнес сущность

Управление требованиями

Разработать концепцию

Концепция

Управление требованиями

Найти актеров и сценарии использования

Дополнительная спецификация требований

Управление требованиями

Найти актеров и сценарии использования

Модель сценариев использования

Управление требованиями

Определить приоритеты для сценариев использования

Атрибуты требований реинжиниринга

Управление требованиями

Детализировать сценарий использования

Сценарий использования

Анализ и проектирование

Выполнить анализ базы данных

Модель данных

Анализ и проектирование

Выполнить анализ сценариев использования

Модель анализа

Реализация

Выполнить анализ модели реализации

Модель реализации

Реализация

Определить детали запуска

Сценарий запуска

Реализация

Запустить сценарии использования

Трассировка выполнения сценария использования

Реализация

Выполнить анализ графика вызовов

Расширенный набор функций

Реализация

Выполнить мэппинг функций на Модель реализации

Описание архитектуры системы

Реализация

Проверить гипотетическую архитектуру на корректность

Описание архитектуры системы

Реализация

Перестроить высокоуровневую архитектуру

Описание архитектуры системы

Управление проектом

Разработать экономическое обоснование

Экономическое обоснование

Управление проектом

Идентифицировать и оценить риски

Список рисков

Управление проектом

Оценить результаты итерации

Оценка итерации

Контрольные точки в нашем процессе

Цель реинжинирингового проекта заключается в переделке устаревшей программной системы, так чтобы были улучшены хотя бы какие-то характеристики качества (See J. Bergey et al., Op. cit).Такая переделка могла бы привести к коррекции технологической базы, например, миграции на технологию SOA. Но при этом, какая бы технология ни была выбрана, проект по реинжинирингу должен оценить применимость к системе желаемой технологии. Фактически, даже если цель заключается в простом моделировании существующего решения, обязательно следует построить прототипы миграции некоторых ключевых компонент, чтобы проверить возможность этого.

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

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

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

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

Заключение

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

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