
- •О. В. Шишов технология разработки программных продуктов
- •1. Программы и программирование
- •1.1 Основные определения
- •1.2. Классификация программ и различные виды программирования
- •1.3. Категории специалистов, занятых разработкой и эксплуатацией программ
- •2. Жизненный цикл программного обеспечения
- •2.1 Основные этапы жизненного цикла и их взаимосвязь
- •2.2 Стратегии и модели жизненного цикла
- •3. Качество по
- •3.1 Критерии оценки качества по
- •3.2 Методы оценки качества программного средства
- •4. Надежность программных продуктов
- •4.1 Надежность и виды отказов
- •4.2 Надежность и правильность программы
- •4.3. Вероятностный подход к оценке надежности
- •4.4 Факторы надежности
- •4.5 Приемы надежного программирования
- •6.2. Стандарты технологии создания программных продуктов
- •6.3. Основные этапы технологического процесса разработки программ
- •7. Структурное проектирование программных продуктов
- •7.1. Модули. Сцепление и связность модулей
- •7.2. Структура программных продуктов
- •7.3. Методы структурного программирования
- •8. Алгоритмическое представление задачи программирования
- •8.1. Свойства алгоритмов
- •8.2. Формы записи алгоритмов
- •8.3. Базовые алгоритмические структуры
- •9. Языки программирования
- •9.1. Основные понятия и элементы языков программирования
- •9.2. Классификация языков программирования
- •9.3. Развитие языков программирования
- •10. Пользовательский интерфейс
- •10.1. Типы интерфейсов
- •10.2. Этапы разработки пользовательского интерфейса
- •10.3. Критерии оценки интерфейса пользователем
- •11. Порядок работы эвм при выполнении программ. Трансляторы, интерпритаторы, компиляторы
- •12. Оптимизация программ
- •13. Отладка и тестирование программного обеспечения
- •13.1. Классификация неисправностей и ошибок в программе
- •13.2. Порядок и способы отладки и тестирования программ
- •13.3. Методы тестирования
- •13.4. Требования и рекомендации по тестированию программ
- •13.4. Программирование «с защитой от ошибок»
- •14. Аттестация программного средства
- •15. Сопровождение по
- •16. Защита программных продуктов
- •16.1. Обеспечение защищенности программных средств
- •16.3. Правовые методы защиты программных продуктов
- •17. Документорование программных продуктов
- •17.1. Виды программных документов
- •17.2. Содержание документации по еспд
- •17.3. Стиль оформления программы
- •Содержание
7. Структурное проектирование программных продуктов
По мере развития вычислительной техники стала резко возрастать сложность программ. Они становились слишком велики для того, чтобы их можно было охватить и представить как единое целое. Общий принцип, используемый человеком при решении любых сложных задач, состоит в дроблении их на мелкие подзадачи, в установлении между ними связей и решении каждой из них независимо. Так и в программировании общее признание получил принцип построения программ из отдельных программных модулей, каждый из которых представляет завершенную программу, где решается часть общей задачи.
Структурное программирование (СП) является одним из методов улучшения программы. Оно предназначено для организации проектирования программ и процесса кодирования. Таким образом, чтобы предотвратить большинство логических ошибок и обнаружить те, которые допущены.
Модульное программирование – это процесс разделения программы на логические части, называемые модулями, и последовательное программирование каждой части. Когда большая единая задача делиться на подзадачи, то значительно проще прочесть и понять программу. Если проведено программирование всей задачи сверху – вниз, то она естественно разбивается на подзадачи для возможных модулей. При этом преследуется две цели:
-
необходимость добиться того, чтобы программный модуль был правильным и не зависел от контекста в котором он будет использоваться
-
следует стремиться к тому, чтобы из модулей можно было формировать большие программы без каких-либо предварительных значений о внутренней работе модуля.
Перечислим некоторые достоинства структурного программирования:
-
Структурное программирование позволяет значительно сократить число вариантов построения программы по одной и той же спецификации, что приводит к значительно снижает сложность программы.
-
В структурированных программах логически связанные операторы находятся визуально ближе, а слабо связанные дальше, что позволяет обходится без блок схем и других графических форм изображения алгоритмов.
-
Сильно упрощается процесс тестирования и отладки структурированных программ.
-
более высокую производительность работы за счет того, что действие каждой управляющей структуры хорошо известно и нет необходимости его обдумывать;
-
ясность и читаемость программ;
-
более высокую эффективность за счет глобальной оптимизации программы.
7.1. Модули. Сцепление и связность модулей
Модуль – это самостоятельная часть программы, имеющая определенное назначение и обеспечивающая заданные функции обработки автономно от других программных модулей.
Разделение ПО на модули необходимо для упрощения их реализации, облегчения чтения программы и работы с данными, имеющими сложную структуру. Выделение модулей позволяет избежать чрезмерной детализации алгоритмов больших программ: перенести подробное рассмотрение реализации тех или иных действий на алгоритмы модулей. Колоссальные трудности вызывает отладка больших программ, но их можно свести к минимуму, если отлаживать программу по частям – модулям, логически связанным между собой, но функционально обособленным.
Кроме этого структуризация программных продуктов преследует цели:
-
распределить работы по исполнителям, обеспечив приемлемую их загрузку и требуемые сроки разработки программных продуктов;
-
построить календарные графики проектных работ и осуществлять их координацию в процессе создания программных изделий;
-
контролировать трудозатраты и стоимость проектных работ и др.
Структурное «разбиение» программ на отдельные составляющие служит основой и для выбора инструментальных средств их создания, хотя имеет место и обратное влияние – выбор инструментальных средств разработчика программного обеспечения определяет типы программных модулей.
Структуризация программ выполняется в первую очередь для удобства разработки, программирования, отладки и внесения изменений в программный продукт. Как правило, программные комплексы большой алгоритмической сложности разрабатываются коллективом разработчиков (2–15 и более человек).
Термин «модуль» традиционно используется в двух смыслах. Первоначально, когда размер программ был сравнительно невелик, и все подпрограммы компилировались отдельно, под модулем понималась подпрограмма, т. е. последовательность связанных фрагментов программы, обращение к которой выполняется по имени. Со временем, когда размер программ значительно вырос, и появилась возможность создавать библиотеки ресурсов: констант, переменных, описаний типов, классов и подпрограмм, термин «модуль» стал использоваться и в смысле автономно компилируемый набор программных ресурсов.
К модулям предъявляются следующие требования:
-
отдельная компиляция;
-
один вход и один выход – на входе программный модуль получает определенный набор исходных данных, выполняет содержательную обработку и возвращает один набор результатных данных, т. е. реализуется стандартный принцип IPO (Input – Process – Output) – вход-процесс-выход;
-
выполнение минимального числа функций.
-
функциональная завершенность – модуль выполняет перечень регламентированных операций для реализации каждой отдельной функции в полном составе, достаточных для завершения начатой обработки;
-
логическая независимость – результат работы программного модуля зависит только от исходных данных, но не зависит от работы других модулей;
-
слабые информационные связи с другими программными модулями – обмен информацией между модулями должен быть по возможности минимизирован;
-
соответствие принципу вертикального управления;
-
возможность вызова других модулей;
-
обозримый по размеру и сложности программный элемент;
-
независимость от истории вызовов;
Требования одной точки входа, одной точки выхода, независимости от истории вызовов и соответствия принципу вертикального управления вызваны тем, что в ранее из-за серьезных ограничений на объем оперативной памяти программисты были вынуждены разрабатывать программы с максимально возможной повторяемостью кодов. В результате подпрограммы, имеющие несколько точек входа и выхода, были не только обычным явлением, но и считались высоким классом программирования. Следствием же было то, что программы было очень сложно не только модифицировать, но и понять, а иногда и просто полностью отладить.
Со временем, когда основные требования структурного подхода стали поддерживаться языками программирования, и под модулем стали понимать отдельно компилируемую библиотеку ресурсов, требование независимости модулей стало основным.
Следует стремиться к независимости между модулями или программами. Для достижения этого требуется, чтобы модуль не зависел от:
1) источника входных данных;
2) местоназначения выходных данных;
3) от предистории.
Каждый модуль должен иметь свое назначение, отличающееся от назначения других модулей. Это должен быть замкнутый блок, вход и выход которого четко определены. Стремление к независимости хорошо тем, что изменения в одном модуле (подпрограмме) влияют на другую часть программы. Воздействие изменения в одном модуле на другую часть программы называется волновым эффектом. Этот эффект можно уменьшить сведя к минимуму связь между модулями, т. е. сократить количество путей вдоль которых изменения или ошибки могут проникнуть в другие части. Простой путь уменьшения волнового эффекта – избегать использование глобальных перемен и делать модуль небольшим. Минимизация взаимосвязи между модулями – это модульное сцепление, которое происходит за счет усиления связей между элементами одного модуля (модульная прочность). Таким образом тесно связанные элементы надо стремиться поместить в один модуль. Использование модулей приводит к уменьшению сложностей, факторы сложности при этом включают три составляющие:
1) функциональная сложность – обусловлено тем, что один модуль выполняет слишком много функций;
2) распределенная сложность – это сложность идентификации общей функции распределенной между несколькими модулями за счет чего утрачивается возможность уменьшения сложности всей программы при модульном программировании;
3) сложность связи – определяется сложностью взаимодействия модулей, при использовании общих данных.
Практика показала, что чем выше степень независимости модулей, тем:
• легче разобраться в отдельном модуле и всей программе и, соответственно, тестировать, отлаживать и модифицировать ее;
• меньше вероятность появления новых ошибок при исправлении старых или внесении изменений в программу, т. е. вероятность появления «волнового» эффекта;
• проще организовать разработку программного обеспечения группой программистов и легче его сопровождать.
Таким образом, уменьшение зависимости модулей улучшает технологичность проекта.
Степень независимости модулей (как подпрограмм, так и библиотек) оценивают двумя критериями: сцеплением и связностью.
Сцепление модулей. Сцепление является мерой взаимозависимости модулей, которая определяет, насколько хорошо модули отделены друг от друга. Модули независимы, если каждый из них не содержит о другом никакой информации. Чем больше информации о других модулях хранит модуль, тем больше он с ними сцеплен.
Различают пять типов сцепления модулей:
• по данным;
• по образцу;
• по управлению;
• по общей области данных;
• по содержимому.
Сцепление по данным предполагает, что модули обмениваются данными, представленными скалярными значениями. При небольшом количестве передаваемых параметров этот тип обеспечивает наилучшие технологические характеристики программного обеспечения.
Сцепление по образцу предполагает, что модули обмениваются данными, объединенными в структуры. Этот тип также обеспечивает неплохие характеристики, но они хуже, чем у предыдущего типа, так как конкретные передаваемые данные «спрятаны» в структуры, и потому уменьшается «прозрачность» связи между модулями. Кроме того, при изменении структуры передаваемых данных необходимо модифицировать все использующие ее модули.
При сцеплении по управлению один модуль посылает другому некоторый информационный объект (флаг), предназначенный для управления внутренней логикой модуля. Таким способом часто выполняют настройку режимов работы программного обеспечения. Подобные настройки также снижают наглядность взаимодействия модулей и потому обеспечивают еще худшие характеристики технологичности разрабатываемого программного обеспечения по сравнению с предыдущими типами связей.
Сцепление по общей области данных предполагает, что модули работают с общей областью данных. Однако:
• программы, использующие данный тип сцепления, очень сложны для понимания при сопровождении программного обеспечения;
• ошибка одного модуля, приводящая к изменению общих данных, может проявиться при выполнении другого модуля, что существенно усложняет локализацию ошибок;
• при ссылке к данным в общей области модули используют конкретные имена, что уменьшает гибкость разрабатываемого программного обеспечения.
Связность модулей. Связность – мера прочности соединения функциональных и информационных объектов внутри одного модуля. Если сцепление характеризует качество отделения модулей, то связность характеризует степень взаимосвязи элементов, реализуемых одним модулем. Размещение сильно связанных элементов в одном модуле уменьшает межмодульные связи и, соответственно, взаимовлияние модулей. В то же время помещение сильно связанных элементов в разные модули не только усиливает межмодульные связи, но и усложняет понимание их взаимодействия. Объединение слабо связанных элементов также уменьшает технологичность модулей, так как такими элементами сложнее мысленно манипулировать.
Различают следующие виды связности (в порядке убывания уровня):
• функциональную;
• последовательную;
• информационную (коммуникативную);
• процедурную;
• временную;
• логическую;
• случайную.
При функциональной связности все объекты модуля предназначены для выполнения одной функции: операции, объединяемые для выполнения одной функции, или данные, связанные с одной функцией. Модуль, элементы которого связаны функционально, имеет четко определенную цель, при его вызове выполняется одна задача, например, подпрограмма поиска минимального элемента массива. Такой модуль имеет максимальную связность, следствием которой являются его хорошие технологические качества: простота тестирования, модификации и сопровождения. Именно с этим связано одно из требований структурной декомпозиции «один модуль – одна между модулями - библиотеками ресурсов. Например, если при проектировании текстового редактора предполагается функция редактирования, то лучше организовать модуль – библиотеку функций редактирования, чем поместить часть функций в один модуль, а часть в другой.
При последовательной связности функций выход одной функции служит исходными данными для другой функции. Как правило, такой модуль имеет одну точку входа, т. е. реализует одну подпрограмму, выполняющую две функции. Считают, что данные, используемые последовательными функциями, также связаны последовательно. Модуль с последовательной связностью функций можно разбить на два или более модулей, как с последовательной, так и с функциональной связностью. Такой модуль выполняет несколько функций, и, следовательно, его технологичность хуже: сложнее организовать тестирование, а при выполнении модификации мысленно приходится разделять функции модуля.
Информационно связанными считают функции, обрабатывающие одни и те же данные. При использовании структурных языков программирования раздельное выполнение функций можно осуществить только, если каждая функция реализуется своей подпрограммой функцией.
Процедурно связаны функции или данные, которые являются частями одного процесса. Обычно модули с процедурной связностью функций получают, если в модуле объединены функции альтернативных частей программы. При процедурной связности отдельные элементы модуля связаны крайне слабо, так как реализуемые ими действия связаны лишь общим процессом, следовательно, технологичность данного вида связи ниже, чем предыдущего.
Временная связность функций подразумевает, что эти функции выполняются параллельно или в течение некоторого периода времени. Временная связность данных означает, что они используются в некотором временном интервале. Например, временную связность имеют функции, выполняемые при инициализации некоторого процесса. Отличительной особенностью временной связности является то, что действия, реализуемые такими функциями, обычно могут выполняться в любом порядке. Содержание модуля с временной связностью функций имеет тенденцию меняться: в него могут включаться новые действия и/или исключаться старые.
Большая вероятность модификации функции еще больше уменьшает показатели технологичности модулей данного вида по сравнению с предыдущим.
Логическая связь базируется на объединении данных или функций в одну логическую группу. В качестве примера можно привести функции обработки текстовой информации или данные одного и того же типа. Модуль с логической связностью функций часто реализует альтернативные варианты одной операции, например, сложение целых чисел и сложение вещественных чисел. Из такого модуля всегда будет вызываться одна какая-либо его часть, при этом вызывающий и вызываемый модули будут связаны по управлению. Понять логику работы модулей, содержащих логически связанные компоненты, как правило, сложнее, чем модулей, использующих временную связность, следовательно, их показатели технологичности еще ниже.
В том случае, если связь между элементами мала или отсутствует, считают, что они имеют случайную связность. Модуль, элементы которого связаны случайно, имеет самые низкие показатели технологичности, так как элементы, объединенные в нем, вообще не связаны.