ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 20.11.2019
Просмотров: 9464
Скачиваний: 184

2.
ПРИЕМЫ
ОБЕСПЕЧЕНИЯ
ТЕХНОЛОГИЧНОСТИ
ПРОГРАММНЫХ
ПРОДУКТОВ
В
условиях
индустриального
подхода
к
разработке
и
сопровождению
программного
обеспечения
особый
вес
приобретают
технологические
характеристики
разрабатываемых
программ
.
Для
обеспечения
необходимых
технологических
свойств
применяют
специальные
технологические
приемы
и
следуют
определенным
методикам
,
сформулированным
всем
предыдущим
опытом
создания
программного
обеспечения
.
К
таким
приемам
и
методикам
относят
правила
декомпозиции
,
методы
проектирования
,
программирования
и
контроля
качества
,
которые
под
общим
названием
"
структурный
подход
к
программированию
»
были
сформулированы
еще
в
60-
х
голах
XX
в
.
В
его
основу
были
положены
следующие
основные
концепции
:
•
нисходящая
разработка
;
•
модульное
программирование
;
•
структурное
программирование
;
•
сквозной
структурный
контроль
.
2.1.
Понятие
технологичности
программного
обеспечения
Под
технологичностью
понимают
качество
проекта
программного
продукта
,
от
которого
зависят
трудовые
и
материальные
затраты
на
его
реализацию
и
последующие
модификации
.
Хороший
проект
сравнительно
быстро
и
легко
кодируется
,
тестируется
,
отлаживается
и
модифицируется
.
Из
опыта
нескольких
поколений
разработчиков
программного
обеспечения
известно
,
что
технологичность
программного
обеспечения
определяется
проработанностью
его
моделей
,
уровнем
независимости
модулей
,
стилем
программирования
и
степенью
повторного
использования
кодов
.
Чем
лучше
проработана
модель
разрабатываемого
программного
обеспечения
,
тем
четче
определены
подзадачи
и
структуры
данных
,
хранящие
входную
,
промежуточную
и
выходную
информацию
,
тем
проще
их
проектирование
и
реализация
и
меньше
вероятность
ошибок
,
для
исправления
которых
потребуется
существенно
изменять
программу
.
Чем
выше
независимость
модулей
,
тем
их
легче
понять
,
реализовывать
,
модифицировать
,
а
также
находить
в
них
ошибки
и
исправлять
их
.
Стиль
программирования
,
под
которым
понимают
стиль
оформления
программ
и
их
«
структурность
»,
также
существенно
влияет
на
читаемость
программного
кода
и
количество
ошибок
программирования
.
Кризис
60-
х
годов
XX
в
.
был
вызван
в
том
числе
и
стилем
программирования
,
при
котором
программа
напоминала
клубок
спутанных
ниток
или
блюдо
спагетти
,
и
отсутствием
языковых
конструкций
поддержки
«
структурного
»
стиля
.
Увеличение
степени
повторного
использования
кодов
предполагает
как
использование
ранее
разработанных
библиотек
подпрограмм
или
классов
,
так
и
унификацию
кодов
текущей
разработки
.
Причем
для
данного
критерия
ситуация
не
так
однозначна
,
как
в
предыдущих
случаях
:
если
степень
повторного
использования
кодов
повышается
искусственно
(
например
,
путем
разработки
«
суперуниверсальных
»
процедур
),
то
технологичность
проекта
может
существенно
снизиться
.
Как
следует
из
определения
,
высокая
технологичность
проекта
особенно
важна
,
если
разрабатывается
программный
продукт
,
рассчитанный
на
многолетнее
интенсивное
использование
,
или
необходимо
обеспечить
повышенные
требования
к
его
качеству
.
2.2.
Модули
и
их
свойства
При
проектировании
достаточно
сложного
программного
обеспечения
после
определения
его
общей
структуры
выполняют
декомпозицию
компонентов
в
соответствии
с
выбранным
подходом
до
получения
элементов
,
которые
,
по
мнению
проектировщика
,
в
дальнейшей
декомпозиции
не

нуждаются
.
Как
уже
упоминалось
раньше
,
в
настоящее
время
используют
два
способа
декомпозиции
разрабатываемого
программного
обеспечения
,
связанные
с
соответствующим
подходом
:
•
процедурный
(
или
структурный
-
по
названию
подхода
);
•
объектный
.
Примечание
.
Помимо
указанных
способов
декомпозиции
,
в
теории
программирования
определяют
и
другие
способы
декомпозиции
:
логическую
-
на
факты
и
правила
,
продукционную
-
на
правила
продукции
и
т
.
п
.
Эти
способы
декомпозиции
используют
в
языках
искусственного
интеллекта
,
поэтому
в
настоящем
учебнике
они
рассматриваться
не
будут
.
Результатом
процедурной
декомпозиции
является
иерархия
подпрограмм
(
процедур
),
в
которой
функции
,
связанные
с
принятием
решения
,
реализуются
подпрограммами
верхних
уровней
,
а
непосредственно
обработка
-
подпрограммами
нижних
уровней
.
Это
согласуется
с
принципом
вертикального
управления
,
который
был
сформулирован
вместе
с
другими
рекомендациями
структурного
подхода
к
программированию
.
Он
также
ограничивает
возможные
варианты
передачи
управления
,
требуя
,
чтобы
любая
подпрограмма
возвращала
управление
той
подпрограмме
,
которая
ее
вызвала
.
Результатом
объектной
декомпозиции
является
совокупность
объектов
,
которые
затем
реализуют
как
переменные
некоторых
специально
разрабатываемых
типов
(
классов
),
представляющих
собой
совокупность
полей
данных
и
методов
,
работающих
с
этими
полями
.
Таким
образом
,
при
любом
способе
декомпозиции
получают
набор
связанных
с
соответствующими
данными
подпрограмм
,
которые
в
процессе
реализации
организуют
в
модули
.
Модули
.
Модулем
называют
автономно
компилируемую
программную
единицу
.
Термин
«
модуль
»
традиционно
используется
в
двух
смыслах
.
Первоначально
,
когда
размер
программ
был
сравнительно
невелик
,
и
все
подпрограммы
компилировались
отдельно
,
под
модулем
понималась
подпрограмма
,
т
.
е
.
последовательность
связанных
фрагментов
программы
,
обращение
к
которой
выполняется
по
имени
.
Со
временем
,
когда
размер
программ
значительно
вырос
,
и
появилась
возможность
создавать
библиотеки
ресурсов
:
констант
,
переменных
,
описаний
типов
,
классов
и
подпрограмм
,
термин
«
модуль
»
стал
использоваться
и
в
смысле
автономно
компилируемый
набор
программных
ресурсов
.
Данные
модуль
может
получать
и
/
или
возвращать
через
общие
области
памяти
или
параметры
.
Первоначально
к
модулям
(
еще
понимаемым
как
подпрограммы
)
предъявлялись
следующие
требования
:
•
отдельная
компиляция
;
•
одна
точка
входа
;
•
одна
точка
выхода
;
•
соответствие
принципу
вертикального
управления
;
•
возможность
вызова
других
модулей
;
•
небольшой
размер
(
до
50-60
операторов
языка
);
•
независимость
от
истории
вызовов
;
•
выполнение
одной
функции
.
Требования
одной
точки
входа
,
одной
точки
выхода
,
независимости
от
истории
вызовов
и
соответствия
принципу
вертикального
управления
были
вызваны
тем
,
что
в
то
время
из
-
за
серьезных
ограничений
на
объем
оперативной
памяти
программисты
были
вынуждены
разрабатывать
программы
с
максимально
возможной
повторяемостью
кодов
.
В
результате
подпрограммы
,
имеющие
несколько
точек
входа
и
выхода
,
были
не
только
обычным
явлением
,
но
и
считались
высоким
классом
программирования
.
Следствием
же
было
то
,
что
программы
было
очень
сложно
не
только
модифицировать
,
но
и
понять
,
а
иногда
и
просто
полностью
отладить
.
Со
временем
,
когда
основные
требования
структурного
подхода
стали
поддерживаться
языками
программирования
,
и
под
модулем
стали
понимать
отдельно
компилируемую
библиотеку
ресурсов
,
требование
независимости
модулей
стало
основным
.

Практика
показала
,
что
чем
выше
степень
независимости
модулей
,
тем
:
•
легче
разобраться
в
отдельном
модуле
и
всей
программе
и
,
соответственно
,
тестировать
,
отлаживать
и
модифицировать
ее
;
•
меньше
вероятность
появления
новых
ошибок
при
исправлении
старых
или
внесении
изменений
в
программу
,
т
.
е
.
вероятность
появления
«
волнового
»
эффекта
;
•
проще
организовать
разработку
программного
обеспечения
группой
программистов
и
легче
его
сопровождать
.
Таким
образом
,
уменьшение
зависимости
модулей
улучшает
технологичность
проекта
.
Степень
независимости
модулей
(
как
подпрограмм
,
так
и
библиотек
)
оценивают
двумя
критериями
:
сцеплением
и
связностью
.
Сцепление
модулей
.
Сцепление
является
мерой
взаимозависимости
модулей
,
которая
определяет
,
насколько
хорошо
модули
отделены
друг
от
друга
.
Модули
независимы
,
если
каждый
из
них
не
содержит
о
другом
никакой
информации
.
Чем
больше
информации
о
других
модулях
хранит
модуль
,
тем
больше
он
с
ними
сцеплен
.
Различают
пять
типов
сцепления
модулей
:
•
по
данным
;
•
по
образцу
;
•
по
управлению
;
•
по
общей
области
данных
;
•
по
содержимому
.
Сцепление
по
данным
предполагает
,
что
модули
обмениваются
данными
,
представленными
скалярными
значениями
.
При
небольшом
количестве
передаваемых
параметров
этот
тип
обеспечивает
наилучшие
технологические
характеристики
программного
обеспечения
.
Например
,
функция
Мах
предполагает
сцепление
по
данным
через
параметры
скалярного
типа
:
Function Max(a, b: integer): integer;
begin
if a>b then Max:=a
else Max: =b;
end;
Сцепление
по
образцу
предполагает
,
что
модули
обмениваются
данными
,
объединенными
в
структуры
.
Этот
тип
также
обеспечивает
неплохие
характеристики
,
но
они
хуже
,
чем
у
предыдущего
типа
,
так
как
конкретные
передаваемые
данные
«
спрятаны
»
в
структуры
,
и
потому
уменьшается
«
прозрачность
»
связи
между
модулями
.
Кроме
того
,
при
изменении
структуры
передаваемых
данных
необходимо
модифицировать
все
использующие
ее
модули
.
Так
,
функция
MaxEl,
описанная
ниже
,
предполагает
сцепление
по
образцу
(
параметр
а
-
открытый
массив
).
Function MaxEl(a:array of integer): integer;
Var i:\vord;
begin
MaxEl: =a [O];
for i: =l to High (a) do
if a [i]>MaxEl then MaxEl: =a [i];
end;
При
сцеплении
по
управлению
один
модуль
посылает
другому
некоторый
информационный
объект
(
флаг
),
предназначенный
для
управления
внутренней
логикой
модуля
.
Таким
способом
часто
выполняют
настройку
режимов
работы
программного
обеспечения
.
Подобные
настройки
также
снижают
наглядность
взаимодействия
модулей
и
потому
обеспечивают
еще
худшие
ха
-
рактеристики
технологичности
разрабатываемого
программного
обеспечения
по
сравнению
с

предыдущими
типами
связей
.
Например
,
функция
MinMax
предполагает
сцепление
по
управлению
.
так
как
значение
параметра
flag
влияет
на
логику
программы
:
если
функция
MinMax
получает
значение
параметра
flag,
равное
true,
то
возвращает
максимальное
значение
из
двух
,
а
если
false,
то
минимальное
:
Function MinMax (a, b: integer; f!ag:boo!ean): integer;
begin
if(a>b) and (flag) then MinMax: =a
else MinMax: =b;
end;
Сцепление
по
общей
области
данных
предполагает
,
что
модули
работают
с
общей
областью
данных
.
Этот
тип
сцепления
считается
недопустимым
,
поскольку
:
•
программы
,
использующие
данный
тип
сцепления
,
очень
сложны
для
понимания
при
сопровождении
программного
обеспечения
;
•
ошибка
одного
модуля
,
приводящая
к
изменению
общих
данных
,
может
проявиться
при
выполнении
другого
модуля
,
что
существенно
усложняет
локализацию
ошибок
;
•
при
ссылке
к
данным
в
общей
области
модули
используют
конкретные
имена
,
что
уменьшает
гибкость
разрабатываемого
программного
обеспечения
.
Например
,
функция
МахА
,
использующая
глобальный
массив
А
,
сцеплена
с
основной
программой
по
общей
области
:
Function MaxA: integer;
Var i:word;
begin
МахА
: =a[Low(a)];
for i: = Low (a) + l to High(a) do
if a [i]>MaxA then MaxA: = a [i];
end;
Следует
иметь
в
виду
,
что
«
подпрограммы
с
памятью
»,
действия
которых
зависят
от
истории
вызовов
,
используют
сцепление
по
общей
области
,
что
делает
их
работу
в
общем
случае
непредсказуемой
.
Именно
этот
вариант
используют
статические
переменные
С
и
C++.
В
случае
сцепления
по
содержимому
один
модуль
содержит
обращения
к
внутренним
компонентам
другого
(
передает
управление
внутрь
,
читает
и
/
или
изменяет
внутренние
данные
или
сами
коды
),
что
полностью
противоречит
блочно
-
иерархическому
подходу
.
Отдельный
модуль
в
этом
случае
уже
не
является
блоком
(«
черным
ящиком
»):
его
содержимое
должно
учитываться
в
процессе
разработки
другого
модуля
.
Современные
универсальные
языки
процедурного
программирования
,
например
Pascal,
данного
типа
сцепления
в
явном
виде
не
поддерживают
,
но
для
языков
низкого
уровня
,
например
Ассемблера
,
такой
вид
сцепления
остается
возможным
.
В
табл
. 2.1
приведены
характеристики
различных
типов
сцепления
по
экспертным
оценкам
[21, 30].
Допустимыми
считают
первые
три
типа
сцепления
,
так
как
использование
остальных
приводит
к
резкому
ухудшению
технологичности
программ
.
Как
правило
,
модули
сцепляются
между
собой
несколькими
способами
.
Учитывая
это
,
качество
программного
обеспечения
принято
определять
по
типу
сцепления
с
худшими
характеристиками
.
Так
,
если
использовано
сцепление
по
данным
и
сцепление
по
управлению
,
то
определяющим
считают
сцепление
по
управлению
.
В
некоторых
случаях
сцепление
модулей
можно
уменьшить
,
удалив
необязательные
связи
и
структурировав
необходимые
связи
.
Примером
может
служить
объектно
-
ориентированное
программирование
,
в
котором
вместо
большого
количества
параметров
метод
неявно
получает
адрес
области
(
структуры
),
в
которой
расположены
поля
объекта
,
и
явно
-
дополнительные
параметры
.
В
результате
модули
оказываются
сцепленными
по
образцу
.

Таблица
2.1
Тип
сцепления
Сцепление
,
балл
Устойчивость
к
ошибкам
других
модулей
Наглядность
(
понятность
)
Возможность
изменения
Вероятность
повторного
использования
По
данным
По
образцу
По
управлению
По
общей
области
По
содержимому
1
3
4
6
10
Хорошая
*
Средняя
Средняя
Плохая
Плохая
Хорошая
Хорошая
*
Плохая
Плохая
Плохая
Хорошая
Средняя
Плохая
Средняя
Плохая
Большая
Средняя
Малая
Малая
Малая
Связность
модулей
.
Связность
-
мера
прочности
соединения
функциональных
и
информационных
объектов
внутри
одного
модуля
.
Если
сцепление
характеризует
качество
отделения
модулей
,
то
связность
характеризует
степень
взаимосвязи
элементов
,
реализуемых
одним
модулем
.
Размещение
сильно
связанных
элементов
в
одном
модуле
уменьшает
межмодульные
связи
и
,
соответственно
,
взаимовлияние
модулей
.
В
то
же
время
помещение
сильно
связанных
элементов
в
разные
модули
не
только
усиливает
межмодульные
связи
,
но
и
усложняет
понимание
их
взаимодействия
.
Объединение
слабо
связанных
элементов
также
уменьшает
технологичность
модулей
,
так
как
такими
элементами
сложнее
мысленно
манипулировать
.
Различают
следующие
виды
связности
(
в
порядке
убывания
уровня
):
•
функциональную
;
•
последовательную
;
•
информационную
(
коммуникативную
);
•
процедурную
;
•
временную
;
•
логическую
;
•
случайную
.
При
функциональной
связности
все
объекты
модуля
предназначены
для
выполнения
одной
функции
(
рис
. 2.1,
а
):
операции
,
объединяемые
для
выполнения
одной
функции
,
или
данные
,
связанные
с
одной
функцией
.
Модуль
,
элементы
которого
связаны
функционально
,
имеет
четко
определенную
цель
,
при
его
вызове
выполняется
одна
задача
,
например
,
подпрограмма
поиска
минимального
элемента
массива
.
Такой
модуль
имеет
максимальную
связность
,
следствием
которой
являются
его
хорошие
технологические
качества
:
простота
тестирования
,
модификации
и
сопровождения
.
Именно
с
этим
связано
одно
из
требований
структурной
декомпозиции
«
один
модуль
-
одна
между
модулями
-
библиотеками
ресурсов
.
Например
,
если
при
проектировании
текстового
редактора
предполагается
функция
редактирования
,
то
лучше
организовать
модуль
-
библиотеку
функций
редактирования
,
чем
поместить
часть
функций
в
один
модуль
,
а
часть
в
другой
.
При
последовательной
связности
функций
выход
одной
функции
служит
исходными
данными
для
другой
функции
(
рис
. 2.1,
б
).
Как
правило
,
такой
модуль
имеет
одну
точку
входа
,
т
.
е
.
реализует
одну
подпрограмму
,
выполняющую
две
функции
.
Считают
,
что
данные
,
используемые
последовательными
функциями
,
также
связаны
последовательно
.
Модуль
с
последовательной
связностью
функций
можно
разбить
на
два
или
более
модулей
,
как
с
последовательной
,
так
и
с
функциональной
связностью
.
Такой
модуль
выполняет
несколько
функций
,
и
,
следовательно
,
его
технологичность
хуже
:
сложнее
организовать
тестирование
,
а
при
выполнении
модификации
мысленно
приходится
разделять
функции
модуля
.