ГЛАВА 7

К оглавлению1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 
34 35 36 

СРЕДСТВА СТРУКТУРНОГО ПРОЕКТИРОВАНИЯ

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

Проектирование - фаза ЖЦ, на которой вырабатывается, как реализуются требования пользователя, которые порождены и зафиксированы на фазе анализа. На этом этапе осуществляется построение модели реализации (или физической модели), демонстрирующей, как система будет удовлетворять предъявленным к ней требованиями (без технических подробностей). Модель реализации является расширением модели требований и состоит из взаимоувязанных диаграмм (DFD, STD, ERD, структурные карты), текстов и словаря данных. Фактически структурное проектирование является мостом между структурным анализом и реализацией.

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

7.1. Структурные карты Константайна

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

модуль состоит из множества операторов языка программирования, записанных последовательно;

модуль имеет имя, по которому к нему можно ссылаться как к единому фрагменту;

модуль может принимать и/или передавать данные как параметры в вызывающей последовательности или связывать данные через фиксированные ячейки или общие области.

Структурные карты Константайна являются моделью отношений иерархии между программными модулями. Узлы структурных карт соответствуют модулям и областям данных, потоки изображают межмодульные вызовы. При этом циклические и условные вызовы модулей моделируются специальными узлами, поэтому потоки должны быть изображены проходящими через эти специальные узлы. Межмодульные связи по данным и управлению также моделируются специальными узлами, привязанными к потокам (т.е. к вызовам модулей), стрелками указываются направления потоков и связей. Фундаментальные элементы структурных карт в соответствии со стандартами IBM, ISO и ANSI приведены на рис. 7.1.

Базовым элементом структурной карты является модуль. Возможно использовать различные типы модулей (см. рис. 7.2):

Собственно МОДУЛЬ. Используется для представления обрабатывающего фрагмента для его локализации на диаграмме.

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

БИБЛИОТЕКА. Отличается от подсистемы тем, что определена вне проекта данной системы.

ОБЛАСТЬ ДАННЫХ. Используется для указания модулей, содержащих исключительно области глобальных/распределенных данных.

При построении структурных карт добавление модулей и увязывание их вместе осуществляется с использований потоков, демонстрирующих иерархию вызовов. Типы используемых при этом потоков приведены на рис. 7.3. При последовательном вызове модули вызываются в порядке их следования. При параллельном вызове модули могут вызываться в любом порядке или одновременно (параллельно).

Для моделирования условных и циклических вызовов применяются следующие узлы (рис. 7.4):

 

Рис. 7.1. Элементы структурных карт

Условный узел используется для условного вызова модуля-потомка. Он изображается с помощью ромба, потоки - альтернативные вызовы изображаются выходящими из него. Таким образом, если из ромба выходят два потока, это соответствует конструкции IF-THEN-ELSE, если один поток - конструкции IF-THEN.

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

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

 

Рис. 7.2. Типы модулей

Рис.7.3. Типы вызовов модулей


Рис. 7.4. Условные и циклические вызовы модулей

Связи по данным и управлению между модулями (передаваемые как параметры) раскрываются аннотированием потоков-вызовов (рис. 7.5). Стрелками отмечаются направления связей.

Рис. 7.5. Связи по данным и управлению

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

Рис. 7.6. Пример структурной карты Константайна

7.2. Структурные карты Джексона

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

По аналогии со структурными картами Константайна диаграмма Джексона может включать объекты следующих типов:

СТРУКТУРНЫЙ блок (базовая компонента методологии) представляет частную функцию или блок кодов с одним входом и одним выходом.

ПРОЦЕДУРНЫЙ блок является специальным видом структурного блока, представляющим вызов ранее определенной процедуры.

БИБЛИОТЕЧНЫЙ блок аналогичен процедурному и представляет вызов библиотечного модуля.

Для взаимоувязывания блоков используются связи следующих типов:

последовательная связь, обеспечивающая последовательное выполнение слева направо;

параллельная связь, обеспечивающая одновременное выполнение блоков;

условная связь, обеспечивающая выбор одной из альтернатив;

итерационная связь, обеспечивающая выполнение блока в цикле.

Пример структурной карты Джексона приведен на рис. 7.7.

7.3. Характеристики хорошей модели реализации

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

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

Рис 7.7. Структурная карта Джексона

7.3.1. Сцепление

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

уменьшение количества соединений между двумя модулями приводит к уменьшению вероятности появления “волнового эффекта” (ошибка в одном модуле влияет на работу других модулей);

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

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

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

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

удаления необязательных связей;

уменьшения количества необходимых связей;

упрощением необходимых связей.

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

Создавайте минимальные по количеству параметров межмодульные связи.

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

Создавайте локализованные связи (например, значения списка параметров вычисляйте непосредственно перед вызовом модуля).

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

Создавайте гибкие связи для облегчения модификаций.

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

Два модуля А и В являются нормально сцепленными, если

А вызывает В,

В возвращает управление А,

вся информация, передаваемая между А и В, представляется значениями параметров при вызове.

Существует три типа нормального сцепления: сцепление по данным, сцепление по образцу, сцепление по управлению. На практике наиболее часто используемым типом сцепления является сцепление по данным (data coupling). Два модуля сцеплены по данным, если они взаимодействуют через передачу параметров и при этом каждый параметр является элементарным информационным объектом. В случае небольшого количества передаваемых параметров сцепление по данным обладает наилучшими характеристиками в соответствии с п.п.1-5.

Два модуля сцеплены по образцу (stamp coupling), если один посылает другому составной информационный объект, т.е. объект, имеющий внутреннюю структуру. Примером составного объекта может быть объект Данные о клиенте, включающий в себе поля: Название организации, Почтовый адрес, Номер счета и т.п.

Два модуля сцеплены по управлению (control coupling), если один посылает другому информационный объект - флаг, предназначенный для управления его внутренней логикой. Существует два типа флагов - описательный и управляющий. Описательный флаг обычно описывает ситуацию, которая произошла, и именуются с использованием существительных и прилагательных: Конец файла, Введенная кредитная карта. Управляющий флаг используется для декларирования определенных действий в вызываемом модуле и именуется с использованием глаголов: Читать следующую запись, Установить в начало. В общем случае управляющие флаги усиливают сцепление и, следовательно, ухудшают качество проекта.

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

Два модуля являются сцепленными по общей области (common coupling), если они ссылаются к одной и той же области глобальных данных. Сцепление по общей области является плохим по следующим причинам. Во-первых, ошибка в любом модуле, использующем глобальную область, может неожиданно проявить себя в любом другом модуле, также использующем эту глобальную область, поскольку эти глобальные данные не находятся “под защитой” модуля. Во-вторых, модули, ссылающиеся к глобальным данным, обычно используют точные имена (в отличие от модулей, которые вызываются с использованием параметров). Следовательно, гибкость модулей, сцепленных глобально, намного хуже, чем гибкость нормально сцепленных модулей. В-третьих, программы с большим количеством глобальных данных чрезвычайно трудны для понимания сопровождающим программистом, поскольку трудно определить, какие данные используются отдельным модулем.

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

Таблица 7.1

Тип сцепления

Устойчивость к волновому эффекту

Модифи-цируемость

Понят-ность

Используемость в других системах

data coupling

*

хорошая

хорошая

хорошая

stamp coupling

*

средняя

средняя

средняя

control coupling

средняя

плохая

плохая

плохая

common coupling

плохая

средняя

плохая

плохая

content coupling

плохая

плохая

плохая

плохая

* Зависит от количества параметров интерфейса.

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

В таблице 7.1 приведены конкретные характеристики каждого типа сцепления.

7.3.2. Связность

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

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

Функционально связный модуль содержит объекты, предназначенные для выполнения одной и только задачи, например: Расчет заработанной платы, Считывание данных кредитной карты. Каждый из этих модулей имеет одну четко определенную цель, при его вызове выполняется только одна задача (при этом она выполняется полностью без исполнения любого другого дополнительного действия).

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

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

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

1. Сделать зарядку

2. Принять душ

3. Сварить кофе

4. Одеться

5. Отправиться на службу

Отправиться на службу - это последний шаг, внесенный в список этого "модуля". Но, например, действия Прочитать газету или Сходить в магазин могут быть в равной степени пригодными кандидатами для шага 5, поскольку шаги в этом списке связаны только тем, что они происходят в данном порядке в течение конкретного дня.

Временно связным является модуль, объекты которого включены в подзадачи, связанные временем исполнения. Представим себе картину позднего вечера:

1. Почистить зубы

2. Выключить телевизор

3. Выгнать кота в коридор

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

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

Поехать автомобилем

Поехать поездом

Поплыть на корабле

Полететь на самолете

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

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

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

1.Ремонтировать автомобиль

Пить пиво

Смотреть фильм

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

В таблице 7.2 приведены конкретные характеристики каждого уровня связности.

Таблица 7.2

 

Уровень связности

Сцепление

Модифици-руемость

Понятность

Сопровож-даемость

функциональная

хорошее

хорошая

хорошая

хорошая

последовательная

хорошее

хорошая

близкая к хорошей

хорошая

информационная

среднее

средняя

средняя

средняя

процедурная

переменная

переменная

переменная

плохая

временная

плохое

средняя

средняя

плохая

логическая

плохое

плохая

плохая

плохая

случайная

плохое

плохая

плохая

плохая

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

7.3.3. Другие принципы проектирования

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

1) Принцип факторизации. Под факторизацией понимается выделение подзадачи, реализуемой некоторым модулем, в новый самостоятельный модуль. Это может быть сделано по следующим резонам:

чтобы уменьшить размеры модуля;

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

чтобы избегать дублирования подзадачи, выполняемой более чем одним модулем;

чтобы отделить собственно вычисления от управления (вызовы и принятия решения);

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

чтобы упростить реализацию.

2) Принцип единства решения. Процесс любого решения состоит из двух частей: распознавания того, какое действие выбрать, и исполнения этого действия. Поскольку эти две составляющие решения очень различны, информационные объекты, используемые при распознавании и исполнении также могут существенно различаться и, следовательно, могут быть недоступными в одном модуле. Такая ситуация получила название расщепления решения (decision split). Сильное расщепление решения (хотя иногда расщепления не удается избежать) обычно является симптомом плохой организации модулей. Исполнительная часть решения должна располагаться как можно ближе к распознавательной части, чтобы распознанной информации не пришлось долго “блуждать” для того, чтобы быть обработанной.

3) Обработка ошибок. Сообщения об ошибках целесообразно формировать и визуализировать в модуле, который ошибку обнаруживает (и, следовательно, “знает”, что это за ошибка). Тексты сообщений рекомендуется хранить вместе по следующим резонам:

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

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

Легче избежать дублирования сообщений.

Облегчается модификация сообщений (включая их перевод на другой язык).

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

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

6) Компромисс между ограниченностью и обобщенностью. Ограниченный модуль обладает по крайней мере одной из следующих характеристик:

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

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

Он включает в себя условия о месте и способе его использования.

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

Он выполняет нелепо обширную работу. Примером является модуль, формирующий расписание игр чемпионата по футболу как по Грегорианскому, так и по Юлианскому календарю.

Он имеет дело с слишком избыточными типами данных, их значениями и структурами. Например, использование числа типа REAL вместо INTEGER для того, чтобы следить за количеством болтов на складе, было бы чрезмерным обощением.

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

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

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

7.4. Транзакционный и трансформационный анализ или как получить структурные карты из диаграмм потоков данных

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

разбиение иерархии диаграмм потоков данных на относительно легко поддающиеся обработке единицы средствами транзакционного анализа;

конвертирование каждой единицы в “хорошую” структурную карту средствами трансформационного анализа;

обратное соединение разделенных единиц в полную модель реализации.

Определим транзакцию как объект, содержащий следующие пять компонент:

СОБЫТИЕ в системе или ее внешнем окружении

СИГНАЛ к системе

ДЕЙСТВИЕ системы

ОТКЛИК от системы

ВЛИЯНИЕ на систему или ее окружение

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

СОБЫТИЕ Диспетчер замечает, что корабль движется слишком быстро

СИГНАЛ Замедлить скорость корабля на 210 м/сек

ДЕЙСТВИЕ Определить какой из тормозных ракетных двигателей включить и на какое время

ОТКЛИК Сигнал тормозному двигателю ракеты для его включения на 4.8 сек

ВЛИЯНИЕ Корабль замедлил скорость на 210 м/сек

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

СОБЫТИЕ Владелец дачи Сергей Чеченин устал пилить и колоть дрова для камина и решил установить газовое отопление

СИГНАЛ Информация о г-не Чеченине и его даче, а также дата начала обслуживания

ДЕЙСТВИЕ Добавить данные о г-не Чеченине в базу данных клиентов

ОТКЛИК Разрешение на предоставление услуг

ВЛИЯНИЕ В освободившееся от дровяных работ время г-н Чеченин проектирует систему автоматизации газовой компании

Отметим, что подобные отдельные транзакции относятся к классам, определяемым как классы транзакционного типа. Например, три транзакции "ДОБАВИТЬ ЧЕЧЕНИНА", "ДОБАВИТЬ ИВАНОВА" и "ДОБАВИТЬ ПЕТРОВА" являются примерами одного транзакционного типа, который может быть назван "ДОБАВИТЬ НОВОГО КЛИЕНТА".

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

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

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

выявление центрального преобразования - фрагмента DFD, который содержит концептуальные функции системы и не зависит от особенностей реализации системных входов и выходов;

конвертирование DFD в предварительную структурную карту;

доработка этой структурной карты средствами структурного проектирования;

проверка окончательной структурной карты на соответствие требованиям первоначальной DFD.

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

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

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

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

Добавить модули обработки ошибок.

Добавить детали инициализации и завершения, если требуется.

Проконтролировать, что все модули имеют имена в соответствии с их положением в иерархии.

Добавить все связи по данным и управлению, которые являются необходимыми на структурной схеме, но не на DFD, например, информация: "конец потока".

Проверить все критерии структурного проектирования и улучшить проект в соответствии с этими критериями.

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

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

СРЕДСТВА СТРУКТУРНОГО ПРОЕКТИРОВАНИЯ

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

Проектирование - фаза ЖЦ, на которой вырабатывается, как реализуются требования пользователя, которые порождены и зафиксированы на фазе анализа. На этом этапе осуществляется построение модели реализации (или физической модели), демонстрирующей, как система будет удовлетворять предъявленным к ней требованиями (без технических подробностей). Модель реализации является расширением модели требований и состоит из взаимоувязанных диаграмм (DFD, STD, ERD, структурные карты), текстов и словаря данных. Фактически структурное проектирование является мостом между структурным анализом и реализацией.

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

7.1. Структурные карты Константайна

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

модуль состоит из множества операторов языка программирования, записанных последовательно;

модуль имеет имя, по которому к нему можно ссылаться как к единому фрагменту;

модуль может принимать и/или передавать данные как параметры в вызывающей последовательности или связывать данные через фиксированные ячейки или общие области.

Структурные карты Константайна являются моделью отношений иерархии между программными модулями. Узлы структурных карт соответствуют модулям и областям данных, потоки изображают межмодульные вызовы. При этом циклические и условные вызовы модулей моделируются специальными узлами, поэтому потоки должны быть изображены проходящими через эти специальные узлы. Межмодульные связи по данным и управлению также моделируются специальными узлами, привязанными к потокам (т.е. к вызовам модулей), стрелками указываются направления потоков и связей. Фундаментальные элементы структурных карт в соответствии со стандартами IBM, ISO и ANSI приведены на рис. 7.1.

Базовым элементом структурной карты является модуль. Возможно использовать различные типы модулей (см. рис. 7.2):

Собственно МОДУЛЬ. Используется для представления обрабатывающего фрагмента для его локализации на диаграмме.

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

БИБЛИОТЕКА. Отличается от подсистемы тем, что определена вне проекта данной системы.

ОБЛАСТЬ ДАННЫХ. Используется для указания модулей, содержащих исключительно области глобальных/распределенных данных.

При построении структурных карт добавление модулей и увязывание их вместе осуществляется с использований потоков, демонстрирующих иерархию вызовов. Типы используемых при этом потоков приведены на рис. 7.3. При последовательном вызове модули вызываются в порядке их следования. При параллельном вызове модули могут вызываться в любом порядке или одновременно (параллельно).

Для моделирования условных и циклических вызовов применяются следующие узлы (рис. 7.4):

 

Рис. 7.1. Элементы структурных карт

Условный узел используется для условного вызова модуля-потомка. Он изображается с помощью ромба, потоки - альтернативные вызовы изображаются выходящими из него. Таким образом, если из ромба выходят два потока, это соответствует конструкции IF-THEN-ELSE, если один поток - конструкции IF-THEN.

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

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

 

Рис. 7.2. Типы модулей

Рис.7.3. Типы вызовов модулей


Рис. 7.4. Условные и циклические вызовы модулей

Связи по данным и управлению между модулями (передаваемые как параметры) раскрываются аннотированием потоков-вызовов (рис. 7.5). Стрелками отмечаются направления связей.

Рис. 7.5. Связи по данным и управлению

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

Рис. 7.6. Пример структурной карты Константайна

7.2. Структурные карты Джексона

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

По аналогии со структурными картами Константайна диаграмма Джексона может включать объекты следующих типов:

СТРУКТУРНЫЙ блок (базовая компонента методологии) представляет частную функцию или блок кодов с одним входом и одним выходом.

ПРОЦЕДУРНЫЙ блок является специальным видом структурного блока, представляющим вызов ранее определенной процедуры.

БИБЛИОТЕЧНЫЙ блок аналогичен процедурному и представляет вызов библиотечного модуля.

Для взаимоувязывания блоков используются связи следующих типов:

последовательная связь, обеспечивающая последовательное выполнение слева направо;

параллельная связь, обеспечивающая одновременное выполнение блоков;

условная связь, обеспечивающая выбор одной из альтернатив;

итерационная связь, обеспечивающая выполнение блока в цикле.

Пример структурной карты Джексона приведен на рис. 7.7.

7.3. Характеристики хорошей модели реализации

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

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

Рис 7.7. Структурная карта Джексона

7.3.1. Сцепление

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

уменьшение количества соединений между двумя модулями приводит к уменьшению вероятности появления “волнового эффекта” (ошибка в одном модуле влияет на работу других модулей);

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

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

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

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

удаления необязательных связей;

уменьшения количества необходимых связей;

упрощением необходимых связей.

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

Создавайте минимальные по количеству параметров межмодульные связи.

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

Создавайте локализованные связи (например, значения списка параметров вычисляйте непосредственно перед вызовом модуля).

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

Создавайте гибкие связи для облегчения модификаций.

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

Два модуля А и В являются нормально сцепленными, если

А вызывает В,

В возвращает управление А,

вся информация, передаваемая между А и В, представляется значениями параметров при вызове.

Существует три типа нормального сцепления: сцепление по данным, сцепление по образцу, сцепление по управлению. На практике наиболее часто используемым типом сцепления является сцепление по данным (data coupling). Два модуля сцеплены по данным, если они взаимодействуют через передачу параметров и при этом каждый параметр является элементарным информационным объектом. В случае небольшого количества передаваемых параметров сцепление по данным обладает наилучшими характеристиками в соответствии с п.п.1-5.

Два модуля сцеплены по образцу (stamp coupling), если один посылает другому составной информационный объект, т.е. объект, имеющий внутреннюю структуру. Примером составного объекта может быть объект Данные о клиенте, включающий в себе поля: Название организации, Почтовый адрес, Номер счета и т.п.

Два модуля сцеплены по управлению (control coupling), если один посылает другому информационный объект - флаг, предназначенный для управления его внутренней логикой. Существует два типа флагов - описательный и управляющий. Описательный флаг обычно описывает ситуацию, которая произошла, и именуются с использованием существительных и прилагательных: Конец файла, Введенная кредитная карта. Управляющий флаг используется для декларирования определенных действий в вызываемом модуле и именуется с использованием глаголов: Читать следующую запись, Установить в начало. В общем случае управляющие флаги усиливают сцепление и, следовательно, ухудшают качество проекта.

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

Два модуля являются сцепленными по общей области (common coupling), если они ссылаются к одной и той же области глобальных данных. Сцепление по общей области является плохим по следующим причинам. Во-первых, ошибка в любом модуле, использующем глобальную область, может неожиданно проявить себя в любом другом модуле, также использующем эту глобальную область, поскольку эти глобальные данные не находятся “под защитой” модуля. Во-вторых, модули, ссылающиеся к глобальным данным, обычно используют точные имена (в отличие от модулей, которые вызываются с использованием параметров). Следовательно, гибкость модулей, сцепленных глобально, намного хуже, чем гибкость нормально сцепленных модулей. В-третьих, программы с большим количеством глобальных данных чрезвычайно трудны для понимания сопровождающим программистом, поскольку трудно определить, какие данные используются отдельным модулем.

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

Таблица 7.1

Тип сцепления

Устойчивость к волновому эффекту

Модифи-цируемость

Понят-ность

Используемость в других системах

data coupling

*

хорошая

хорошая

хорошая

stamp coupling

*

средняя

средняя

средняя

control coupling

средняя

плохая

плохая

плохая

common coupling

плохая

средняя

плохая

плохая

content coupling

плохая

плохая

плохая

плохая

* Зависит от количества параметров интерфейса.

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

В таблице 7.1 приведены конкретные характеристики каждого типа сцепления.

7.3.2. Связность

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

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

Функционально связный модуль содержит объекты, предназначенные для выполнения одной и только задачи, например: Расчет заработанной платы, Считывание данных кредитной карты. Каждый из этих модулей имеет одну четко определенную цель, при его вызове выполняется только одна задача (при этом она выполняется полностью без исполнения любого другого дополнительного действия).

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

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

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

1. Сделать зарядку

2. Принять душ

3. Сварить кофе

4. Одеться

5. Отправиться на службу

Отправиться на службу - это последний шаг, внесенный в список этого "модуля". Но, например, действия Прочитать газету или Сходить в магазин могут быть в равной степени пригодными кандидатами для шага 5, поскольку шаги в этом списке связаны только тем, что они происходят в данном порядке в течение конкретного дня.

Временно связным является модуль, объекты которого включены в подзадачи, связанные временем исполнения. Представим себе картину позднего вечера:

1. Почистить зубы

2. Выключить телевизор

3. Выгнать кота в коридор

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

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

Поехать автомобилем

Поехать поездом

Поплыть на корабле

Полететь на самолете

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

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

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

1.Ремонтировать автомобиль

Пить пиво

Смотреть фильм

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

В таблице 7.2 приведены конкретные характеристики каждого уровня связности.

Таблица 7.2

 

Уровень связности

Сцепление

Модифици-руемость

Понятность

Сопровож-даемость

функциональная

хорошее

хорошая

хорошая

хорошая

последовательная

хорошее

хорошая

близкая к хорошей

хорошая

информационная

среднее

средняя

средняя

средняя

процедурная

переменная

переменная

переменная

плохая

временная

плохое

средняя

средняя

плохая

логическая

плохое

плохая

плохая

плохая

случайная

плохое

плохая

плохая

плохая

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

7.3.3. Другие принципы проектирования

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

1) Принцип факторизации. Под факторизацией понимается выделение подзадачи, реализуемой некоторым модулем, в новый самостоятельный модуль. Это может быть сделано по следующим резонам:

чтобы уменьшить размеры модуля;

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

чтобы избегать дублирования подзадачи, выполняемой более чем одним модулем;

чтобы отделить собственно вычисления от управления (вызовы и принятия решения);

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

чтобы упростить реализацию.

2) Принцип единства решения. Процесс любого решения состоит из двух частей: распознавания того, какое действие выбрать, и исполнения этого действия. Поскольку эти две составляющие решения очень различны, информационные объекты, используемые при распознавании и исполнении также могут существенно различаться и, следовательно, могут быть недоступными в одном модуле. Такая ситуация получила название расщепления решения (decision split). Сильное расщепление решения (хотя иногда расщепления не удается избежать) обычно является симптомом плохой организации модулей. Исполнительная часть решения должна располагаться как можно ближе к распознавательной части, чтобы распознанной информации не пришлось долго “блуждать” для того, чтобы быть обработанной.

3) Обработка ошибок. Сообщения об ошибках целесообразно формировать и визуализировать в модуле, который ошибку обнаруживает (и, следовательно, “знает”, что это за ошибка). Тексты сообщений рекомендуется хранить вместе по следующим резонам:

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

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

Легче избежать дублирования сообщений.

Облегчается модификация сообщений (включая их перевод на другой язык).

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

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

6) Компромисс между ограниченностью и обобщенностью. Ограниченный модуль обладает по крайней мере одной из следующих характеристик:

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

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

Он включает в себя условия о месте и способе его использования.

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

Он выполняет нелепо обширную работу. Примером является модуль, формирующий расписание игр чемпионата по футболу как по Грегорианскому, так и по Юлианскому календарю.

Он имеет дело с слишком избыточными типами данных, их значениями и структурами. Например, использование числа типа REAL вместо INTEGER для того, чтобы следить за количеством болтов на складе, было бы чрезмерным обощением.

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

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

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

7.4. Транзакционный и трансформационный анализ или как получить структурные карты из диаграмм потоков данных

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

разбиение иерархии диаграмм потоков данных на относительно легко поддающиеся обработке единицы средствами транзакционного анализа;

конвертирование каждой единицы в “хорошую” структурную карту средствами трансформационного анализа;

обратное соединение разделенных единиц в полную модель реализации.

Определим транзакцию как объект, содержащий следующие пять компонент:

СОБЫТИЕ в системе или ее внешнем окружении

СИГНАЛ к системе

ДЕЙСТВИЕ системы

ОТКЛИК от системы

ВЛИЯНИЕ на систему или ее окружение

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

СОБЫТИЕ Диспетчер замечает, что корабль движется слишком быстро

СИГНАЛ Замедлить скорость корабля на 210 м/сек

ДЕЙСТВИЕ Определить какой из тормозных ракетных двигателей включить и на какое время

ОТКЛИК Сигнал тормозному двигателю ракеты для его включения на 4.8 сек

ВЛИЯНИЕ Корабль замедлил скорость на 210 м/сек

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

СОБЫТИЕ Владелец дачи Сергей Чеченин устал пилить и колоть дрова для камина и решил установить газовое отопление

СИГНАЛ Информация о г-не Чеченине и его даче, а также дата начала обслуживания

ДЕЙСТВИЕ Добавить данные о г-не Чеченине в базу данных клиентов

ОТКЛИК Разрешение на предоставление услуг

ВЛИЯНИЕ В освободившееся от дровяных работ время г-н Чеченин проектирует систему автоматизации газовой компании

Отметим, что подобные отдельные транзакции относятся к классам, определяемым как классы транзакционного типа. Например, три транзакции "ДОБАВИТЬ ЧЕЧЕНИНА", "ДОБАВИТЬ ИВАНОВА" и "ДОБАВИТЬ ПЕТРОВА" являются примерами одного транзакционного типа, который может быть назван "ДОБАВИТЬ НОВОГО КЛИЕНТА".

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

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

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

выявление центрального преобразования - фрагмента DFD, который содержит концептуальные функции системы и не зависит от особенностей реализации системных входов и выходов;

конвертирование DFD в предварительную структурную карту;

доработка этой структурной карты средствами структурного проектирования;

проверка окончательной структурной карты на соответствие требованиям первоначальной DFD.

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

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

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

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

Добавить модули обработки ошибок.

Добавить детали инициализации и завершения, если требуется.

Проконтролировать, что все модули имеют имена в соответствии с их положением в иерархии.

Добавить все связи по данным и управлению, которые являются необходимыми на структурной схеме, но не на DFD, например, информация: "конец потока".

Проверить все критерии структурного проектирования и улучшить проект в соответствии с этими критериями.

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

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