Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Учебник ТРПП.doc
Скачиваний:
30
Добавлен:
23.04.2019
Размер:
7.83 Mб
Скачать
  • Физическое проектирование – реализация даталогической модели средствами конкретной СУБД, а также выбор решений, связанных с физической средой хранения данных: выбор методов управления дисковой памятью, методов доступа к данным, методов сжатия данных и т.д. – эти задачи решаются в основном средствами СУБД и скрыты от разработчика БД.

    На основе ER-модели по определённым правилам строится даталогическая модель, т.е. набор таблиц. База данных, построенная таким образом, обычно находится в четвёртой нормальной форме. Основные преимущества ER-моделей:

    1. наглядность;

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

    3. ER - модели реализованы во многих системах автоматизированного проектирования баз данных (например, ERWin).

    Контрольные вопросы

    1. Кто является автором ER-модели?

    2. Когда была предложена ER – модель?

    3. Как переводится название ER-модели?

    4. Перечислите базовые понятия ER-модели.

    5. Дайте понятие сущности.

    6. Какие типы связи возможны между сущностями?

    7. Что обозначает связь «один-к-одному»?

    8. Что обозначает связь «один-ко-многим»?

    9. Что обозначает связь «многие-ко-многим»?

    10. Что понимают под обязательностью и необязательностью связи?

    11. Допускаются ли в ER–модели подтипы сущности? Что такое суперсущность?

    12. На каком этапе проектирования БД строятся ER-модели?

    13. Укажите достоинства ER-моделей.

    Глава 10. Стиль программирования

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

    1. Три подхода к программированию

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

    1. Императивный стиль. Самым распространенным классом языков программирования является класс императивных языков (они еще известны под названием операторных). К ним относятся и Паскаль, и Бейсик, и даже Си++, несмотря на всю его объектную ориентированность. Императивный подход наиболее естественен для человека, общающегося с компьютером. Действительно, если вспомнить определение алгоритма: конечная последовательность определенных в каждый момент времени действий, выполнение которых ведет к решению задачи за конечное число шагов, - то именно набор указаний - императив - наиболее приемлем для кодирования. Да и вообще, приятно ведь кем-нибудь покомандовать! Более того, если вспомнить таких классиков теоретического программирования, как Тьюринг и Пост, то становится понятно, что и они, создавая теорию универсальных вычислителей, пользовались именно императивным стилем написания программ. Фортран и более поздние языки программирования также несут в своих операторах приказной тон: ДЛЯ i ОТ 1 ДО 10 ДЕЛАЙ.

    2. Функциональный стиль. Среди многих десятков языков программирования есть один "древний старичок". - "ЛИСП". Он чуть моложе Фортрана, и его первый интерпретатор был написан именно на Фортране. Название происходит от английского термина List Processing - обработка списков. Его автором является профессор математики Маккарти. Первая реализация ЛИСП'а была сделана в самом начале шестидесятых годов. Досталось (и достается сейчас) языку довольно много. Началось все с названия. Имя языка совпадает с английским словом "шепелявить". Потом языку досталось из-за безумного количества скобок, используемых для записи программ, из-за бедности типов данных (базовых всего два). Но первый компьютерный психиатр "Элиза" был написан именно на ЛИСП'е и только значительно позже переписан на других языках программирования. Первые экспертные системы и системы автоматического доказательства теорем также были исходно реализованы на ЛИСП'е. И это несмотря на бедность средств работы с периферией, контроль типов во время исполнения программы и т. п. Почему же так случилось? Да потому, что ЛИСП - один из немногих языков программирования, который поддерживает функциональный стиль. Давайте рассмотрим действие некоторой программы P. Она получает на входе некоторый набор (множество) данных М и преобразует его во множество выходных данных M1. То есть программа отображает множество М во множество М1, причем конкретному набору входных данных соответствует конкретный выходной набор. Отображение однозначно! В математике такая зависимость называется функцией, а значит, мы имеем право рассматривать программу как функцию над множеством входных параметров. Кажущаяся сложность определений, полностью окупается тем изяществом, с которым можно писать программы на функциональных языках. Пусть необходимо реверсировать произвольную последовательность. То есть из конструкции вида (A B C D E F Q) получить (Q F E D C B A). Последовательность может быть произвольной длины и произвольной структуры, то есть вместо любого из атомов А, В, и т. д. может стоять произвольная подпоследовательность. (Вообще, в ЛИСП'е такие структуры называются списками). Решение этой задачи занимает всего несколько строк. Вот оно: (DEFUN REVERSE-1 (X) ; Определяем функцию реверсирования с единственным аргументом (COND ((NULL X) NIL) ; Если аргумент пустой, то ничего не делать (вернуть пустой список) (T (APPEND (REVERSE-1 (CDR X)) (LIST(CAR X)))))) ; Иначе объединить реверсированный список, содержащий все элементы исходного за исключением самого первого (головы), со списком, содержащим голову исходного. Согласитесь, что три строчки не так много для сформулированной задачи.

    Функциональное программирование, в том числе и ЛИСП, активно применяется в системах символьных вычислений. Мощнейший аналитический решатель задач REDUCE полностью написан на диалекте языка, называемом R-LISP, а все версии AutoCAD, по 12-ю включительно, поддерживают встроенный язык Авто-ЛИСП.

    3. Логический стиль. Последний класс языков программирования является "побочным продуктом" разработки компьютеров пятого поколения. Идея была выдвинута в семидесятых годах в Японии, и именно там был реализован логический подход к программированию. Только там мог возникнуть язык, который позволяет компьютеру если не думать, то по крайней мере логично рассуждать. Этот язык получил имя "Пролог" (Programming Logic). Именно логическое программирование на Прологе позволило программисту свести к минимуму усилия по проработке логики программы. Идея, заложенная в логический стиль, проста. Давайте сформулируем аксиомы, касающиеся некоторых объектов, и назовем эти аксиомы фактами. Установим отношения между объектами и назовем их правилами или теоремами. Дальше, построим запрос (опять в виде некоторой теоремы) и попросим компьютер доказать либо опровергнуть его. Реализация сформулированной идеи носит естественные ограничения исчисления предикатов, в рамках которого работает язык (о полуразрешимости исчисления предикатов можно прочесть в любом курсе по математической логике). Удобства, предоставляемые Прологом, становятся особенно заметными после некоторой практики программирования задач символьной обработки и искусственного интеллекта. Однако Пролог нашел интересное применение не только в среде экспертных систем и систем распознавания образов. Для доказательства запросов (целей) правила и факты представляются в Пролог-машине в виде таблицы, то есть любая Пролог-система для каждой задачи строит небольшую реляционную базу данных. Благодаря этому свойству Пролога, стало возможным его использование в качестве языка запросов к обычным базам данных. Использование Пролога в таком новом качестве позволяет многократно повысить скорость обработки запроса, поскольку число промежуточных операций по переводу информации из одного представления в другое резко сокращается.

    При работе с базами данных Пролог во многом удобнее императивного SQL. На нем можно относительно легко реализовать СУБД. Однако фирмы - разработчики программного обеспечения пишут софт на Си++, аргументируя свой выбор возможностью писать в объектах. Текстовый процессор на ЛИСП'е "выжмет" из своего автора гораздо меньше сил, чем такой же процессор, но написанный на другом языке. А отладка если и не доставит удовольствие, то точно уж не будет столь изнурительной. И в объектах писать можно (система CLOS - Common Lisp Object System довольно давно стала негласным стандартом языка), и с периферией работать просто. ЛИСП и Пролог сейчас - это мощные и гибкие системы, хотя пользуются ими единицы-профессионалы.

    Говорят, что язык поддерживает некоторый стиль программирования, если в нем есть такие возможности, которые делают программирование в этом стиле удобным (достаточно простым, надежным и эффективным). Язык не поддерживает некоторый стиль программирования, если требуются большие усилия или даже искусство, чтобы написать программу в этом стиле. Однако это не означает, что язык запрещает писать программы в этом стиле. Действительно, можно писать структурные программы на Фортране и объектно-ориентированные программы на С, но это будет пустой тратой сил, поскольку данные языки не поддерживают указанных стилей программирования.

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

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

    1. Все конструкции языка должны естественно и элегантно определяться в нем.

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

    3. Должно быть минимальное число неочевидных конструкций специального назначения.

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

    5. Пользователю достаточно знать только то множество конструкций, которое непосредственно используется в его программе.

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

    2. Стиль структу́рного программи́рования

    Структурное программирование — методология разработки ПО, в основе которой лежит представление программы в виде иерархической структуры блоков. Предложена в 70-х годах XX века Э. Дейкстрой, разработана и дополнена Н. Виртом. В соответствии с данной методологией:

    1. Любая программа представляет собой структуру, построенную из трёх типов базовых конструкций:

    • последовательное исполнение — однократное выполнение операций в том порядке, в котором они записаны в тексте программы;

    • ветвление — однократное выполнение одной из двух или более операций, в зависимости от выполнения некоторого заданного условия;

    • цикл — многократное исполнение одной и той же операции до тех пор, пока выполняется некоторое заданное условие (условие продолжения цикла).

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

    3. Разработка программы ведётся пошагово, методом «сверху вниз».

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

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

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

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

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

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

    • Сильно упрощается процесс тестирования и отладки структурированных программ.

    3. Общие положения стандарта оформления кода

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

    На самом деле, нет какого-то единого стиля, овладев которым, можно научиться писать красивые программы. Программист, всю жизнь писавший на С++, довольно быстро может разобраться в программе на Паскале, Java и тем более С#. Довольно быстро - при условии, что она понятно написана. Другое дело - программы, написанные неумело. Если в программе задействована глобальная переменная, изменения которой происходят в несвязанных классах/функциях, можно говорить о неудобной архитектуре. Если в программе жестко прописаны константы и, поменяв числовое значение в одной переменной, мы нарушаем целостность программы, можно говорить о плохой архитектуре. Можно говорить о плохой архитектуре, когда классы связаны между собой крест-накрест, и изменения в одном из них ведут к изменениям в другом, а изменения в другом - к изменению в первом. Когда программа ведет себя непредсказуемым образом - значит, это неудачное программное решение. Проблема состоит в том, что и хорошую, и плохую программу можно написать на разных языках. И раз уж такая глобальная вещь как язык программирования, имеет так мало влияния на качество программы, то что уж говорить об оформлении кода. Конечно, оформление кода не может служить панацеей от кривых рук программиста. Скорее, неаккуратное оформление может развалить красивый код на кучу мало связных кусков.

    Несколько подходов к стилю

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

    2. С-стильпротив шаблонов проектирования.

    Поскольку язык С является в некотором роде подклассом языка С++ (подклассом в математическом смысле), у людей знакомых с С, но плохо знакомых с С++ есть большой соблазн писать на С++ в С-стиле. С-стиль - это предпочтение функций классам (в крайнем случае - функциональное программирование), широкое использование указателей и явного приведения типов. Программы, написанные на С, обладают большей переносимостью, быстрее собираются и скомпилированный код оказывается более эффективным. Многие программы до сих пор пишутся в С-стиле. С-программы более читабельны, взаимосвязи между частями кода оказываются более наглядными. Однако при всех плюсах С значительно менее безопасный и значительно более низкоуровневый язык по сравнению с С++. Противоположный уклон - мощное использование С++ механизмов, в частности механизмов объектно-ориентированного проектирования: наследование, агрегация. Используя, в частности, шаблоны проектирования можно моделировать сложное поведение системы набором стандартных приемов. Такой код будет проще поддерживать и расширять, но только для того, кто уже знаком с системой. Динамические механизмы очень неочевидны и ненаглядны, для их понимания необходимы диаграммы состояний классов, например как в языке UML, без дополнительной информации сложную объектно-ориентированную систему трудно понять. 3.Объемные комментарии против программирования без комментариев. Значительно повысить ясность кода помогают комментарии. Код без комментариев не является коммерческим кодом. Классическая школа рекомендует подробно комментировать каждый класс и все публичные методы класса, а также переменные, если таковые есть, плюс обязательны комментарии для внутренних методов и переменных, а также внутри функций необходимо комментировать особо сложные и важные моменты. Существует подход, предлагающий прежде чем писать функцию, описывать ее поведение подробно в комментарии. Опять же, современный подход, в частности некоторые аспекты экстремального программирования, советуют избегать комментариев - комментарии подталкивают к тому, чтобы писать более непонятный код (мол, из комментария и так ясно что происходит), кроме того, комментарии быстро устаревают, если код интенсивно развивается, тем самым порождая несоответствие документации коду. Код, с этой точки зрения, должен быть ясен, четок и развернут так, как если бы вы писали не сам код, а комментарий к нему.

    4. Использование библиотек против системного программирования. Корень этого вопроса состоит в том, что часто внешние библиотеки дублируют функциональность системы, создавая обертки к системным классам и функциям. Само по себе это неплохо - обычно в обертки входят дополнительные средства обеспечения безопасности и более удобный интерфейс, например за счет скрытия деталей. Однако это порождает проблему выбора. Обычно в таких случаях советуют использовать библиотеки высокого уровня. Например, если вы под Borland C++ Builder пишете работу с таймером, скорее всего вы будете использовать компоненту TTimer, а не системный таймер. Дополнительные вопросы возникают при возможности работы со сторонними библиотеками. Если кроме системного и встроенного классов существует дополнительная библиотека утилит, в которой реализованы те же возможности, возникает вопрос производительности и удобства. Пример - использование переменной для строк. Это может быть char*, AnsiString или std::string. Первый вариант не слишком удобен для использования, в том числе и потому что другие два варианта имеют возможность приведения к первому, при этом предоставляя дополнительные возможности. Однако выбор между вторым и третьим вариантом не столь однозначен. Решать какой именно библиотекой пользоваться в таком случае по обстоятельствам. В частности, анализ для каких целей используется класс, и в какой библиотеке поддержка его именно с этой точки зрения выше. Вывод: главное - единообразие. Какой-то определенный стиль программирования не является ни панацеей от ошибок, ни признаком высшего мастерства. Вы можете выбрать для себя любой стиль, и твердо следовать ему, совершенствуя приемы и доводя до автоматизма решения простых задач. Однако какой бы стиль вы ни избрали, необходимо учитывать то, что вы работаете в команде, и в ваш код будут вносить изменения другие люди и наоборот, вы вносите изменения в чужой код. Вы пишете в команде с другими людьми, которые также хотят твердо придерживаться своего стиля программирования, которые учатся на своих ошибках и доводят до совершенства свой стиль. Программа, написанная единообразно, будет смотреться гораздо более качественной и красивой, чем программа, в которой куски кода в С-стиле перемежаются с объектно-ориентированными паттернами. Существуют красивые программы в венгерской нотации и системными вызовами без малейшего упоминания библиотек высокого уровня MFC, VCL, .NET. Существуют ужасные программы на платформе .NET 2.0. Какой будет программа, попавшая в ваши руки - решать вам.

    Необходимо

    Надо выработать один стиль - некий стандарт, особенно если над одним кодом работает команда, чтобы при передаче кода, другой разработчик без проблем мог в нем ориентироваться. В настоящее время наличие развитых методов программирования, достаточный объём информации о программировании, позволяет организовать процесс обучения программистов с "насаждением" определенного стиля программирования (как это делается при изучении "родного" языка — прививаются навыки "грамотного" письма). Это наиболее простой, легкий и проверенный путь избавления от стилевых конфликтов, позволяющий получить программистов, умеющих писать красивые программы и облегчить им в будущем тернистый путь превращения в профессионалов. Крайне желательно для насаждения красивого стиля программирования использовать в качестве примеров программы, разработанные "гуру" программирования. Образцы программ, как правило, поставляются в виде example в составе систем программирования. Для языков Си, С++ очень хорошими примерами являются системные программы среды UNIX, в частности, LINUX.

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

    Контрольные вопросы

    1. Понятие стиля программирования.

    2. Что включает понятие императивного стиля программирования?

    3. Что такое функциональный стиль программирования?

    4. Чем отличается логический стиль?

    5. Сформулируйте требования к языку программирования.

    6. В чем заключается стиль структурного программирования?

    7. Что такое «заглушки» и какова их роль в структурном программировании?

    8. Охарактеризуйте основные положения стандарта оформления кода?

    Глава 11. Парадигмы программирования

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

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

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

    Термин «парадигма программирования» впервые применил Роберт Флойд в своей лекции лауреата премии Тьюринга. Парадигмы программирования не являются взаимоисключающими. Если прогресс искусства программирования в целом требует постоянного изобретения и усовершенствования парадигм, то совершенствование искусства отдельного программиста требует, чтобы он расширял свой репертуар парадигм. Таким образом, по мнению Роберта Флойда, в отличие от парадигм в научном мире, парадигмы программирования могут сочетаться, обогащая инструментарий программиста.

    1. Процедурное программирование

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

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

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

    Процедурные языки программирования:

    Аda (язык общего назначения); Basic (версии начиная с Quick Basic до появления Visual Basic); Си ; КОБОЛ ; Фортран ; Модула-2; Pascal; ПЛ/1 ; Рапира ; REXX .

    2. Функциональное программирование

    Функциона́льное программи́рование — раздел дискретной математики и парадигма программирования, в которой процесс вычисления трактуется как вычисление значений функций в математическом понимании последних (в отличие от функций как подпрограмм в процедурном программировании). Противопоставляется парадигме императивного программирования, которая описывает процесс вычислений как последовательность изменения состояний (в значении, подобном таковому в теории автоматов). Функциональное программирование не предполагает изменяемость данных в отличие от императивного, где одной из базовых концепций является переменная. На практике отличие математической функции от понятия «функции» в императивном программировании заключается в том, что императивные функции взаимодействуют и изменяют уже определённые данные. Таким образом, в императивном программировании, при вызове одной и той же функции с одинаковыми параметрами можно получить разные данные на выходе, из-за влияния на функцию внешних факторов. А в функциональном языке при вызове функции с одними и теми же аргументами мы всегда получим одинаковый результат в обоих случаях, входные данные не могут измениться, выходные данные зависят только от них. Наиболее известными языками функционального программирования являются:

    • XQuery Haskell — чистый функциональный. Назван в честь Хаскелла Карри.

    • LISP (Джон МакКарти, 1958, множество его потомков, наиболее современные из которых — Scheme и Common Lisp).

    • ML (Робин Милнер, 1979, из ныне используемых диалектов известны Standard ML и Objective CAML).

    • Miranda (Дэвид Тёрнер, 1985, который впоследствии дал развитие языку Haskell).

    • Erlang — (Joe Armstrong, 1986) функциональный язык с поддержкой процессов.

    • Nemerle — гибридный функционально/императивный язык.

    • F# - функциональный язык для платформы .NET

    Ещё не полностью функциональные изначальные версии и Lisp и APL внесли особый вклад в создание и развитие функционального программирования. Более поздние версии Lisp, такие как Scheme, а также различные варианты APL поддерживали все свойства и концепции функционального языка.

    Как правило, интерес к функциональным языкам программирования, особенно чисто функциональным, был сугубо научный, нежели коммерческий. Однако, таким примечательным языкам как Erlang, OCaml, Haskell, Scheme (после 1986) а также специфическим R (статистика), Mathematica (символическая математика), J и K (финансовый анализ), и XSLT (XML) находили применение в индустрии коммерческого программирования. Такие широко распространенные декларативные языки как SQL и Lex/Yacc содержат некоторые элементы функционального программирования, они остерегаются использовать переменные. Языки работы с электронными таблицами также можно рассматривать как функциональные. Многие нефункциональные языки, такие как C, C++ и C# могут вести себя как функциональные при использовании указателей на функцию, в соответствие с библиотекой <functional> и λ-исчислениями.

    3. Логическое программирование

    Логи́ческое программи́рование — парадигма программирования, основанная на автоматическом доказательстве теорем, а также раздел дискретной математики, изучающий принципы логического вывода информации на основе заданных фактов и правил вывода. Логическое программирование основано на теории и аппарате математической логики с использованием математических принципов резолюций. Самым известным языком логического программирования является Prolog. Первым языком логического программирования был язык Planner, в котором была заложена возможность автоматического вывода результата из данных и заданных правил перебора вариантов (совокупность которых называлась планом). Planner использовался для того, чтобы понизить требования к вычислительным ресурсам (с помощью метода backtracking) и обеспечить возможность вывода фактов, без активного использования стека. Затем был разработан язык Prolog, который не требовал плана перебора вариантов и был, в этом смысле, упрощением языка Planner.

    От языка Planner также произошли логические языки программирования QA-4, Popler, Conniver и QLISP. Языки программирования Mercury, Visual Prolog, Oz и Fril произошли уже от языка Prolog. На базе языка Planner было разработано также несколько альтернативных языков логического программирования, не основанных на методе поиска с возвратами (backtracking), например, Ether .

    4. Автоматное программирование

    Автома́тное программи́рование — это парадигма программирования, при использовании которой программа или её фрагмент осмысливается как модель какого-либо формального автомата. В зависимости от конкретной задачи в автоматном программировании могут использоваться как конечные автоматы, так и автоматы более сложной структуры. Определяющими для автоматного программирования являются следующие особенности:

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

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

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

    5. Объектно-ориентированное программирование

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

    5.1 История ооп

    Объектное и объектно-ориентированное программирование (ООП) возникло в результате развития идеологии процедурного программирования, где данные и подпрограммы (процедуры, функции) их обработки формально не связаны. Кроме того, в современном ООП часто большое значение имеют понятия события (так называемое событийно-ориентированное программирование) и компонента (компонентное программирование). Первым языком программирования, в котором были предложены принципы объектной ориентированности, была Симула. В момент своего появления (в 1967 году), этот язык программирования предложил поистине революционные идеи: объекты, классы, виртуальные методы и др., однако это всё не было воспринято современниками как нечто грандиозное. Тем не менее, большинство концепций были развиты Аланом Кэйем и Дэном Ингаллсом в языке Smalltalk. Именно он стал первым широко распространённым объектно-ориентированным языком программирования. В настоящее время количество прикладных языков программирования, реализующих объектно-ориентированную парадигму, является наибольшим по отношению к другим парадигмам. В области системного программирования до сих пор применяется парадигма процедурного программирования, и общепринятым языком программирования является язык C. Хотя при взаимодействии системного и прикладного уровней операционных систем заметное влияние стали оказывать языки объектно-ориентированного программирования. Например, одной из наиболее распространенных библиотек мультиплатформенного программирования является объектно-ориентированная библиотека Qt, написанная на языке C++.

    5.2 Главные понятия и разновидности ооп

    Структура данных «класс», представляющая собой объектный тип данных, внешне похожа на типы данных процедурно-ориентированных языков, такие как структура в языке Си или запись в Паскале или QuickBasic. При этом элементы такой структуры (члены класса) могут сами быть не только данными, но и методами (то есть процедурами или функциями). Такое объединение называется инкапсуляцией. Наличие инкапсуляции достаточно для объектности языка программирования, но ещё не означает его объектной ориентированности — для этого требуется наличие наследования. Но даже наличие инкапсуляции и наследования не делает язык программирования в полной мере объектным с точки зрения ООП. Основные преимущества ООП проявляются только в том случае, когда в языке программирования реализован полиморфизм. Язык Self, соблюдая многие исходные положения объектно-ориентированного программирования, ввёл альтернативное классам понятие прототипа, положив начало прототипному программированию, считающемуся подвидом объектного.

    5.2.1 Основные понятия

    Абстракция данных 

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

    Инкапсуляция 

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

    Сокрытие данных 

    Сокрытие данных — неотделимая часть ООП, управляющая областями видимости. Является логическим продолжением инкапсуляции. Целью сокрытия является невозможность для пользователя узнать или испортить внутреннее состояние объекта.

    Наследование 

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

    Полиморфизм 

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

    5.2.2 Сложности определения

    ООП имеет уже более чем сорокалетнюю историю, но, несмотря на это, до сих пор не существует чёткого общепринятого определения данной технологии. Основные принципы, заложенные в первые объектные языки и системы, подверглись существенному изменению (или искажению) и дополнению при многочисленных реализациях последующего времени. Кроме того, примерно с середины 1980-х годов термин «объектно-ориентированный» стал модным, в результате с ним произошло то же самое, что несколько раньше с термином «структурный» (ставшим модным после распространения технологии структурного программирования) — его стали искусственно «прикреплять» к любым новым разработкам, чтобы обеспечить им привлекательность. Бьёрн Страуструп в 1988 году писал, что обоснование «объектной ориентированности» чего-либо, в большинстве случаев, сводится к силлогизму: «X — это хорошо. Объектная ориентированность — это хорошо. Следовательно, X является объектно-ориентированным».

    5.2.3 Определение ооп

    По мнению Алана Кея, создателя языка Smalltalk, которого считают одним из «отцов-основателей» ООП, объектно-ориентированный подход заключается в следующем наборе основных принципов):

    • Всё является объектом.

    • Вычисления осуществляются путём взаимодействия (обмена данными) между объектами, при котором один объект требует, чтобы другой объект выполнил некоторое действие. Объекты взаимодействуют, посылая и получая сообщения. Сообщение — это запрос на выполнение действия, дополненный набором аргументов, которые могут понадобиться при выполнении действия.

    • Каждый объект имеет независимую память, которая состоит из других объектов.

    • Каждый объект является представителем (экземпляром) класса, который выражает общие свойства объектов.

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

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

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

    5.2.3 Концепции

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

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

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

    Однако общность механизма обмена сообщениями имеет и другую сторону — «полноценная» передача сообщений требует дополнительных накладных расходов, что не всегда приемлемо. Поэтому в большинстве ныне существующих объектно-ориентированных языков программирования используется концепция «отправка сообщения как вызов метода» — объекты имеют доступные извне методы, вызовами которых и обеспечивается взаимодействие объектов. Данный подход реализован в огромном количестве языков программирования, в том числе C++, Object Pascal, Java, Oberon-2. В настоящий момент именно он является наиболее распространённым в объектно-ориентированных языках.

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

    5.2.4 Особенности реализации

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

    Поля данных

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

    Методы 

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

    Классы могут наследоваться друг от друга. Класс-потомок получает все поля и методы класса-родителя, но может дополнять их собственными либо переопределять уже имеющиеся. Большинство языков программирования поддерживает только единичное наследование (класс может иметь только один класс-родитель), лишь в некоторых допускается множественное наследование — порождение класса от двух или более классов-родителей. Множественное наследование создаёт целый ряд проблем, как логических, так и чисто реализационных, поэтому в полном объёме его поддержка не распространена. Вместо этого в 1990-е годы появилось и стало активно вводиться в объектно-ориентированные языки понятие интерфейса. Интерфейс — это класс без полей и без реализации, включающий только заголовки методов. Если некий класс наследует (или, как говорят, реализует) интерфейс, он должен реализовать все входящие в него методы. Использование интерфейсов предоставляет относительно дешёвую альтернативу множественному наследованию.

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

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

    Контроль доступа 

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

    Методы доступа 

    Поля класса, в общем случае, не должны быть доступны извне, поскольку такой доступ позволил бы произвольным образом менять внутреннее состояние объектов. Поэтому поля обычно объявляются скрытыми (либо язык в принципе не позволяет обращаться к полям класса извне), а для доступа к находящимся в полях данным используются специальные методы, называемые методами доступа. Такие методы либо возвращают значение того или иного поля, либо производят запись в это поле нового значения. При записи метод доступа может проконтролировать допустимость записываемого значения и, при необходимости, произвести другие манипуляции с данными объекта, чтобы они остались корректными (внутренне согласованными). Методы доступа называют ещё аксессорами (от англ. access — доступ), а по отдельности — геттерами (англ. get — чтение) и сеттерами (англ. set — запись).

    Свойства объекта 

    Псевдополя, доступные для чтения и/или записи. Свойства внешне выглядят как поля и используются аналогично доступным полям (с некоторыми исключениями), однако фактически при обращении к ним происходит вызов методов доступа. Таким образом, свойства можно рассматривать как «умные» поля данных, сопровождающие доступ к внутренним данным объекта какими-либо дополнительными действиями (например, когда изменение координаты объекта сопровождается его перерисовкой на новом месте). Свойства, по сути — не более чем синтаксический сахар, поскольку никаких новых возможностей они не добавляют, а лишь скрывают вызов методов доступа. Конкретная языковая реализация свойств может быть разной. Например, в C# объявление свойства непосредственно содержит код методов доступа, который вызывается только при работе со свойствами, то есть не требует отдельных методов доступа, доступных для непосредственного вызова. В Delphi объявление свойства содержит лишь имена методов доступа, которые должны вызываться при обращении к полю. Сами методы доступа представляют собой обычные методы с некоторыми дополнительными требованиями к сигнатуре.

    Полиморфизм реализуется путём введения в язык правил, согласно которым переменной типа «класс» может быть присвоен объект любого класса-потомка её класса.

    5.3 Подходы ооп к проектированию программ в целом

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

    Объектно-ориентированное проектирование основывается на описании структуры и поведения проектируемой системы, то есть, фактически, в ответе на два основных вопроса:

    • Из каких частей состоит система.

    • В чём состоит ответственность каждой из частей.

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

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

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

    5.4 Родственные методологии

    5.4.1 Компонентное программирование

    Компонентно-ориентированное программирование — это своеобразная «надстройка» над ООП, набор правил и ограничений, направленных на построение крупных развивающихся программных систем с большим временем жизни. Программная система в этой методологии представляет собой набор компонентов с хорошо определёнными интерфейсами. Изменения в существующую систему вносятся путём создания новых компонентов в дополнение или в качестве замены ранее существующих. При создании новых компонентов на основе ранее созданных запрещено использование наследования реализации — новый компонент может наследовать лишь интерфейсы базового. Таким образом компонентное программирование обходит проблему хрупкости базового класса.

    Компонентно-ориентированное программирование (англ. component-oriented programming) возникло как своего рода дисциплина, то есть набор определенных ограничений, налагаемых на механизм ООП, когда стало ясно, что бесконтрольное использование ООП приводит к проблемам с надежностью больших программных комплексов. Это так называемая проблема хрупких базовых типов (fragile base class problem); проблема может проявиться при попытке изменить реализацию типа-предка, когда может оказаться, что изменить реализацию типа-предка даже при неизменных интерфейсах его методов невозможно, не нарушив корректность функционирования типов-потомков. Следует отметить, что структурное программирование ранее тоже возникло как некоторая дисциплина использования структур управления, исключающая бесконтрольные неупорядоченные переходы управления с помощью оператора GOTO.

    5.4.2 Прототипное программирование

    Прототипное программирование, сохранив часть черт ООП, отказалось от базовых понятий — класса и наследования.

    Вместо механизма описания классов и порождения экземпляров язык предоставляет механизм создания объекта (путём задания набора полей и методов, которые объект должен иметь) и механизм клонирования объектов.

    Каждый вновь созданный объект является «экземпляром без класса». Каждый объект может стать прототипом — быть использован для создания нового объекта с помощью операции клонирования. После клонирования новый объект может быть изменён, в частности, дополнен новыми полями и методами.

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

    Каноническим примером прототип-ориентированного языка является язык Self. В дальнейшем этот стиль программирования начал обретать популярность и был положен в основу таких языков программирования, как JavaScript, Cecil, NewtonScript, Io, Slate, MOO, REBOL, Kevo и др.

    5.5 Производительность объектных программ

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

    Динамическое связывание методов. 

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

    Значительная глубина абстракции. 

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

    Наследование «размывает» код. 

    Код, относящийся к «оконечным» классам иерархии наследования (которые обычно и используются программой непосредственно) — находится не только в самих этих классах, но и в их классах-предках. Относящиеся к одному классу методы фактически описываются в разных классах. Это приводит к двум неприятным моментам:

    • Снижается скорость трансляции, так как компоновщику приходится подгружать описания всех классов иерархии.

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

    Инкапсуляция снижает скорость доступа к данным. 

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

    Динамическое создание и уничтожение объектов. 

    Динамически создаваемые объекты, как правило, размещаются в куче, что менее эффективно, чем размещение их на стеке и, тем более, статическое выделение памяти под них на этапе компиляции.

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

    5.6 Критика ооп

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

    Обычно сравнивают объектное и процедурное программирование:

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

    • Объектное — когда важна управляемость проекта и его модифицируемость, а также скорость разработки.

    Критические высказывания в адрес ООП:

    • Исследование Thomas E. Potok, Mladen Vouk и Andy Rindos показало отсутствие значимой разницы в продуктивности разработки программного обеспечения между ООП и процедурным подходом.

    • Кристофер Дэйт указывает на невозможность сравнения ООП и других технологий во многом из-за отсутствия строгого и общепризнанного определения ООП

    • Фредерик Брукс указывает на то, что наиболее сложной частью создания программного обеспечения является « … спецификация, дизайн и тестирование концептуальных конструкций, а отнюдь не работа по выражению этих концептуальных конструкций…». ООП (наряду с такими технологиями как искусственный интеллект, верификация программ, автоматическое программирование, графическое программирование, экспертные системы и др.), по его мнению, не является «серебряной пулей», которая могла бы на порядок величины (т.е. примерно в 10 раз, как говорится в статье) снизить сложность разработки программных систем. Согласно Бруксу, «…ООП позволяет сократить только привнесённую сложность в выражение дизайна. Дизайн остаётся сложным по своей природе…».

    • Никлаус Вирт считает, что ООП — не более чем тривиальная надстройка над структурным программированием, и преувеличение её значимости, выражающееся, в том числе, во включении в языки программирования всё новых модных «объектно-ориентированных» средств, вредит качеству разрабатываемого программного обеспечения.

    • Патрик Киллелиа в своей книге «Тюнинг веб-сервера» писал: «… ООП предоставляет вам множество способов замедлить работу ваших программ …»

    Если попытаться классифицировать критические высказывания в адрес ООП, можно выделить несколько аспектов критики данного подхода к программированию.

    Критика рекламы ООП

    Критикуется явно высказываемое или подразумеваемое в работах некоторых пропагандистов ООП, а также в рекламных материалах «объектно-ориентированных» средств разработки представление об объектном программировании как о некоем всемогущем подходе, который магическим образом устраняет сложность программирования. Как замечали многие, в том числе упомянутые выше Брукс и Дейкстра, «серебряной пули не существует» — независимо от того, какой парадигмы программирования придерживается разработчик, создание нетривиальной сложной программной системы всегда сопряжено со значительными затратами интеллектуальных ресурсов и времени. Из наиболее квалифицированных специалистов в области ООП никто, как правило, не отрицает справедливость критики этого типа.

    Оспаривание эффективности разработки методами ООП

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

    Производительность объектно-ориентированных программ

    Указывается на то, что целый ряд «врождённых особенностей» ООП-технологии делает построенные на её основе программы технически менее эффективными, по сравнению с аналогичными необъектными программами. Не отрицая действительно имеющихся дополнительных накладных расходов на организацию работы ООП-программ, нужно, однако, отметить, что значение снижения производительности часто преувеличивается критиками. В современных условиях, когда технические возможности компьютеров чрезвычайно велики и постоянно растут, для большинства прикладных программ техническая эффективность оказывается менее существенна, чем функциональность, скорость разработки и сопровождаемость. Лишь для некоторого, очень ограниченного класса программ (ПО встроенных систем, драйверы устройств, низкоуровневая часть системного ПО, научное ПО) производительность остаётся критическим фактором.

    Критика отдельных технологических решений в ООП-языках и библиотеках

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

    5.7 Объектно-ориентированные языки - характеристика

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

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

    • Объявление классов с полями (данными — членами класса) и методами (функциями — членами класса).

    • Механизм расширения класса (наследования) — порождение нового класса от существующего с автоматическим включением всех особенностей реализации класса-предка в состав класса-потомка. Большинство ООП-языков поддерживают только единичное наследование.

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

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

    • Полиморфное поведение экземпляров классов за счёт использования виртуальных методов. В некоторых ООП-языках все методы классов являются виртуальными.

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

    • Конструкторы, деструкторы, финализаторы.

    • Свойства (аксессоры).

    • Индексаторы.

    • Интерфейсы — как альтернатива множественному наследованию.

    • Переопределение операторов для классов.

    Часть языков (иногда называемых «чисто объектными») целиком построена вокруг объектных средств — в них любые данные (возможно, за небольшим числом исключений в виде встроенных скалярных типов данных) являются объектами, любой код — методом какого-либо класса, и невозможно написать программу, в которой не использовались бы объекты. Примеры подобных языков — C#, Smalltalk, Java, Ruby. Другие языки (иногда используется термин «гибридные») включают ООП-подсистему в исходно процедурный язык. В них существует возможность программировать, не обращаясь к объектным средствам. Классические примеры — C++ и Pascal.

    6. Аспектно-ориентированное программирование

    Аспектно-ориентированное программирование (АОП) — парадигма программирования, основанная на идее разделения функциональности для улучшения разбиения программы на модули. Методология аспектно-ориентированного программирования была предложена группой инженеров исследовательского центра Xerox PARC под руководством Грегора Кичалеса (Gregor Kiczales). Ими же был разработан аспектно-ориентированное расширение для языка Java, получившее название AspectJ — (2001 год).

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

    Все языки АОП предоставляют средства для выделения сквозной функциональности в отдельную сущность. Так как AspectJ является родоначальником этого направления, используемые в этом расширении концепции распространились на большинство языков АОП. Основные понятия АОП:

    • Аспект ( aspect) — модуль или класс, реализующий сквозную функциональность. Аспект изменяет поведение остального кода, применяя совет в точках соединения, определённых некоторым срезом.

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

    • Точка соединения ( join point) — точка в выполняемой программе, где следует применить совет. Многие реализации АОП позволяют использовать вызовы методов и обращения к полям объекта в качестве точек соединения.

    • Срез ( pointcut) — набор точек соединения. Срез определяет, подходит ли данная точка соединения к данному совету. Самые удобные реализации АОП используют для определения срезов синтаксис основного языка (например, в AspectJ применяются Java-cигнатуры) и позволяют их повторное использование с помощью переименования и комбинирования.

    • Внедрение ( introduction, введение) — изменение структуры класса и/или изменение иерархии наследования для добавления функциональности аспекта в инородный код. Обычно реализуется с помощью некоторого метаобъектного протокола ( metaobject protocol, MOP).

    Ведение лога и обработка ошибок — типичные примеры сквозной функциональности. Другие примеры: трассировка; авторизация и проверка прав доступа; контрактное программирование (в частности, проверка пред- и постусловий). Для программы, написанной в парадигме ООП, любая функциональность, по которой не была проведена декомпозиция, является сквозной.

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

    Контрольные вопросы

    1. Дайте понятие парадигмы программирования.

    2. Может ли язык программирования поддерживать сразу несколько парадигм?

    3. Охарактеризуйте процедурное программирование?

    4. Охарактеризуйте функциональное программирование?

    5. В чем особенность логического программирования?

    6. Что такое автоматное программирование?

    7. В чем особенность объектно-ориентированного программирования (ООП)?

    8. Какой язык был первым в ООП и когда он появился?

    9. Какое понятие является важнейшим в ООП?

    10. Поясните основные принципы ООП?

    11. Перечислите родственные ООП методологии.

    12. От какого принципа отказались в прототипном программировании?

    13. Какие особенности ООП приводят к снижению производительности программных систем?

    14. Охарактеризуйте обязательный набор синтаксических средств объектно-ориентированного языка программирования.

    15. В чем заключается аспектно-ориентированное программирование?

    Глава 12. Эффективность и оптимизация программ

    1. Общие понятия эффективности

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

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

    • программа в таком виде пригодна,

    • если она нужна для работы,

    • если ее будут выпол­нять многократно и

    • если статус проекта и фирмы позволяет,

    тогда и только тогда следует рассмотреть возможность ее оптимизации.

    Обыч­но большая часть времени расходуется на выполнение очень небольшой части программы (<~5% ее объема), называемой крити­ческой областью. Как правило, только критическая область объ­ектной программы оптимизируется программистом вручную. Погоня за эффективностью часто ведет к злоупотреблению. За­мечено, что программисты тратят огромное количество времени, думая и беспокоясь о работе некритических областей программы. Современные компьютеры отличаются высоким быстро­действием и очень мала разница во времени выполнения програм­мы, если некоторые, редко выполняемые операторы удается сде­лать эффективными. Экономию можно получить только за счет многократно выполняемых циклов.

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

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

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

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

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

    Следовательно, еще до написания программы необходимо уста­новить, насколько эффективной она должна быть. Очевидно, что следует модифицировать только те программы, которые выполня­ются многократно. Программисты, «экономящие на спичках», со­кращают на 10 мкс время выполнения редко используемой прог­раммы, затрачивая при этом 2 ч на программирование и много минут на компилирование и тестирование. Очевидно, что в этом случае вы ничего не сэкономите. Зато, как и при любом изменении программы, можете добавить в нее ошибки. Однако человеческая натура такова, что эффективность программ всегда будет вызы­вать интерес.

    Многие методы, делающие программу эффективной, не наносят ущерба ее удобочитаемости. Эти методы следует использовать всегда. Но некоторые меры по повышению эффективности могут быть просто вредными для по­лучения удобочитаемой программы. Удобочитаемость программы более существенна, чем ее эффек­тивность. Дело в том, что удобочитаемую программу легче отла­живать, модифицировать и использовать. А всякую большую про­грамму обычно изменяет, модифицирует и применяет совсем не тот человек, который ее писал. Лишь в особых случаях программу следует делать более эффективной: программа: либо не помещается в памяти, либо слиш­ком долго выполняется. Или же программа должна быть включена в библиотеку и часто использоваться. В этом случае эффективность становится очень важным фактором и ей отдают предпочтение в ущерб удобочитаемости.

    2. Оптимизирующие компиляторы

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

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

    К сожалению, об увеличении скорости компилирования можно сказать немного. Некоторые программные ухищрения могут со­кратить время компилирования, но они либо тривиальны, либо сильно зависят от компилятора. Методы, дающие положительный результат при использовании в одном компиляторе, не дают тех же улучшений в другом компиляторе. Некоторые компиляторы работают более эффективно, если дли­ны имен переменных распределены равномерно. Другие компиля­торы более эффективны, если метки операторов равномерно рас­пределены по последнему символу. Естественно, что исключение неиспользуемых меток и выражений также уменьшает время ком­пилирования любого компилятора. Наличие меток препятствует некоторым типам оптимизации, поэтому неиспользуемые метки ухудшают эффективность объектной программы. При повторном прогоне программы следует исправить все ошибки в исходной про­грамме, а число предупреждающих диагностических сообщений должно минимизироваться каждый раз, когда это возможно.

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

    Некоторые компиляторы оптимизируют выполнение программы. Имеются два типа такой оптимизации: машинно-зависимая и ма­шинно-независимая.

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

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

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

    3. Оптимизация программ

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

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

    Сегментация программ

    Программу, подлежащую оптимизации, следует разделить на подпрограммы. Оптимизация значительно облегчается, если про­грамма уже разделена на подпрограммы в соответствии с принци­пами структурного программирования. Как только подпрограммы выделены, следует ответить на три вопроса:

    • Какой процент общего времени использует каждая подпро­грамма?

    • Насколько (в процентном выражении) оптимизируется каж­дая подпрограмма?

    • Сколько человеко-часов необходимо для достижения этой цели?

    Каждый из этих вопросов подробно обсуждается далее.

    Время работы подпрограмм

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

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

    подпрограммы А — 5%, подпрограммы С — 15%,

    подпрограммы В — 60%, подпрограммы В — 20%.

    Очевидно, что, даже если подпрограмму А исключить совсем (что, вообще говоря, невозможно), мы смогли бы сэкономить толь­ко 5% общего времени работы программы. Таким образом, попыт­ку оптимизации, вероятно, следует предпринять в первую очередь в отношении подпрограммы В, где возможна наибольшая эконо­мия.

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

    Большинство программ имеет одну критическую точку, которая использует большую часть времени выполнения. Нередко ка­кая-либо малая часть программы расходует более 50% времени выполнения. Очевидно, что эту часть программы следует оптими­зировать в первую очередь.

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

    Оценивайте возможное улучшение

    Если точно определен процент общего времени, используемый подпрограммой, следует оценить ее возможное улучшение. Если подпрограмма расходует небольшой процент от общего времени программы и ее можно лишь незначительно улучшить, то не стоит тратить на это усилий. При определении возможного улучшения необходима или возможна только приблизительная оценка. Не так уж важно, со­ставляет возможное улучшение 20 или 25%. Однако существенно, будет оно 5 или 70%.

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

    Теперь можно установить некоторый параметр, который будет показывать возможное улучшение. Если у нас имеется под­программа, использующая 50% общего времени работы програм­мы, но дающая только 5% повышения эффективности, мы получим в результате 2,5% (.50 * .05 = .025) общего улучшения эффектив­ности. Другая подпрограмма, которая использует 10% общего вре­мени, но дает 50% повышения эффективности, обеспечивает 5% (.50 * .10 = .05) общего улучшения эффективности. Таким образом, вторую подпрограмму следует оптимизировать в первую очередь, так как это дает больший выигрыш. Итак, при выборе подпрограм­мы для оптимизации следует учитывать произведение процента потребления времени и процента улучшения.

    Необходимые усилия.

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

    (Процент времени*Процент улучшения ) / Необходимые усилия

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

    Существуют два подхода к оптимизации имеющихся программ:

    • «чистка»

    • перепрограммирование.

    Оба подхода имеют как до­стоинства, так и недостатки.

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

    Второй подход состоит в переделке исходной программы. Если программа разделена на подпрограммы, можно переделать под­программу, которая расходует наибольшую часть времени. Реа­лизация этого подхода обеспечивает обычно наилучший результат. Однако этот подход и самый дорогой. Особенно полезно перепрограм­мировать задачу, если программа подверглась значительному из­менению. Частые переделки могут привести к изменению цели пер­воначальной программы. Программа может постоянно переделы­ваться в течение некоторого времени. И когда, наконец, результаты работы программы окажутся приемлемыми и дальнейшие пере­смотры будут менее обширными и менее частыми, следует заняться переделкой, используя приобретенные знания и поставив новые цели, что приведет к значительной экономии времени выполнения программы.

    Шаги оптимизации

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

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

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

    4. Применяйте локальную оптимизацию в критических областях.

    5. Слишком часто программисты тратят много времени, улучшая редко используемую программу.

    4. Эффективность выполнения программ

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

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

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

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

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

    Хорошие приемы программирования приводят к уменьшению как времени выполнения, так и объема используемой памяти, од­нако зачастую улучшение одного из этих факторов происходит за счет ухудшения другого. Большинство из обсуждающихся здесь методов экономит как время, так и память. Если использование метода приводит к возникновению конфликта между временем и памятью, это будет оговорено.

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

    • стоимость улучшения програм­мы,

    • частота ее использования,

    • относительная скорость выполнения различных операций в машине,

    • способ компилирования раз­личных операторов.

    Хорошей считается программа, которая выполняется при ми­нимальном расходе машинного времени. В этом случае за данный отрезок времени можно выполнить еще и другие задания. С появ­лением мультипроцессорной обработки (т. е. выполнением более одного задания за то же время) стало желательным также и ми­нимальное использование памяти, так как при работе в указанном режиме каждая программа должна находиться в оперативной па­мяти. Чем меньший объем памяти требуется каждой программе, тем больше программ можно разместить в оперативной памяти и обработать за одно и то же время. В режиме мультипроцессорной ^обработки использование оперативной памяти так же важно, как и расход времени. Сокращение занимаемой памяти или расхода времени будет уменьшать стоимость выполнения программы. Так как ресурсы машины очень дороги, то экономия даже небольшого количества времени или памяти в многократно используемой про­грамме может вполне стоить затраченных усилий.

    Обычно любая попытка улучшить эффективность предназнача­ется для часто используемых программ. Хотя это весьма резуль­тативный подход, однако есть другой путь сэкономить большое ко­личество машинного времени. Вырабатывайте комплекс привычек, которые будут способствовать составлению более эффективной программы и соответственно экономии машинного времени.

    5. Оптимизация использования памяти

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

    Оверлейность программы

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

    Виртуальная память

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

    Программист может принять некоторые меры для повышения эффективности выполнения программы при использовании вирту­альной памяти. Программу следует писать с подпрограммами. Это улучшает свойство локализованности программы, т. е. степени, до которой во время выполнения удается выделить в программе неко­торый ее фрагмент. Это легко выполняемый прием программиро­вания. Локализованность улучшается при использовании методов структурного программирования. Избегайте использования глобальных переменных, так как они приводят к ухуд­шению локальности. Организация циклов и подпрограмм также способствует лока­лизованности, так как приводит к многократному выполнению не­большой части всей программы. Чем выше степень локализованно­сти в программе, использующей виртуальную память, тем более эффективно будет выполняться программа, так как ей не придется вызывать в память много страниц. Таким образом, при исполь­зовании виртуальной памяти храните части программ, связанные друг с другом, рядом.

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

    Советы:

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

    2. Удаляйте подпрограммы, обрабатывающие исключения, под­программы обработки ошибок и другие редко используемые разделы программы из ее основной части, чтобы увеличить интенсивность обращений к наиболее часто используемым страницам.

    3. Присваивайте начальные значения элементам каждого мас­сива данных непосредственно перед первым его использованием, а не перед началом работы программы.

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

    5. Данные, не являющиеся массивом, можно разместить рядом, перегруппировав их описания. Лучше всего располагать рядом наиболее часто используемые массивы.

    Эквивалентность

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

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

    Использование циклов

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

    6. Некоторые приёмы повышения эффективности программ

    1.Вычисление констант

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

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

    2.Инициирование переменных

    Если начальные значения присваиваются переменным одновре­менно с их объявлением, то тем самым экономится время выпол­нения программы. В этом случае переменные получают начальные значения во время компилирования, а не во время выполнения. Инициирование переменных во время их объявления облегчает документирование программ, а также помогает избежать ошибок, которые могут возникнуть в случае, если переменным не были при­своены начальные значения.

    Инициируйте переменные во время компилирования.

    3.Арифметические операции

    Арифметические операции выполняются с различной скоростью. Полезно знать, какие операции выполняются быстрее, так как иногда бывает целесообразно заменить одну операцию другой. Пе­речислим математические операции в порядке возрастания време­ни их выполнения: 1) сложение или вычитание, 2) умножение, 3) деление, 4) возведение в степень.

    Некоторые медленно выполняемые операции легко заменить на более быстрые.

    Сложение выполняется быстрее, чем умножение, поэтому умно­жение на небольшое целое число следует заменять сложением. Так, 3*1 должно быть заменено на 1+1+1. Если в выражении не все числа являются целыми, то при замене может быть утеряна точ­ность. Ошибка округления действительных чисел имеет тенден­цию накапливаться, а не уменьшаться. Так, если К — действитель­ное число, а I — целое, то 1*К более правильно, чем К+К+К+К— (I раз).

    Преобразование уравнений может привести к исключению опе­раций. Например, выражение Х = 2*Y+(А—1)/Р+2*Т можно за­менить уравнением

    Х = 2*(Y+Т) + (А—1)/Р, что исключает одну операцию умножения.

    Поскольку деление является более медленной операцией, всюду, где возможно, его следует заменять умножением. Умножение вы­полняется по меньшей мере в два раза быстрее деления. Исключайте деление из вашей программы всюду, где это возможно: вме­сто А/5.0 пишите А*0.2.

    Если в вычислениях вы все время делите на некоторое число, папример на X, замените его на обратную величину.

    Важно также правильно задать тип показателя степени в опе­рации возведения в степень. Всегда, когда это возможно, следует использовать целые числа. Например,

    Медленный способ: А**8.0 или А**Р, где Р — число с плаваю­щей точкой.

    Более быстрый способ: А**8 или А**1, где I — целое число.

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

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

    Функция извлечения квадратного корня реализуется обычно гораздо быстрее, и точность при этом выше, чем при выполнении операции возведения в степень.

    Умножение выполняется значительно быстрее возведения в сте­пень, поэтому, если показатель степени — небольшое целое число, то операцию возведения в степень следует заменять несколькими операциями умножения:

    Для возведения в степень обычно требуется библиотечная про­грамма. Поэтому замена его несколькими операциями умножения экономит и память, и время, если показатель степени является не­большим целым числом.

    Заменяйте Х**2 на Х*Х Заменяйте Х**3 на Х*Х*Х Заменяйте Х**4 на (Х*Х)#(Х*Х)

    или на (((Х*Х)*Х)*Х)

    Последний пример содержит повторяющееся вычисление (Х*Х), которое в дальнейшем может быть оптимизировано. Замена одной операции другой, выполняемой более быстро, называется уменьше­нием силы операции. Уменьшение силы операции может иногда ухудшить удобочи­таемость программ, и об этом следует всегда помнить. Кроме того, при таком преобразовании некоторое количество машинного вре­мени затрачивается на управление промежуточными результатами.

    4. Арифметика с фиксированной точкой

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

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

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

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

    5. Смешанные типы данных

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

    Избегайте смешанных типов данных,

    6. Способ устранения ошибок

    В некоторых простых компиляторах следует тщательно выби­рать тип используемых констант. Например, А = 0 (неэффективно) А = 0.0 ( эффективно).

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

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

    7. Выравнивание десятичных чисел

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

    8. Упорядочивание памяти

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

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

    9. Группировка

    При выполнении операций одного приоритета над операндами разного типа следует группировать операнды одного типа, заклю­чая их в круглые скобки. Например, если операнд I относится к типу 1, операнд А — к типу 2, операнд К — к типу 3, то выражение вида 1*А*1*К*А* К* I следует записать как ((1*1*1)* А*А)* К*К.

    Группировка и скобки помогает избежать преобразований, ко­торые необходимо выполнить для первого выражения.

    Можно избежать лишних преобразований, если вначале вы­полнить преобразование одного типа данных в другой, а затем использовать нужный тип. Например, если I и А — переменные, которые используются вместе и требуют дополнительных преобра­зований, преобразуйте их сразу и используйте полученную форму в дальнейшем во всех математических операциях.

    Например,

    Медленный способ:

    В = А*1

    С=(А+1)*2.0

    Д = А* А/1

    Эти операторы используют переменные А и I несколько раз. Лучше преобразовать один раз переменную I в переменную типа А и затем пользоваться новой переменной.

    Более быстрый способ:

    А1 = 1

    В=А*А1

    С=(А+А1)*2.0

    Д=А*А/А1

    Здесь переменную I следует преобразовать не три раза, а толь­ко один.

    10. Исключение циклов

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

    РОLY =((А(1)*Х+А(2))*Х+А(3))*Х+А(4)

    выполняется быстрее, чем в цикле:

    POLY=A(I)

    DO 1 I=2,4

    1 РОLY = РОLY*Х+А(1)

    Кроме того, в каждом языке есть свои особенности инициирова­ния массивов.

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

    11. Организация циклов

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

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

    Поэтому уделяйте основное внимание циклам. Разберем при­мер:

    Цикл А 100 итераций

    Цикл В 100 итераций

    Цикл С 100 итераций

    Конец С

    Конец В

    Конец А

    Рассмотрим вначале цикл С. Любая экономия, даже самая ма­лая, будет здесь увеличиваться в 100*10О*10О=1 000 000 раз, т. е. коэффициент улучшения равен одному миллиону. Очень малое улучшение внутри цикла С гораздо выгоднее, чем значительное улучшение вне его. Затем рассмотрите цикл В, и, наконец, цикл А.

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

    Повторяющиеся вычисления в циклах являются наиболее типич­ными ошибками, влияющими на эффективность. Можно значительно сэконо­мить время выполнения программы просто проверкой циклов, вы­полняющих много итераций, и уменьшением повторяющихся вы­числений внутри этих циклов. Этот процесс обычно называют исключением инвариантных выражений или чисткой циклов. Инва­риантными являются выражения, которые не изменяются внутри цикла. Если при компилировании можно удалить одну операцию умножения из цикла, который повторяется при выполнении программы 1000 раз, мы сэкономим время, которое затрачивается на выполнение 999умножений.

    Оптимизируйте сначала внутренние циклы.

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

    12. Условные и логические выражения

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

    Правильное расположение логических выражений может сэкономить время выполнения.

    13. Ввод-вывод

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

    14. Использование сведения о машине и компиляторе

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

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

    Номера операторов записывают в пяти строках таблицы соглас­но последней цифре номера оператора. Номера операторов, окан­чивающиеся на 0 или 1, размещаются в первой строке, на 2 или .4 — во второй строке, на 4 или 5 — в третьей и т. д. Таким обра­зом, если номера операторов распределены равномерно, сокраща­ется время компилирования.

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

    Изложенные здесь замечания показывают, что, если эффектив­ность очень важна, вы должны знать не только общие приемы, позволяющие ее повысить, но также и обладать некоторыми сведениями о машине, ее компиляторе и операционной системе.

    7. Советы программисту по оптимизации программ

    • Если программа неправильна, не имеет значения, какова ее эффективность.

    • Определяйте требования к эффективности программы на стадии проектирования.

    • Удобочитаемость программы обычно более важна, чем эффек­тивность.

    • Используйте оптимизирующий компилятор. Инициируйте переменные во время компилирования.

    • Избегайте смешанных типов данных.

    • Оптимизируйте сначала внутренние циклы.

    • Используйте для индексации наиболее предпочтительный тип данных.

    • Группируйте записи в эффективные блоки для ввода-вывода.

    • Используйте загрузочные модули.

    Контрольные вопросы

    1. Что является наиболее важным при написании эффективных программ?

    2. Какой тип программ следует оптимизировать? Какой тип программ оптимизировать не надо?

    3. Что означают понятия: оверлейность программ, свертка, уменьшение силы операции, исключение повторяющихся выражений, исключение циклов, исключение инвариантных выражений, развертка цикла, критическая область, локализованность?

    4. В каком случае использовать цикл менее эффективно, чем программировать последовательно?

    5. Как следует располагать вложенные циклы, чтобы сократить число инициирований и проверок цикла?

    6. Какие области программы наиболее выгодны для оптими­зации?

    7. Расположите нижеуказанные операции по скорости их вы­полнения— от самой быстрой к самой медленной:

    1) деление, 4) извлечение корня,

    2) сложение, 5) возведение в степень,

    3) умножение, 6) вычитание.

    1. Имеется ли оптимизирующий компилятор, пригодный для нашего языка программирования? Если да, то какие типы оптимизации он выполняет?

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

    3. Выберите два различных оператора в вашем языке програм­мирования и разработайте тесты, выявляющие, какой оператор выполняется быстрее.

    4. Охарактеризуйте типы программ по степени важности для них эффективности.

    5. Почему удобочитаемость программ зачастую более существенна, чем эффективность?

    6. В чем особенности оптимизирующего компилятора?

    7. Что понимают под машинно-зависимой и машинно-независимой оптимизацией?

    8. Что такое критическая точка программы? Как это понятие используется при оптимизации?

    9. Охарактеризуйте приемы чистки и перепрограммирования программного кода.

    10. Каковы шаги оптимизации программы?

    11. Особенности оптимизации использования памяти?

    12. Какова роль описания переменных, инициирования переменных, вычисления констант, арифметических операций в повышении эффективности программ?

    13. Охарактеризуйте влияние циклов на эффективность программы.

    Глава 13. Структурное тестирование по

    1.Основные понятия и принципы тестирования по

    Тестированиепроцесс выполнения программы с целью обнаружения ошибок. Шаги процесса задаются тестами. Каждый тест определяет:

    • свой набор исходных данных и условий для запуска программы;

    • набор ожидаемых результатов работы программы.

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

    Целью проектирования тестовых вариантов является систематическое обнаружение различных классов ошибок при минимальных затратах времени и стоимости. Тестирование обеспечивает:

    • обнаружение ошибок;

    • демонстрацию соответствия функций программы ее назначению;

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

    • отображение надежности как индикатора качества программы.

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

    Рассмотрим информационные потоки процесса тестирования. Они показаны на рис. 1.

    Рис. 1. Информационные потоки процесса тестирования

    На входе процесса тестирования три потока:

    • текст программы;

    • исходные данные для запуска программы;

    • ожидаемые результаты.

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

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

    • качество и надежность ПО удовлетворительны;

    • тесты не способны обнаруживать серьезные ошибки.

    В конечном счете, если тесты не обнаруживают ошибок, появляется сомнение в том, что тестовые варианты достаточно продуманны и что в ПО нет скрытых ошибок. Такие ошибки будут, в конечном итоге, обнаруживаться пользователями и корректироваться разработчиком на этапе сопровождения (когда стоимость исправления возрастает в 60 – 100 раз по сравнению с этапом разработки).

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

    Существуют 2 принципа тестирования программы:

    • функциональное тестирование (тестирование «черного ящика»);

    • структурное тестирование (тестирование «белого ящика»).

    2.Тестирование «черного ящика»

    Известны: функции программы.

    Исследуется: работа каждой функции на всей области определения.

    Как показано на рис. 2, основное место приложения тестов «черного ящика» - интерфейс ПО.

    Рис. 2. Тестирование «черного ящика»

    Эти тесты демонстрируют:

    • как выполняются функции программ;

    • как принимаются исходные данные;

    • как вырабатываются результаты;

    • как сохраняется целостность внешней информации.

    При тестировании «черного ящика» рассматриваются системные характеристики программ, игнорируется их внутренняя логическая структура. Исчерпывающее тестирование, как правило, невозможно. Например, если в программе 10 входных величин и каждая принимает по 10 значений, то потребуется 10 тестовых вариантов. Отметим также, что тестирование «черного ящика» не реагирует на многие особенности программных ошибок.

    3.Тестирование «белого ящика»

    Известна: внутренняя структура программы.

    Исследуются: внутренние элементы программы и связи между ними (рис. 3).

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

    Рис. 3. Тестирование «белого ящика»

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

    В этом случае формируются тестовые варианты, в которых:

    • гарантируется проверка всех независимых маршрутов программы;

    • проходятся ветви True, False для всех логических решений;

    • выполняются все циклы (в пределах их границ и диапазонов);

    • анализируется правильность внутренних структур данных.

    Недостатки тестирования «белого ящика»:

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

    При n = 5 и k = 20 количество маршрутов m = 10 . Примем, что на разработку,

    выполнение и оценку теста по одному маршруту расходуется 1 мс. Тогда при

    работе 24 часа в сутки 365 дней в году на тестирование уйдет 3170 лет.

    • Исчерпывающее тестирование маршрутов не гарантирует соответствия программы исходным требованиям к ней.

    • В программе могут быть пропущены некоторые маршруты.

    • нельзя обнаружить ошибки, появления которых зависит от обрабатываемых данных (это ошибки, обусловленные выражениями типа if abs (a-b) < eps…, if (a+b+c)/3=a…).

    Достоинства тестирования «белого ящика» связаны с тем, что принцип «белого ящика» позволяет учесть особенности программных ошибок:

    1. Количество ошибок минимально в «центре» и максимально на «периферии» программы.

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

    3. При записи алгоритма ПО в виде текста на языке программирования возможно внесение типовых ошибок трансляции (синтаксических и семантических).

    4. Некоторые результаты в программе зависят не от исходных данных, а от внутренних состояний программы.

    Каждая из этих причин является аргументом для проведения тестирования по принципу «белого ящика». Тесты «черного ящика» не смогут реагировать на ошибки таких типов.

    Способ тестирования базового пути

    Тестирование базового пути – это способ, который основан на принципе «белого ящика». Автор этого способа – Том МакКейб.

    Способ тестирования базового пути дает возможность:

    • получить оценку комплексной сложности программы;

    • использовать эту оценку для определения необходимого количества тестовых вариантов.

    Тестовые варианты разрабатываются для проверки базового множества путей (маршрутов) в программе. Они гарантируют однократное выполнение каждого оператора программы при тестировании.

    Цикломатическая сложность

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

    • количество независимых путей в базовом множестве программы;

    • верхнюю оценку количества тестов, которое гарантирует однократное выполнение всех операторов.

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

    1. тесты, обеспечивающие его проверку, гарантируют:

      • однократное выполнение каждого оператора;

      • выполнение каждого условия по True-ветви и по False-ветви.

    2. мощность базового множества равна цикломатической сложности потокового графа.

    Значение 2-го свойства трудно переоценивать – оно дает априорную оценку количества независимых путей, которое имеет смысл искать в графе.

    Цикломатическая сложность определяется по формуле :

    где Е – количество дуг, N - количество узлов потокового графа;

    Способы тестирования условий

    Цель этого семейства способов тестирования – строить тестовые варианты для проверки логических условий программы. При этом желательно обеспечить охват операторов из всех ветвей программы.

    Рассмотрим используемую здесь терминологию. Простое условие – булева переменная или выражение отношения. Выражение отношения имеет вид

    Е1 <оператор отношения> Е2,

    где Е1, Е2 – арифметические выражения, а в качестве оператора отношения используется один из следующих операторов:

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

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

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

    • ошибка булева оператора (наличие некорректных / отсутствующих / избыточных булевых операторов);

    • ошибка булевой переменной;

    • ошибка булевой скобки;

    • ошибка оператора отношения;

    • ошибка арифметического выражения.

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

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

    Существует несколько методик тестирования условий.

    1.Простейшая методика – тестирование ветвей. Здесь для составного условия С проверяется:

    • каждое простое условие (входящее в него);

    • True-ветвь;

    • False-ветвь.

    2.Другая методика – тестирование области определения. В ней для выражения отношения требуется генерация 3-4 тестов. Выражение вида

    Е1 <оператор отношения> Е2,

    Проверяется тремя тестами, которые формируют значение Е1 большим, чем Е2, равным Е2 и меньшим, чем Е2. Если оператор отношения неправилен, а Е1 и Е2 корректны, то эти три теста гарантируют обнаружение ошибки оператора отношения. Для определения ошибок в Е1 и Е2 тест должен сформировать значение Е1 большим или меньшим, чем Е2, причем обеспечить как можно меньшую разницу между этими значениями.

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

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

    Тестирование циклов

    Цикл – наиболее распространенная конструкция алгоритмов, реализуемых в ПО. Тестирование циклов производится по принципу «белого ящика», при проверке циклов основное внимание обращается на правильность конструкций циклов. Различают 4 типа циклов: простые, вложенные, объединенные, неструктурированные.

    Простые циклы Объединенные циклы

    Вложенные циклы Неструктурированные

    циклы

    Простые циклы

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

    1. прогон всего цикла;

    2. только один проход цикла;

    3. два прохода цикла;

    4. m проходов цикла, где m < n;

    5. n1, n, n + 1 проходов цикла.

    Вложенные циклы

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

    Рис. 11. Объемлющий и вложенный циклы

    Порядок тестирования вложенных циклов иллюстрирует рис.12.

    Рис.12. Шаги тестирования вложенных циклов

    Шаги тестирования.

    1. Выбираем самый внутренний цикл. Устанавливаются минимальные значения параметров всех остальных циклов.

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

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

    4. Работа продолжается до тех пор, пока не будет протестированы все циклы.

    Объединенные циклы

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

    Неструктурированные циклы

    Неструктурированные циклы тестированию не подлежат. Этот тип циклов должен быть переделан с помощью структурированных программных конструкций.

    Контрольные вопросы

    1. Определите понятие тестирования. Что такое тест?

    2. Что такое исчерпывающее тестирование?

    3. Какие задачи решает тестирование?

    4. Каких задач не решает тестирование?

    5. Какие принципы тестирования вы знаете? В чем их отличие?

    6. В чем состоит суть тестирования «черного ящика»?

    7. В чем состоит суть тестирования «белого ящика»?

    8. В чем достоинства и недостатки каждого из принципов тестирования?

    9. Поясните понятие базового пути.

    10. Какие способы вычисления цикломатической сложности вы знаете?

    11. Поясните особенности тестирования циклов.

    12. Каковы шаги тестирования вложенных циклов?

    Глава 14. Функциональное тестирование по

    Функциональное тестирование, основанное на принципе «чёрного ящика», может применяться как на уровне программных модулей, так .и на уровне программной системы.

    1. Особенности тестирования «чёрного ящика»

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

    • набор, образуемый такими входными данными, которые приводят к аномалиям поведения программы (назовём его IT);

    • набор, образуемый такими входными данными, которые демонстрируют дефекты программы (назовём его OT).

    Как показано на рисунке 1, любой способ тестирования «чёрного ящика» должен:

    • выявить такие входные данные, которые с высокой вероятностью принадлежат набору IT;

    • сформулировать такие ожидаемые результаты, которые с высокой вероятностью являются элементами набора OT.

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

    Выходные данные,

    приводящие к аномалиям

    поведения

    Выходные данные,

    выявляющие наличие

    дефектов

    Рис. 1. Тестирование «чёрного ящика»

    Принцип «чёрного ящика» не альтернативен принципу «белого ящика». Скорее это дополняющий подход, который обнаруживает другой класс ошибок.

    Тестирование «чёрного ящика» обеспечивает поиск следующих категорий ошибок:

    1. некорректных или отсутствующих функций;

    2. ошибок интерфейса;

    3. ошибок во внешних структурах данных или в доступе к внешней базе данных;

    4. ошибок характеристик (необходимая ёмкость памяти);

    5. ошибок инициализации и завершения;

    Подобные категории ошибок способами «белого ящика» не выявляются.

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

    Техника «чёрного ящика» ориентированна на решении следующих задач:

    • сокращение необходимого количества тестовых вариантов (из-за проверки не статических, а динамических аспектов системы);

    • выявление классов ошибок, а не отдельных ошибок;

    2. Способ разбиения по эквивалентности

    Разбиение по эквивалентности − самый популярный способ тестирования «чёрного ящика». В этом способе входная область данных программы делится на классы эквивалентности. Для каждого класса эквивалентности разрабатывается один тестовый вариант. Класс эквивалентности − набор данных с общими свойствами. Обрабатывая разные элементы класса, программа должна вести себя одинаково. Иначе говоря, при обработке любого набора из класса эквивалентности в программе задействуется один и тот же набор операторов (и связей между ними). На рис.2. каждый класс эквивалентности показан эллипсом. Здесь выделены входные классы эквивалентности допустимых и недопустимых исходных данных, а также классы результатов. Классы эквивалентности могут быть определены по спецификации на программу.

    Классы эквивалентности исходных данных

    Программное изделие

    Рис. 2. Разбиение по эквивалентности

    Например, если спецификация задаёт в качестве допустимых входных величин 5-разрядные целые числа в диапазоне 15 000…70 000, то класс эквивалентности допустимых ИД (исходных данных) включает величины от 15 000 до

    70 000, а два класса эквивалентности недопустимых ИД составляют:

    • числа меньшие, чем 15 000;

    • Числа большие, чем 70 000;

    Класс эквивалентности включает множество значений данных, допустимых или недопустимых по условиям ввода.

    Условие ввода может задавать:

    1. определённое значение;

    2. диапазон значений;

    3. множество конкретных величин;

    4. булево условие;

    Сформулируем правила формирования классов эквивалентности.

    1. Если условие ввода задаёт диапазон nm, то определяются один допустимый и два недопустимых класса эквивалентности:

    • V_Class={nm} − допустимый класс эквивалентности;

    • Inv_Class1={x|для любого x: x<n} − первый недопустимый класс эквивалентности;

    • Inv_Class2={y|для любого y: y>m} − второй недопустимый класс эквивалентности;

    2. Если условие ввода задаёт конкретное значение а, то определяются один допустимый и два недопустимых класса эквивалентности:

    • V_Class={а};

    • Inv_Class1={x|для любого x: x<a};

    • Inv_Class2={y|для любого y: y>a};

    3. Если условие ввода задаёт множество значений {а,b,c},то определяются один допустимый и один недопустимый класс эквивалентности:

    • V_Class={а,b,c};

    • Inv_Class={x|для любого x:(xa)&(xb)&(xc)}.

    4. Если условие ввода задаёт булево значение, например true, то определяются один допустимый и один недопустимый класс эквивалентности:

    • V_Class={ true};

    • Inv_Class={false}.

    После построения классов эквивалентности разрабатываются тестовые варианты. Тестовый вариант выбирается так, чтобы проверить сразу наибольшее количество свойств класса эквивалентности.

    3. Способ анализа граничных значений

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

    1. тестовые варианты создаются для проверки только рёбер классов эквивалентности;

    2. при создании тестовых вариантов учитывают не только условия ввода, но и область ввода.

    Сформулируем правила анализа граничных значений.

    1. Если условие ввода задаёт диапазон nm, то тестовые варианты должны быть построены:

    • для значений n и m;

    • для значений чуть левее n и чуть правее m на числовой оси.

    Например, если задан входной диапазон -1,0…+1,0, то создаются тесты для значений -1,0, +1,0, -1,001, +1,001.

    2. Если условие ввода задаёт множество значений, то создаются тестовые варианты:

    • для проверки минимального и максимального из значений;

    • для значений чуть меньше минимума и чуть больше максимума.

    Так, если входной файл может содержать от 1 до 255 записей, то создаются тесты для 0, 1, 255, 256 записей.

    3. Правила 1 и 2 применяются к условиям области вывода.

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

    4. Если внутренние структуры данных программы имеют предписанные границы, то разрабатываются тестовые варианты, проверяющие эти структуры на их границах.

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

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

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

    Пред-условия:

    1. массив должен быть упорядочен;

    2. массив должен иметь не менее одного элемента;

    3. нижняя граница массива (индекс) должна быть меньше или равна его верхней границе;

    Пост-условия:

    1. если элемент найден, то флаг Result=True, значение I − номер элемента;

    2. если элемент не найден, то флаг Result=False, значение I не определено.

    Для формирования классов эквивалентности (и их рёбер) надо произвести разбиение области ИД − построить дерево разбиений. Листья дерева разбиений дадут нам искомые классы эквивалентности. Определим стратегию разбиения. На первом уровне будем анализировать выполнимость предусловий, на втором − выполнимость постусловий. На третьем уровне можно анализировать специальные требования, полученные из практики разработчика. В нашем примере мы знаем, что входной массив должен быть упорядочен. Обработка упорядоченных наборов из чётного и нечётного количества элементов может выполняться по-разному. Кроме того, принято выделять специальный случай одноэлементного массива. Следовательно, на уровне специальных требований возможны следующие эквивалентные разбиения:

    1. массив из одного элемента;

    2. массив из чётного количества элементов;

    3. массив из нечётного количества элементов, большего единицы.

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

    1. работа с первым элементом массива;

    2. работа с последним элементом массив;

    3. работа с промежуточным (ни с первым, ни с последним) элементом массива;

    Структура дерева разбиений приведена на рис. 3.

    Это дерево имеет 11 листьев. Каждый лист задаёт отдельный тестовый вариант. Покажем тестовые варианты, основанные на проведённых разбиениях.

    Тестовый вариант 1 (единичный массив, элемент найден) ТВ1:

    ИД: М=15; Key=15.

    ОЖ.РЕЗ.: Result=True; I=1.

    Тестовый вариант 2 (чётный массив, найден 1-й элемент) ТВ2:

    ИД: М=15,20,25,30,35,40; Key=15.

    ОЖ.РЕЗ.: Result=True; I=1.

    Тестовый вариант 3 (чётный массив, найден последний элемент) ТВ3:

    ИД: М=15,20,25,30,35,40; Key=40.

    ОЖ.РЕЗ.: Result=True; I=6.

    Тестовый вариант 4 (чётный массив, найден промежуточный элемент) ТВ4:

    ИД: М=15,20,25,30,35,40; Key=25.

    ОЖ.РЕЗ.: Result=True; I=3.

    Тестовый вариант 5 (нечётный массив, найден 1-й элемент) ТВ5:

    ИД: М=15,20,25,30,35,40,45; Key=15.

    ОЖ.РЕЗ.: Result=True; I=1.

    Тестовый вариант 6 (нечётный массив, найден последний элемент) ТВ6:

    ИД: М=15,20,25,30,35,40,45; Key=45.

    ОЖ.РЕЗ.: Result=True; I=7.

    Тестовый вариант 7 (нечётный массив, найден промежуточный элемент) ТВ7:

    ИД: М=15,20,25,30,35,40,45; Key=30.

    ОЖ.РЕЗ.: Result=True; I=4.

    Единичный М1

    Первый элемент 2

    Первый элемент 5

    Последний элемент 6

    Промежуточный элемент 7

    Предусловия

    Постусловия

    Специальные требования

    Граничные рёбра

    Рис.3. Дерево разбиений области исходных данных бинарного поиска

    Тестовый вариант 8 (чётный массив, не найден элемент) ТВ8:

    ИД: М=15,20,25,30,35,40; Key=23.

    ОЖ.РЕЗ.: Result= False; I=?.

    Тестовый вариант 9 (нечётный массив, не найден элемент) ТВ9:

    ИД: М=15,20,25,30,35,40,45; Key=24.

    ОЖ.РЕЗ.: Result= False; I=?.

    Тестовый вариант 10 (единичный массив, не найден элемент) ТВ10:

    ИД: М=15; Key=0.

    ОЖ.РЕЗ.: Result= False; I=?.

    Тестовый вариант 11 (нарушены предусловия) ТВ11:

    ИД: М=15,10,5,25,20,40,35; Key=35.

    ОЖ.РЕЗ.: Аварийное донесение. Массив не упорядочен.

    4. Способ диаграмм причин-следствий

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

    Шаги способа:

    1. для каждого модуля перечисляются причины (условия ввода или классы эквивалентности условий ввода) и следствия (действия или условия ввода). Каждой причине и следствию присваивается свой идентификатор;

    2. разрабатывается граф причинно-следственных связей4

    3. граф преобразуется в таблицу решений;

    4. столбцы таблицы решений преобразуются в тестовые варианты.

    Изобразим базовые символы для записи графов причин и следствий (cause-effect graphs).

    Обозначения. Сделаем предварительные замечания:

    1. причины будем обозначать символами ci , а следствия – символами ei;

    2. каждый узел графа может находиться в состоянии 0 или 1 (0 – состояние отсутствует, 1 – состояние присутствует).

    Функция тождество (рис. 4) устанавливает, что если значение ci есть 1, то и значение ei есть 1; в противном случае значение ei есть 0.

    Рис. 4. Функция тождество

    Функция не (рис. 5) устанавливает, что если значение c1 есть 1, то значение е1 есть 0, в противном случае значение е1 есть 1.

    Рис. 5. Функция не

    Функция или (рис. 6) устанавливает, что если c1 или c2 есть 1, то е1 есть 1, в противном случае е1 есть 0.

    V

    Рис. 6. Функция или

    Функция или (рис. 7) устанавливает, что если c1 и c2 есть 1, то е1 есть 1, в противном случае е1 есть 0.

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

    Рис. 7. Функция и

    Ограничение Е (исключает, Exclusive, рис. 8) устанавливает, что Е должно быть истинным, если хотя бы одна из причин – а или b – принимает значение 1 (а и b не могут принимать значение 1одновременно).

    Е

    Рис. 8. Ограничение Е (исключает, Exclusive)

    О граничение I (включает, Inclusive, рис. 9) устанавливает, что по крайней мере одна из величин а, b или с, всегда должна быть равной 1(а, b и с не могут принимать значение 0 одновременно

    I

    Рис. 9. Ограничение I (включает, Inclusive)

    О граничение O (одно и только одно, Only one, рис. 10) устанавливает, что одна и только одна из величин а или b должна быть равна 1.

    О

    Рис. 10. Ограничение О (одно и только одно, Only one)

    Ограничение R (требует, Requires, рис. 11) устанавливает, что если а принимает значение 1, то и b должна принимать значение 1 (нельзя, чтобы а было равно 1, а б – 0).

    R

    Рис. 11. Ограничение R (требует, Requires)

    Часто возникает необходимость в ограничениях для следствий.

    Ограничение М (скрывает, Masks, рис. 12) устанавливает, что если следствие а имеет значение 1, то следствие b должно принять значение 0.

    Рис. 12. Ограничение М (скрывает, Masks)

    Пример

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

    При расчёте по среднему тарифу:

    • при месячном потреблении энергии меньшем, чем 100 кВт/ч, выставляется фиксированная сумма;

    • при потреблении энергии большем или равном 100 кВт/ч применяется процедура А планирования расчёта;

    При расчёте по переменному тарифу:

    • при месячном потреблении энергии меньшем, чем 100 кВт/ч, применяется процедура А планирования расчёта;

    • при потреблении энергии большем или равном 100 кВт/ч применяется процедура В планирования расчёта;

    Шаг 1. Причинами являются:

    1. расчёт по среднему тарифу;

    2. расчёт по переменному тарифу;

    3. месячное потребление электроэнергии меньшее, чем 100 кВт/ч;

    4. месячное потребление электроэнергии большее или равное 100 кВт/ч.

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

    • 101 – минимальная месячная стоимость;

    • 102 – процедура А планирования расчёта;

    • 103 – процедура В планирования расчёта;

    Шаг 2. Разработка графа причинно-следственных связей (рис.13).

    Узлы причин перечислим по вертикали у левого края рисунка, а узлы следствий – у правого края рисунка. Для следствия 102 возникает необходимость введения вторичных причин – 11 и 12, – их размещаем в центральной части рисунка.

    Е

    V

    О

    Рис. 13. Граф причинно-следственных связей

    Шаг 3. Генерация таблицы решений. При генерации причины рассматриваются как условия, а следствия – как действия.

    Порядок генерации.

    1. Выбирается некоторое следствие, которое должно быть в состоянии «1».

    2. Находятся все комбинации причин (с учётом ограничений), которые устанавливают это следствие в состояние «1». Для этого из следствия прокладывается обратная трасса через граф.

    3. Для каждой комбинации причин, приводящих следствие в состояние «1»,

    строится один столбец.

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

    2. Действия 1-4 повторяются для всех следствий графа.

    Таблица решений для нашего примера показана в табл. 1.

    Шаг 4. Преобразование каждого столбца таблицы в тестовый вариант. В нашем примере таких вариантов четыре.

    Тестовый вариант 1 (столбец 1) ТВ1:

    ИД: расчёт по среднему тарифу; месячное потребление электроэнергии 75 кВт/ч.

    ОЖ.РЕЗ.: минимальная месячная стоимость.

    Тестовый вариант 2 (столбец 2) ТВ2:

    ИД: расчёт по переменному тарифу; месячное потребление электроэнергии 90 кВт/ч.

    ОЖ.РЕЗ.: процедура А планирования расчёта.

    Тестовый вариант 3 (столбец 3) ТВ3:

    ИД: расчёт по среднему тарифу; месячное потребление электроэнергии 100 кВт/ч.

    ОЖ.РЕЗ.: процедура В планирования расчёта.

    Тестовый вариант 4 (столбец 4) ТВ4:

    ИД: расчёт по переменному тарифу; месячное потребление электроэнергии 100 кВт/ч.

    ОЖ.РЕЗ.: процедура В планирования расчёта.

    Табл. 1. Таблица решений для расчёта оплаты за электричество

    Номера столбцов→

    1

    2

    3

    4

    Условия

    Причины

    1

    1

    0

    1

    0

    2

    0

    1

    0

    1

    3

    1

    1

    0

    0

    4

    0

    0

    1

    1

    Вторичные причины

    11

    0

    0

    1

    0

    12

    0

    1

    0

    0

    Действия

    Следствия

    101

    1

    0

    0

    0

    102

    0

    1

    1

    0

    103

    0

    0

    0

    1

    Контрольные вопросы

    1. Каковы особенности тестирования методом «чёрного ящика»?

    2. Какие категории ошибок выявляют тестирования методом «чёрного ящика»?

    3. Какие достоинства имеет тестирования методом «чёрного ящика»?

    4. Поясните суть способа разбиения по эквивалентности?

    5. Что такое класс эквивалентности?

    6. Что может задавать условие ввода?

    7. Какие правила формирования классов эквивалентности вы знаете?

    8. Как выбирается тестовый вариант при тестировании по способу разбиения по эквивалентности?

    9. Поясните суть способа анализа граничных значений.

    10. Чем способ анализа граничных значений отличается от разбиения по эквивалентности?

    11. Поясните правила анализа граничных значений.

    12. Что такое дерево разбиений? Каковы его особенности?

    13. В чём суть способа диаграмм причин-следствий?

    14. Что такое причина?

    15. Что такое следствие?

    16. Дайте общую характеристику графа причинно-следственных отношений.

    17. Какие функции используются в графе причин и следствий?

    18. Какие ограничения используются в графе причин и следствий?

    19. Поясните шаги способа диаграмм причин-следствий.

    20. Какую структуру имеет таблица решений в способе диаграмм причин-следствий?

    21. Как таблица решений преобразуется в тестовые варианты?

    Глава 15. Комплексное тестирование. Отладка

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

    1. Методика комплексного тестирования пс

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

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

    Охарактеризуем каждый шаг процесса тестирования.

    1. Тестирование элементов. Цель – индивидуальная проверка каждого модуля. Используются способы тестирования «белого ящика».

    2. Тестирование интеграции. Цель – тестирование сборки модулей в программную систему. В основном применяют способы тестирования «чёрного ящика».

    3. Тестирование правильности. Цель –проверить реализацию в программной системе всех функциональных и поведенческих требований, а также требования эффективности. Используются исключительно способы тестирования «чёрного ящика».

    4. Системное тестирование. Цель – проверка правильности объединения и взаимодействия всех элементов компьютерной системы, реализации всех системных функций.

    Организация процесса тестирования в виде эволюционно разворачивающейся спирали обеспечивает максимальную эффективность поиска ошибок. Однако возникает вопрос – когда заканчивается тестирование?

    Ответ практика обычно основан на статистическом критерии: «Можно с 95% уверенностью сказать, что провели достаточное тестирование, если вероятность безотказной работы ЦП с программным изделием в течение 1000 часов составляет, по меньшей мере, 0,995».

    Научный подход при ответе на этот вопрос состоит в применении математической модели отказов. Например, для логарифмической модели Пуассона формула расчёта текущей интенсивности отказов имеет вид:

    λ(t) = λ0 λ0 × p × t +1

    × t +1

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

    Системный анализ

    Анализ требований

    Проектирование

    Кодирование

    Тестирование элементов

    Тестирование интеграции и

    Тестирование правильности

    Системное тестирование

    Рис.1.Спираль процесса тестирования ПС

    2.Тестирование элементов

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

    Тестирования подвергаются:

    • интерфейс модуля;

    • внутренние структуры данных;

    • независимые пути;

    • пути обработки ошибок;

    • граничные условия.

    Интерфейс модуля тестируется для проверки правильности ввода-вывода тестовой информации. Если нет уверенности в правильном вводе-выводе данных, нет смысла проводить другие тесты.

    Исследование внутренних структур данных гарантирует целостность сохраняемых данных.

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

    Наиболее общими ошибками вычисления являются:

    1. неправильный или непонятный приоритет арифметических операций;

    2. смешанная форма операций;

    3. некорректная инициализация;

    4. несогласованность в представлении точности;

    5. некорректное символическое представление выражений.

    Источниками ошибок сравнения и неправильных потоков управления являются:

    1. сравнение различных типов данных;

    2. некорректные логические операции и приоритетность;

    3. ожидание эквивалентности в условиях, когда ошибки точности делают эквивалентность невозможной;

    4. некорректное сравнение переменных;

    5. неправильное прекращение цикла;

    6. отказ в выходе при отклонении итерации;

    7. неправильное изменение переменных цикла.

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

    1. донесение об ошибке не вразумительно;

    2. текст донесения не соответствует обнаруженной ошибке;

    3. вмешательство системных средств регистрации аварии произошло до обработки ошибке в модуле;

    4. обработка исключительного условия некорректна;

    5. описание ошибки не позволяет определить её причину.

    Граничное тестирование. Модули часто отказывают на «границах». Это означает, что ошибки часто происходят:

    1. при обработке n-го элемента n-элементного массива;

    2. при появлении минимального (максимального) значения.

    Тестовые ситуации, ориентированные на данные ситуации, имеют высокую вероятность обнаружения ошибок.

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

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

    (In Data) и ожидаемые результаты (ExpRes) тестовых вариантов, запускает в работу тестируемый модуль, получает из модуля реальные результаты (OutData) и формирует донесения о тестировании. Алгоритм работы тестового драйвера приведен на рис. 3.

    Рис. 2. Программная среда для тестирования модуля

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

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

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

    Открыть файл InData

    Рис. 3. Алгоритм работы драйвера тестирования

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

    3.Тестирование интеграции

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

    Тесты проводятся для обнаружения ошибок интерфейса. Перечислим некоторые категории ошибок интерфейса:

    • потеря данных при прохождении через интерфейс;

    • отсутствие в модуле необходимой ссылки;

    • неблагоприятное влияние одного модуля на другой;

    • подфункции при объединении не образуют требуемую главную функцию;

    • отдельные (допустимые) неточности при интеграции выходят за допустимый уровень;

    • проблемы при работе с глобальными структурами данных.

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

    3.1.Нисходящее тестирование интеграции

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

    Рассмотрим пример (рис.4.). Интеграция поиском в глубину будет подключать все модули, находящиеся на главном управляющем пути структуры (по вертикали). Выбор главного управляющего пути отчасти произволен и зависит от характеристик, определяемых приложением. Например, при выборе левого пути прежде всего будут подключены модули М1, М2, М5. Следующим подключается модуль М8 или М6 (если это необходимо для правильного функционирования М2). Затем строится центральный или правый управляющий путь.

    П ри интеграции поиском в ширину структура последовательно проходится по уровням-горизонталям. На каждом уровне подключаются модули, непосредственно подчиненные управляющему модулю – начальнику. В этом случае прежде всего подключаются модули М2, М3, М4. На следующем уровне – модули М5, М6 и т.д.

    Рис.4. Нисходящая интеграция системы

    Опишем возможные шаги процесса нисходящей интеграции.

    1. Главный управляющий модуль (находится на вершине иерархии) используется как тестовый драйвер. Все непосредственно подчиненные ему модули временно замещаются заглушками.

    2. Одна из заглушек заменяется реальным модулем. Модуль выбирается поиском в ширину или в глубину.

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

    4. Если в модуле-драйвере уже нет заглушек, производится смена модуля-драйвера (поиском в ширину или в глубину).

    5. Выполняется возврат на шаг2 (до тех пор, пока не будет построена целая структура).

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

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

    Существует 3 возможности борьбы с этим недостатком:

    1. откладывать некоторые тесты до замещения заглушек модулями;

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

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

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

    • заглушка А – отображает трассируемое сообщение;

    • заглушка В – отображает проходящий параметр;

    • заглушка С – возвращает величину из таблицы;

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

    Рис.5. Категории заглушек

    Категории заглушек представлены на рис.5. Очевидно, что заглушка А наиболее проста, а заглушка D наиболее сложна в реализации. Этот подход работоспособен, но может привести к существенным затратам, так как заглушки становятся все более сложными.

    3.2 Восходящее тестирование интеграции

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

    1. Модули нижнего уровня объединяются в кластеры (группы, блоки), выполняющие определенную программную подфункцию.

    2. Для координации вводов-выводов тестового варианта пишется драйвер, управляющий тестированием кластеров.

    3. Тестируется кластер.

    4. Драйверы удаляются, а кластеры объединяются в структуру движением вверх.

    Пример восходящей интеграции системы приведен на рис.6. Модули объединяются в кластеры 1, 2, 3. Каждый кластер тестируется драйвером. Модули в кластерах 1 и 2 подчинены модулю Ма, поэтому драйверы D1 и D2 удаляются и кластеры подключают к Ма. Аналогично драйвер D3 удаляется перед подключением кластера 3 к модулю Мb. В последнюю очередь к модулю Мс подключаются модули Ма и Мb.

    Рассмотрим различные типы драйверов:

    • драйвер А – вызывает подчиненный модуль;

    • драйвер В – посылает элемент данных (параметр) из внутренней таблицы;

    • драйвер С – отображает параметр из подчиненного модуля;

    • драйвер D – является комбинацией драйверов В и С.

    О чевидно, что драйвер А наиболее прост, а драйвер D наиболее сложен в реализации. Различные типы драйверов представлены на рис. 7.

    Кластер 1 3Кластер

    Рис.6. Восходящая интеграция системы

    Рис. 7. Различные типы драйверов

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

    Сравнение нисходящего и восходящего тестирования интеграции:

    Нисходящее тестирование:

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

    2. основное достоинство – возможность раннего тестирования главных управляющих функций.

    Восходящее тестирование:

    1. основной недостаток – система не существует как объект до тех пор, пока не будет добавлен последний модуль;

    2. основное достоинство – упрощается разработка тестовых вариантов, отсутствуют заглушки.

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

    При проведении тестирования интеграции очень важно выявить критические модули. Признаки критического модуля:

    1. реализует несколько требований к программной системе;

    2. имеет высокий уровень управления (находится достаточно высоко в программной структуре);

    3. имеет высокую сложность или склонность к ошибкам (как индикатор может использоваться цикломатическая сложность – ее разумный верхний предел составляет 10);

    4. имеет определенные требования к производительности обработки.

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

    4.Тестирование правильности

    После окончания тестирования интеграции программная система собрана в единый корпус, интерфейсные ошибки обнаружены и откорректированы. Теперь начинается последний шаг программного тестирования – тестирование правильности. Цель – подтвердить, что функции, описанные в спецификации требований к ПС, соответствуют ожиданиям заказчика. Подтверждение правильности ПС с помощью тестов «черного ящика», демонстрирующих соответствие требованиям. При обнаружении отклонений от спецификации требований создается список недостатков. Как правило, отклонения и ошибки, выявленные при подтверждении правильности, требуют изменения сроков разработки продукта.

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

    1. системную спецификацию;

    2. план программного проекта;

    3. спецификацию требований к ПС; работающий или бумажный макет;

    4. предварительное руководство пользователя;

    5. спецификацию проектирования;

    6. листинги исходных текстов программ;

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

    8. руководства по работе и инсталляции;

    9. ехе-код выполняемый программы;

    10) описание базы данных;

    11) руководство пользователя по настройке;

    12) документы сопровождения; отчеты о проблемах ПС; запросы сопровождения; отчеты о конструкторских изменения;

    13) стандарты и методики конструирования ПС.

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

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

    Альфа-тестирование проводится заказчиком в организации разработчика. Разработчик фиксирует все выявленные заказчиком ошибки и проблемы использования.

    Бета-тестирование проводится конечным пользователем в организации заказчика. Разработчик в этом процессе участия не принимает. Фактически, бета-тестирование – это реальное применение ПС в среде, которая не управляется разработчиком. Заказчик сам записывает все обнаруженные проблемы и сообщает о них разработчику. Бета-тестирование выявленных проблем разработчик изменяет ПС и тем самым подготавливает продукт полностью на базе заказчика.

    5.Системное тестирование

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

    1. предусмотреть средства обработки ошибки, которые тестируют все вводы информации от других элементов системы;

    2. провести тесты, моделирующие неудачные данные или другие потенциальные ошибки интерфейса ПС;

    3. записать результаты тестов, чтобы использовать их как доказательство невиновности в случае «указания причины»;

    4. принять участие в планировании и проектировании системных тестов, чтобы гарантировать адекватное тестирование ПС.

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

    5.1.Тестирование восстановления

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

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

    5.2.Тестирование безопасности

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

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

    • попытки узнать пароль с помощью внешних средств;

    • атака системы с помощью специальных утилит, анализирующих защиты;

    • подавление, ошеломление системы (в надежде, что она откажется обслуживать других клиентов);

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

    • просмотр несекретных данных в надежде найти ключ для входа в систему.

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

    5.3.Стрессовое тестирование

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

    • генерируется 10 прерываний в сек. (при средней частоте 1, 2 прерывания в сек);

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

    • формируются варианты, требующие максимума памяти и других ресурсов;

    • генерируются варианты, вызывающие переполнение виртуальной памяти;

    • проектируются варианты, вызывающие чрезмерный поиск данных на диске.

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

    5.4. Тестирование производительности

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

    Тестирование производительности проверяет скорость работы ПО в компьютерной системе. Производительность тестируется на всех шагах процесса тестирования. Даже на уровне элемента при проведении тестов «белого ящика» может оцениваться производительность индивидуального модуля. Тем не менее, пока все системные элементы не объединятся полностью, не может быть установлена истинная производительность системы. Иногда тестирование производительности сочетают со стрессовым тестированием. При этом нередко требуется специальный аппаратный и программный инструментарий. Например, часто требуется точное измерение используемого ресурса (процессорного цикла и т.д.). Внешний инструментарий регулярно отслеживает интервалы выполнения, регистрирует события (например, прерывания) и машинные состояния. С помощью инструментария испытатель может обнаружить состояния, которые приводят к деградации и возможным отказам системы.

    6. Искусство отладки

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

    то процесс отладки уничтожает ее.

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

    1. причина найдена, исправлена, уничтожена;

    2. причина не найдена.

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

    Возможные разные способы проявления ошибок:

    1. программа завершается нормально, но выдает неверные результаты;

    2. программа зависает;

    3. программа завершается по прерыванию;

    4. программа завершается, выдает ожидаемые результаты, но хранимые данные испорчены (это самый неприятный вариант).

    Характер проявления ошибок также может меняться. Симптом ошибки может быть:

    • постоянным;

    • мерцающим;

    • пороговым (проявляется при превышении некоторого порога а обработке – 200 самолетов на экране отслеживается, а 201-й - нет);

    • отложенным (проявляется только после исправления маскирующих ошибок).

    В ходе отладки мы встречаем ошибки в широком диапазоне: от мелких неприятностей до катастроф. Следствием увеличения ошибок является усиление давления на отладчика – «найди ошибки быстрее!!!». Часто из-за этого давления разработчик устраняет одну ошибку и вносит две новые ошибки.

    Английский термин debugging (отладка) дословно переводится как «ловля блох», который отражает специфику процесса – погоню за объектами отладки, «блохами». Рассмотрим, как может быть организован этот процесс «ловли блох» .

    Различают две группы методов отладки:

    • аналитические;

    • экспериментальные.

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

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

    Цель отладки – найти оператор программы, при исполнении которого правильные аргументы приводят к неправильным результатам. Если место проявления симптома ошибки не является искомой аномалией, то один из аргументов оператора должен быть неверным. Поэтому надо перейти к исследованию предыдущего оператора, выработавшего этот неверный аргумент. В итоге пошаговое обратное прослеживание приводит к искомому ошибочному месту.

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

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

    В экспериментальных методов для прослеживания выполняется:

    1. Выдача значений переменных в указанных точках.

    2. Трассировка переменных (выдача их значений при каждом изменении).

    3. Трассировка потоков управления (имен вызываемых процедур, меток, на которые передается управление, номеров операторов перехода).

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

    Контрольные вопросы

    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. Поясните достоинства и недостатки экспериментальных методов отладки.

    Глава 16. Сопровождение программного обеспечения. Документирование результатов и хода разработки

    1. Проблемы документирования

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

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

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

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

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

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

    5. Стандартизация. Создаваемая программная документация должна соответствовать по своему содержанию и оформлению государственным стандартам и стандартам предприятия-разработчика и заказчика.

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

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

    2. Виды документации

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

    Всю программную документацию можно разбить на три большие группы — эксплуатационную, техническую и технологи­ческую.

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

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

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

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

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

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

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

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

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

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

    4. описание методов решения поставленных задач и используемых при этом алгоритмов;

    5. проекты модулей, описывающих интерфейсы каждого модуля его внутренние данные и структуру управления;

    6. тексты программных модулей на языке реализации;

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

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

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

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

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

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

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

    3. Средства автоматизации документирования

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

    Документирование ПО как вид деятельности можно разбить на три этапа — определение плана создаваемой документации, сбор необходимой информации и оформление документов в соответ­ствии с требуемыми стандартами.

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

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

    Средства автоматизации документирования встраиваются в развитые CASE-средства, а также поставляются отдельно. Наиболее известным из них является SoDA – Software Document Automation - автоматизированное документирование ПО (Rational Software);

    Контрольные вопросы

    1. Поясните требования к программной документации.

    2. Какие виды программной документации вы знаете?

    3. Что входит в эксплуатационную документацию?

    4. На кого рассчитана эксплуатационная документация?

    5. Что входит в состав технической документации?

    6. На кого рассчитана техническая документация?

    7. Что входит в состав технологической документации?

    8. На кого рассчитана технологическая документация?

    9. На какие этапы можно разбить процесс документирования?

    10. Какой этап документирования наиболее автоматизирован?

    11. Какие средства автоматизации документирования вы можете назвать?

    Глава 17. Защита программ

    1. Концептуальные основы защиты информации

    Основные определения

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

    • контроль целостности информации;

    • предотвращение несанкционированного доступа к вычислительной системе.

    Вопросы, касающиеся безопасности ИС, можно разделить на следующие группы:

    1. физическая безопасность (защита от сбоев питания);

    2. логическая безопасность (защита от несанкционированного доступа);

    3. социальная безопасность (законодательство о защите авторских прав на ПО).

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

    Анализ возможных угроз и каналов утечки информации

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

    Источники возможных угроз:

    1. Природные (стихийные бедствия, магнитные бури, радиоактивное излучение и осадки и т.д.);

    2. Технические (отключения или колебания электропитания, отказы и сбои аппаратно-программных средств, электромагнитные излучения и наводки, утечки через каналы связи);

    3. Созданные людьми (непреднамеренные действия, преднамеренные действия).

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

    1. Человек

    • хищение носителей информации;

    • чтение информации с экрана посторонним лицом;

    • чтение информации с распечаток.

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

    2. Аппаратура

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

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

    В первом случае необходимо осуществлять осмотр технических средств ИС на наличие устройств, не предусмотренных конкретной конфигурацией.

    Для закрытия второго канала утечки информации используют различные программно-аппаратные средства, осуществляющие снижение уровня ЭМИН, создающие преднамеренные помехи или осуществляющие кодирование информационных сигналов.

    3. Программа

    • несанкционированный доступ программы к информации;

    • расшифровка программной зашифрованной информации;

    • копирование программной информации с носителей.

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

    Классификация видов защиты информации

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

    1. защита информации от несанкционированного доступа (НСД);

    2. защита информации в системах связи;

    3. защита юридической значимости электронных документов;

    4. защита конфиденциальной информации от утечки по каналам побочных электромагнитных излучений и наводок (ПЭМИН);

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

    6. защита от несанкционированного копирования и распространения программ и ценной компьютерной информации.

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

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

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

    Защита информации от утечки по каналам ПЭМИН является важным аспектом зашиты конфиденциальной и секретной информации в ЭВМ от несанкционированного доступа со стороны посторонних лиц. Данный вид защиты направлен на предотвращение возможности утечки информативных электромагнитных сигналов за пределы охраняемой территории.

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

    Защита от несанкционированного копирования и распространения

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

    2. Организационно-правовое обеспечение защиты информации Организационные мероприятия и процедуры по обеспечению защиты информации

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

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

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

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

    • ведение служебной информации (генерацию паролей, сопровождение правил разграничения доступа и др);

    • приемку включаемых новых программных средств;

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

    Правовое регулирование и организация работ по защите информации

    Конфиденциальная информация в контексте норм правового регулирования может относиться к государственной тайне или коммерческой тайне.

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

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

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

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

    • патентную защиту;

    • защиту авторских прав;

    • защиту производственных секретов (лицензионные отношения);

    • торговый знак.

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

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

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

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

    Защита торгового знака подразумевает присваивание названия программному обеспечению и регистрацию его как торгового знака.

    3. Защита информации от несанкционированного доступа

    3.1. Основные понятия защиты от нсд

    Требования по защите от НСД в различных приложениях должны быть направлены на достижение трех основных свойств защищаемой информации:

    1. конфиденциальность;

    2. целостность;

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

    Все типы систем защиты от НСД должны содержать такие элементы, как диспетчер доступа, модель защиты и блок аутентификации.

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

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

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

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

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

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

    3.2. Формальные модели защиты

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

    З - множество субъектов доступа, являющихся активными структурными элементами модели (в большинстве случаев субъекты в свою очередь могут рассматриваться как объекты доступа, т.е. 3 является подмножеством О);

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

    М - матрица доступа, в которой строки соответствуют субъектам, а столбцы объектам; значение элемента матрицы М[З,О] определяет права доступа субъекта 3 к объекту О.

    Права доступа регламентируют способы обращения субъекта З к различным типам объектов доступа. Так, например, права доступа к файлам или сегментам памяти стандартными являются: чтение (К), запись (\У) и выполнение (Е). Дополнительно может использоваться еще одно право доступа - дополнение (А), означающее право субъекта производить запись данных в свободные области объекта без перекрытия имеющихся данных.

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

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

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

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

      1. Каждому охраняемому объекту доступа присваивается метка, отражающая уровень его конфиденциальности.

      2. Каждому субъекту доступа приписывается уровень доступа , определяющий возможность его доступа к объекту определенного уровня.

    Разграничение доступа к объектам ВС определяется следующими двумя:

        1. Субъекту разрешается доступ к документам только в том случае, если уровень допуска субъекта равен или выше уровня конфиденциальности объекта;

        2. Только специально определенные субъект и процесс могут снизить уровень конфиденциальности объекта.

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

    Использование данных моделей позволяет:

    • Децентрализовать критичную информацию о правилах доступа, рассеяв ее практически по всем элементам процесса доступа.

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

    3 3. Системы разграничения доступа

    На практике системы разграничения доступа, базирующиеся на моделях матричного типа, реализуются в виде специальных компонент, поставляющихся отдельно, либо входящих в состав операционных систем или СУБД. В таких ОС, как UNIX VAX Windows NТ функции разграничения доступа к объектам интегрированы непосредственно в управляющий модуль. Особенностью СРД этих ОС является децентрализованность механизмов диспетчера доступа, что приводит к невозможности строгого выполнения требований верифицируемости, защищенности и полноты контроля этих механизмов.

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

    К аппаратным средствам поддержки защиты и изоляции ядра безопасности относятся:

    • многоуровневые, привилегированные режимы выполнения команд (с числом уровней больше двух);

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

    • реализация механизма виртуальной памяти с разделением адресных пространств;

    • аппаратная реализация функций ОС;

    • хранение и распространение программ в ПЗУ;

    • использование новых архитектур ЭВМ (с отходом от фон-неймановской архитектуры в сторону повышения структурной сложности базовых машинных объектов).

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

    4 Защита информации в каналах связи

    4. 1. Основные понятия и определения

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

    а) Активное вторжение

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

    • воздействие на передаваемую информацию;

    • воспрепятствование передаче информации;

    • осуществление ложных соединений.

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

    1. установление связи;

    2. передача данных;

    3. завершение связи.

    На стадии установления связи возможны два типа вторжений: соединение с применением ложного идентификатора; повтор предыдущего соединения.

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

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

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

    Целостность данных при их передаче по каналам связи обеспечивается соответствующим способом шифрования. Основные криптоалгоритмы такие как DES , ГОСТ 28147-89, RSA, Эль - Гамапя, позволяют реализовать процедуры подтверждения целостности и подлинности передаваемой информации. Подтверждение подлинности информации означает, что источник информации можно надежно определить, то есть указать, что полученное сообщение передано данному объекту некоторым другим объектом в течение времени соединения. Целостность сообщения означает, что сообщение не модифицировалось в процессе передачи.

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

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

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

    Б ) Пассивное вторжение

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

    1. защита процесса передачи информации;

    2. шифрование информации;

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

    • частоты передачи сообщений и длины сообщений - трафика (меры . объема данных или сообщений, проходящих между пунктами в сети);

    • конфигурации сообщений;

    • адресов.

    Для этого используют следующие методы защиты:

    • дополнение сообщений;

    • маскировка адресов назначения;

    • защита идентификаторов;

    • защитная стратегия маршрутизации.

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

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

    Для защиты идентификаторов сети получают разные идентификаторы для разных соединений.

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

    4.2. Криптоалгоритмы и протоколы шифрования

    Криптография - сокрытие смысла информации, представленной в любой форме: в виде данных, хранящихся на диске или сообщений, передаваемых но каналам связи.

    Функции криптографии:

    • зашифрование/расшифрование (криптопреобразование) информации;

    • контроль целостности и подлинности информации с целью обнаружения случайных и преднамеренных искажений (аутентификация).

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

    Для сокрытия смысла информации применяют два типа преобразований:

    1. кодирование;

    2. шифрование.

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

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

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

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

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

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

    1. Ключ используется только для одного сеанса криптопреобразования (причина названия шифра).

    2. Ключ формируется случайным образом.

    3. Число элементов в ключе совпадает с числом элементов открытого текста. Это означает, что сколько бы раз в открытом тексте не встречался определенный элемент, он каждый раз. раз будет иметь новый кодовый идентификатор.

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

    Современные криптоалгоритмы подразделяются па два класса: ассиметричные и симметричные. В симметричных криптосистемах (классическая криптография) секретный ключ зашифрования совпадает с секретным ключей расшифрования. В России наиболее используемыми симметричными криптоалгоритмами являются DES - Государственный стандарт США на шифрование данных и ГОСТ 28147-89 — отечественный стандарт на шифрование данных. В асимметричных криптосистемах (криптография с открытым ключом открытый ключ шифрования не совпадает с секретным ключом дешифрования. Открытый ключ сообщается всем пользователям криптосистемы. Расшифровать с помощью открытого ключа зашифрованную информацию практически невозможно. В сети с N абонентами, каждый абонент вырабатывает собственную ключевую пару и, следовательно, в таких системах будет N открытых и N секретных ключей. На практике чаще всего применяется криптоалгоритм RSA .

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

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

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

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

    Существует целый ряд способов распределения ключей, использующих центр распределения ключей. Это позволяет сократить число необходимых ключей, так как не каждому пользователю сети надо секретно взаимодействовать с каждым. Пример протокола распределения ключей с использованием симметричной криптосистемы и ЦРК:

    • ЦРК вырабатывает и передает по защищенному каналу долговременные ключи каждому пользователю системы для связи с ЦРК; Когда пользователь А желает установить секретную связь с пользователем В, он посылает запрос в ЦРК с требованием секретного сеансового ключа для связи с пользователем В;

    • ЦРК вырабатывает сеансовый ключ, зашифровывает его два раза на долговременных ключах пользователей вместе с идентифицирующей пользователей информацией и рассылает соответствующие шифры пользователям А и В; 4. Пользователи А и В расшифровывают поступившие шифротексты и получают сеансовый ключ.

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

    4. 3. Алгоритмы и протоколы реализации функции цифровой подписи

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

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

    • идентификатор пользователя;

    • дата и время создания подписи;

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

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

    Криптографические хэш-функции подразделяются на два класса: с ключом и без ключа. Значение хэш-функции с ключом может вычислить лишь тот, кто знает некоторый секретный параметр-ключ. Такие функции называются МАС - кодами аутентификации сообщений (стандарт FIPS PUB 113-1985 (МАС)). Российским аналогом этого американского стандарта может служить режим имитоприставки в ГОСТ 28147-89.

    Хэш-функцией с ключом (зависящей от ключа) называется функция, имеющая следующие свойства:

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

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

    • При любых данных к и х вычисление Н(к,х) должно быть достаточно быстрым;

    • По любому данному х должно быть трудно угадать значение Н(к,х). Должно быть трудно определить ключ к даже по большому числу известных пар [х, Н(к,х)].

    В стандарте FIPS PUB 113-1985 хэш-функция с ключом построена на основе блочного стандарта шифрования DES с ключом из 56 бит. Хэш-функцнн без ключа называются MDS - код определения манипуляции. Они в свою очередь подразделяются на два подкласса: слабые однонаправленные хэш-функцнн и сильные однонаправленные хэш-функции.

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

    1. По открытому ключу. Злоумышленник знает только открытый ключ.

    2. По открытому ключу и сообщению. Злоумышленник знает открытый ключ и может наблюдать случайные пары (сообщение/подпись).

    3. По выбранным сообщениям. Злоумышленник может получить подписи к сообщениям выбранным им лично.

    Различают несколько уровней по степени раскрытия схемы подписей:

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

    • 'Выборочное подделывание. Злоумышленник подделывает подпись некоторого сообщения, по своему выбору.

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

    • Полное раскрытие схемы подписи. Злоумышленник может вычислить секретный ключ подписывающего.

    5. Программно-аппаратная форма защиты

    интеллектуальной собственности

    5.1. Методы защиты от исследования логики работы

    исполняемых модулей

    Выбор методов защиты от исследования исполняемых модулей обусловлен формой атаки: статическая или динамическая.

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

    Существуют следующие методы защиты от дизассемблирования:

    1. шифрование

    2. использование самогенерируемых кодов

    3. "обман" дизассемблера

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

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

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

    1. использование нестандартной структуры программы;

    2. скрытые переходы, вызовы подпрограмм и прерываний и выходы из них;

    3. переходы и вызовы подпрограмм по динамически изменяемым адресам;

    4. модификация исполняемых кодов.

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

    Второй способ заключается в нестандартной реализации некоторых операторов.

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

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

    2. Динамическая форма атаки предусматривает использование отладчиков. Проблема защиты заключается в обнаружении факта работы программы под отладчиком. Для этого могут использоваться следующие механизмы:

    1.Блокировка отладочных прерываний. Метод защиты зависит от того, восстанавливает ли отладчик среду своего функционирования. Эта функция заключается в переопределении отладчиком текущих векторов 1 и 3 на стандартный либо свой собственный обработчик. При восстановлении среды функционирования отладчиком защита заключается в перехвате отладочных прерываний. Если в процессе выполнения защищенной программы при вызове отладочного прерывания управление получает ее собственный обработчик, то программа функционирует не под отладчиком. В противном случае необходимо предпринять меры, препятствующие отладке. Пример отладчика – Turbo Debugger. Если отладчик не восстанавливает среду функционирования, то обработчики отладочных прерываний программы могут состоять из одной команды RET или выполнять какие-либо действия, фиксирующие факт работы программы под контролем отладчика. Пример отладчика - Debug.

    2.Блокировки прерываний от клавиатуры. В ходе трассировки программы необходимо нажимать на клавиши для перехода к очередной команде. Это можно использовать для блокировки отладчика. Так если отладчик не восстанавливает среду функционирования, то достаточно запретить клавиатурное прерывание при выполнении определенного участка программы (например, начало программы или наиболее важный ее участок). Запретить клавиатурное прерывание можно либо написать свой обработчик вектора 9, либо использовав порт контроллера прерываний 21h. При восстановлении отладчиком среды функционирования можно применить метод, описанный для блокировки отладочных прерываний контролируя при этом вектор 9.

    3.Использование прерывания таймера. Защищенная программа устанавливает свой обработчик для прерывания таймера, который устанавливает, например, флаг в случае прихода прерывания от таймера. В определенный момент времени она запрещает это прерывание и выполняет какую-либо работу, периодически проверяя флаг. Если программа работает под отладчиком, команда запрета прерываний не работает и флаг будет установлен, сигнализируя о работе под отладчиком.

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

    5.2. Сигнатурные методы защиты от несанкционированного копирования

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

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

    • Подсчет битов. Этот метод основан на том, что нет двух дисководов, вращающихся с одинаковой скоростью. Характеристика диска, зависящая от скорости его вращения, может рассматриваться в качестве сигнатуры. Например, при форматировании диска всегда остается пустое место на каждой дорожке между концом последнего сектора и началом первого. Форматирующая программа заполняет этот промежуток ничего не значащими битами. Размер этого пространства, и следовательно, число битов зависят от скорости вращения дисковода.

    • Запись ключевой информации в такие участки диска, как межсекторные промежутки, инженерные дорожки, между стандартными дорожками, а также в сектора, имеющие нестандартный формат.

    • Физическое расположение файлов на диске.

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

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

    5. 3. Аппаратные методы защиты от несанкционированного копирования

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

    • Простой электронный ключ. Содержит определенные числовые установки, а также программу их модификации в зависимости от входных значений. Эта информация записана в ПЗУ ключа.

    • Электронный ключ с памятью. Аналогичен предыдущему, но при этом способен запоминать определенный объем информации^ в энергонезависимой памяти.

    • Ключи с генераторами случайных чисел. Эти устройства имеют встроенные физические генераторы СЧ (генераторы "белого шума"). Выработанные случайные последовательности запоминаются во внутренней энергонезависимой памяти и служат сигнатурой.Некоторые типы ключей для генерации случайных чисел используют нестабильные процессы периферийных устройств (принтер).

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

    6 Компьютерная вирусология

    Общие вопросы компьютерной вирусологии

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

    1. троянские программы;

    2. люки;

    3. компьютерные черви;

    4. компьютерные вирусы.

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

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

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

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

    Имена вирусов могут формироваться в соответствии со следующими характеристиками:

    1. место разработки или обнаружения вируса ;

    2. по содержащимся в теле вируса текстовым строкам ;

    3. по вызываемым вирусам эффектам ;

    4. по длине вируса;

    5. в соответствии с классификационным кодом.

    Классификационный код был разработан в связи с появлением большого количества штаммов вирусов и необходимостью отражения в названии вируса его основных особенностей. Данный код состоит из буквенного префикса, количественной характеристики, буквенного суффикса. Префикс характеризует тип вируса: С, Е, R, В, М, J, МС. Количественная характеристика - длина вируса. Суффикс используется для определения номера штамма. Например RСЕ-1024С.

    Основные симптомы заражения вирусом:

    1. Изменение длины файла;

    2. Изменение даты и времени создания файла;

    3. Уменьшение объема оперативной и дисковой памяти;

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

    5. Зависание или перезагрузка операционной системы;

    6. Сбойные ситуации при работе с файлами в таких программах как Word, Ехсеl и т.д.

    Структура и алгоритмы работы компьютерных вирусов

    Классификация вирусов по алгоритму работы

    1. Вирусы - невидимки (Stealth).

    Stealth -вирусы маскируют свое присутствие в вычислительной системе. Для этого вирус использует следующие способы:

    • при просмотре длин зараженных программ не показывает их изменений путем перехвата функций 21h-ого прерывания. После их выполнения вирус уменьшает значение длины файла и передает управление вызвавшей прерывание программе.

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

    2. Полиморфные вирусы.

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

    3. DIR вирусы.

    Не модифицируют заражаемые файлы. Записывают свое тело в свободный кластер диска и помечают его как последний кластер файла. Корректируют каталог так, чтобы номер первого кластера зараженного файла указывал на кластер, в котором расположен вирус. После отработки вирус запускает на выполнение зараженную программу.

    Классификация вирусов по среде обитания

    I. Файловый нерезидентный вирус.

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

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

    • формирование команд перехода на тело вируса;

    • дозапись тела вируса в заражаемую программу;

    • передача управления программе-вирусоносителю

    В случае файлов типа ЕХЕ меняются значения точки входа в программу на тело вируса. Методы заражения файлов типа СОМ и ЕХЕ:

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

    • вставка в конец файла.

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

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

    2. Файловый резидентный вирус

    Файловые резидентные вирусы наряду с файлами заражают ОП. Резидентный вирус состоит из двух частей:

    • инсталлятор;

    • модуль обработки прерываний.

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

    • восстановление измененных байт зараженной программы;

    • проверка зараженности ОП;

    • установка модуля обработки прерываний в заданный участок ОП;

    • передача управления зараженной программы.

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

    3. Бутовый вирус

    Бутовый вирус является специализированной разновидностью файлового резидентного вируса. При заражении он может использовать следующие два способа:

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

    • замена стандартной загрузочной записи с сохранением ее в другом месте диска. В этом случае вирус состоит из двух частей - головы и хвоста. Голова располагается на месте загрузочной записи. Хвост может располагаться в следующих участках винчестера: в кластерах, помеченных как сбойные; в последних секторах винчестера; в неиспользованных блоках FAT -таблицы или каталога; на инженерных дорожках винчестера..Как правило, хвост содержит в себе оригинальную загрузочную запись. Действия бутового вируса: перехват управления при загрузке ОС; проверка зараженности ОП; перехват соответствующих прерываний (обычно всегда 13Н); перезапись стандартной загрузочной записи в ОП и передача ей управления; перехват управления по обращению к диску; проверка зараженности диска и перезапись тела вируса..

    3. Файлово-бутовый вирус

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

    4. Макро-вирус

    При работе с документом Word (Ехсеl) при выполнении различных действии ищет и выполняет соответствующие макросы - при сохранении файла вызывается макрос FileSave при сохранении по команде СОХРАНИТЬ КАК – FileSaveAs -, при печати документов - FilePrint и т.д. Вирусы семейства Масго.Word содержат в себе как минимум один из автоматических макросов или один из стандартных макросов. Если документ заражен, то при открытии документа Word вызывает зараженный автоматический макрос и, таким образом, запускает код вируса. Если же вирус содержит макросы со стандартными именами, то они получают управление при вызове соответствующего пункта меню (Открыть, Закрыть и т.д. )

    Контрольные вопросы

    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. Перечислите симптомы заражения компьютерным вирусом.

    Глава 18. Инструментарий технологии программирования. Case - технологии

    1. Классификация инструментальных средств

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

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

    Здесь связи означают:

    1 – заказчик на естественном (например, русском) языке объясняет математику или системотехнику (аналитику), какую прикладную задачу он хочет решить. Эта задача из некоторой предметной области, например, задача бухгалтерского учета или зачисления абитуриентов в ВУЗ;

    2 – математик (или системотехник - аналитик)) формализует задачу, представляя ее в виде математической модели или составляя строгое формальное описание процедуры ее решения, входных и выходных данных. Этот этап называется формализацией задачи;

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

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

    • основные характеристики программы, сведения об ее эксплуатации;

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

    • сведения для проверки работоспособности и корректности выполнения программы, для обеспечения функционирования и настройки программы на условия конкретного применения;

    • сведения о необходимых запросах со стороны программы и форматах ответов пользователя;

    • данные о нештатных ситуациях и поведении пользователя в них.

    Этот этап называется сдачей программы в эксплуатацию.

    Как видно, все связи на рисунке двунаправлены. Это означает, что в процессе проектирования программы идет диалог, в ходе которого уточняется и/или корректируется предмет общения.

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

    • для создания отдельных приложений (программ)

    • для создания информационных систем и технологий.

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

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

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

    Локальные средства:

    Языки программирования делятся на следующие виды:

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

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

    • машинно-ориентированные (язык С). Объединяет идеи ассемблера и алгоритмического языка. Программы компактны и работают очень быстро.

    • универсальные (Турбо-Паскаль, Бэйсик). Приближены максимально, насколько это возможно, к естественному английскому языку: название каждой команды – английское слово;

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

    • проблемно-ориентированные . Моделируют систему с помощью последовательности событий. Применяются, в частности, при проектировании вычислительных комплексов;

    • объектно-ориентированные . Имеют встроенные средства для моделирования новых объектов программирования;

    • логико-ориентированные .  Отдельно описываются правила предметной области, по которым затем выводятся новые факты.

    Системы программирования включают:

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

    • транслятор – программу, переводящую исходный текст во внутреннее представление компьютера;

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

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

    • справочные системы.

    Инструментальная среда пользователя – это специальные программные средства, встроенные в ППП:

    библиотеки функций, процедур, объектов и методов обработки;

    макрокоманды;

    программные модули-вставки;

    конструкторы экранных форм и отчетов;

    языки запросов высокого уровня.

    2. Средства для создания информационных систем и технологий поддерживают полный цикл проектирования сложной информационной системы или технологии от исследования объекта автоматизации до оформления проектной и прочей документации на информационную систему или технологию. Они позволяют  вести коллективную  работу  над  проектом за счет возможности работы в локальной сети, экспорта – импорта любых фрагментов проекта, организации управления проектом. Это, прежде всего, разнообразные CASE - средства. Подробнее CASE-технологии будут рассмотрены далее.

    2. Общая характеристика case- средств

    В рамках программной инженерии CASE-средства представляют собой основную технологию, используемую для создания и эксплу­атации систем ПО. Под CASE - средством (в соответствии с между­народным стандартом ISO/1ЕС 14102:1995(Е)) понимается програм­мное средство, поддерживающее процессы жизненного цикла ПО (определенные в стандарте ISO/1ЕС 12207:1995), включая анализ требований к системе, проектирование прикладного ПО и баз дан­ных, генерацию кода, тестирование, документирование, обеспечение качества, управление конфигурацией ПО и управление проектом, а также другие процессы. CASE-средства вместе с системным ПО и техническими средствами образуют среду разработки ПО (Software Engineering Environment).

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

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

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

    CASE-средствам присущи следующие основные особенности:

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

    • интеграция отдельных компонентов CASE-средств, обеспечива­ющая управляемость процессом разработки ПО;

    • использование специальным образом организованного хранили­ща проектных метаданных (репозитория).

    Интегрированное CASE-средство - (комплекс средств, поддержи­вающих полный ЖЦ ПО) содержит следующие компоненты:

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

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

    3. средства разработки приложений, включая языки 4GL (язык 4-го поколения) и генераторы кодов;

    4. средства управления требованиями

    5. средства управления конфигурацией ПО;

    6. средства документирования;

    7. средства тестирования

    8. средства управления проектом;

    9. средства реверсного инжиниринга ПО и баз данных.

    Репозиторий

    Основные функции средств организации и поддержки репозитория

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

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

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

    Графические средства (диаграммеры) обеспечивают:

    • создание иерархически связанных диаграмм, в которых сочета­ются графические и текстовые объекты;

    • создание и редактирование объектов в любом месте диаграммы;

    • создание, перемещение и выравнивание групп объектов, изменение их размеров, масштабирование;

    • сохранение связей между объектами при их перемещении и из­менении размеров;

    • автоматический контроль ошибок и др.

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

    1. контроль синтаксиса диаграмм и типов их элементов. Обычно такой контроль осуществляется при вводе и редактировании элементов диаграмм;

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

    3. сквозной контроль диаграмм одного или различных типов на предмет их состоятельности по уровням — вертикальное и горизонтальное балансирование диаграмм. При вертикальном балансировании диаграмм одного типа выявляются несбалансированные потоки данных между детализируемой и детализирующей диаграммами. Гори­зонтальное балансирование определяет несоответствия между структурами данных и спецификациями процессов.

    3. Классификация case-средств

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

    Классификация по типам отражает функциональную ориентацию СА8Е-средств на те или иные процессы ЖЦ и включает следующие типы:

    1. средства анализа и проектирования, предназначенные для пост­роения и анализа как моделей деятельности организации (пред­метной области), так и моделей проектируемой системы. К таким средствам относятся BPwin (PLATINUM technology), Silverrun(Silverrun technologies), Oracle Designer (Огас1е), Ration Rose(Ration Software), Paradigm Plus (PLATINUM technology), Power Designer (Sybase), System Architect (Popkin Software). Их целью является определение системных требований и свойств, которы­ми система должна обладать, а также создание проекта системы, удовлетворяющей этим требованиям и обладающей соответству­ющими свойствами. Выходом таких средств являются специфи­кации компонентов системы и их интерфейсов, алгоритмов и структур данных;

    2. средства проектирования баз данных, обеспечивающие моделиро­вание данных и генерацию схем баз данных (как правило, на язы­ке SQL – Structured Query Language - структурированном языке запросов) для наиболее распространенных СУБД. Средства проектирования баз данных имеются в составе таких CASE-средств, как Silverrun , Огас1е Designer, Paradigm Plus, Power Designer. Наи­более известным средством, ориентированным только на проектирование БД, является ERwin (PLATINUM technology);

    3. средства управления требованиями, обеспечивающие комплексную поддержку разнородных требований к создаваемой системе. Примерами таких средств являются RequisitePro (Rational Software) и DOORS - Dinamic Object-Oriented Requirements System—динамическая объектно-ориентированная система уп­равления требованиями (Quality Systems and Software Inc.);

    4. средства управления конфигурацией ПО — PVCS (Merant),С1еагCase (Rational Software) и др.;

    5. средства документирования. Наиболее известным из них является SoDA – Software Document Automation - автоматизированное документирование ПО (Rational Software);

    6. средства тестирования. Наиболее развитым на сегодняшний день средством является Rational Suite TestStudio (Rational Software) —набор продуктов, предназначенных для автоматического тести­рования приложений;

    7. средства управления проектом — Ореп Р1ап Professional (Welcom Software), MicroSoft Project 98 и др.;

    8. средства реверсного инжиниринга, предназначенные для переноса существующей системы ПО в новую среду. Они обеспечивают анализ программных кодов и схем баз данных и формирование на их основе различных моделей и проектных спецификаций. Средства анализа схем и формирования БД входят в состав таких CASE-средств, как Silverrun, Огас1е Designer, Power Designer,, ERwin. Анализаторы программных кодов имеются в составе Rational Rose и Paradigm Plus.

    Классификация по категориям определяет степень интегрированности по выполняемым функциям и включает отдельные локальные средства, решающие небольшие автономные задачи (tools), набор частично интегрированных средств, охватывающих большин­ство процессов ЖЦ ПО (toolkit), и полностью интегрированные сред­ства, поддерживающие весь ЖЦ ПО и связанные общим репозиторием. Помимо этого, CASE-средства можно также классифициро­вать по применяемым структурным или объектно-ориентированным методам анализа и проектирования ПО.

    На сегодняшний день российский рынок программного обеспе­чения располагает практически всеми перечисленными выше сред­ствами.

    4.Технология внедрения case-средств

    Термин "adoption" ("внедрение") используется в широком смыс­ле и охватывает все действия - от оценки первоначальных потреб­ностей до полномасштабного использования Case-средств в различ­ных подразделениях организации-пользователя. Процесс внедрения Case-средств включает следующие этапы:

    • определение потребностей в Case-средствах (рис.1);

    • оценка и выбор Case-средств (рис.2);

    • выполнение пилотного проекта;

    • практическое внедрение Case-средств.

    При определении потребностей в Case-средствах осуществляется анализ возможностей организации в отношении ее технологической базы, персонала и используемого ПО. Такой анализ определяется моделью оценки зрелости технологических процессов в организации СММ (Capability Maturity Model), разработанной SEI (Software Engineering Institute), стандартами ISO 9001: 1994 ; ISO 9003-3: 1991 и ISO 9004-2:1991. Главное в этих подходах — анализ различных аспектов происходя­щих в организации процессов.

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

    Рис.1 - Определение потребностей в CASE-средствах

    Рис.2 - Критерии выбора CASE средств

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

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

    1. Case-средства не обязательно дают немедленный эффект; он мо­жет быть получен только спустя какое-то время;

    2. реальные затраты на внедрение Case-средств обычно намного превышают затраты на их приобретение;

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

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

      • широкое разнообразие качества и возможностей Case-средств;

      • относительно небольшое время использования Case-средств в различных организациях и недостаток опыта их применения;

      • разнообразие практики внедрения Case-средств в различных организациях;

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

      • широкий диапазон предметных областей проектов;

      • различная степень интеграции Case-средств в различных про­ектах.

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

    Ключом к успешному внедрению СА8Е-средств является готов­ность организации, которая включает следующие аспекты:

    1. технология — понимание ограниченности существующих возможностей и способность принять новую технологию;

    2. культура - способность воспринять новые процессы и взаимоотношения между разработчиками и пользователями;

    3. управление — четкое руководство и организованность по отношению к наиболее важным этапам и процессам внедрения.

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

    Чтобы принять взвешенное решение относительно инвестиций в Case-технологию, пользователи вынуждены производить оценку отдельных Case-средств, опираясь на неполные и противоречивые данные. Эта проблема зачастую усугубляется недостаточным знани­ем всех возможных "подводных камней" использования Case-средств. Среди наиболее важных проблем выделяются следующие:

    • достоверная оценка отдачи от инвестиций в Case-средства затруднительна ввиду отсутствия приемлемых метрик и данных по проектам и процессам разработки ПО;

    • внедрение Case-средств может представлять собой достаточно длительный процесс и может не принести немедленной отдачи. Возможно даже краткосрочное снижение продуктивности в результате усилий, затрачиваемых на внедрение. Вследствие этого руководство организации-пользователя может утратить интерес к Case-средствам и прекратить поддержку их внедрения;

    • отсутствие полного соответствия между теми процессами и методами, которые поддерживаются Case-средствами, и теми, которые используются в данной организации, может привести к дополнительным трудностям;

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

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

    • негативное отношение персонала к внедрению новой Case-технологии может быть главной причиной провала проекта.

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

    Успеш­ное внедрение Case -средств должно обеспечить:

    1. высокий уровень технологической поддержки процессов разра­ботки и сопровождения ПО;

    2. положительное воздействие на некоторые или все из перечисленных факторов — производительность, качество продукции, со­блюдение стандартов, документирование;

    3. приемлемый уровень отдачи от инвестиций в Case-средства.

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

    Контрольные вопросы

    1. Что понимают под инструментарием технологии программирования?

    2. Какие классы инструментария вы можете назвать?

    3. Что включают в себя средства для создания отдельных приложений?

    4. Приведите классификацию языков программирования.

    5. Охарактеризуйте системы программирования.

    6. Что понимают под средствами для создания информационных систем и технологий?

    7. Что такое Case-средства?

    8. Укажите особенности Case –средств.

    9. Какие компоненты входят в интегрированное Case-средство?

    10. Что такое репозиторий?

    11. Какие функции выполняют диаграммеры Case-средства?

    12. Какие виды контроля предусмотрены в Case-средстве?

    13. Какие этапы жизненного цикла поддерживают Case-средства?

    14. Приведите классификацию Case-средств по типам.

    15. Приведите классификацию Case-средств по категориям.

    Глава 19. Коллективная разработка по

    1. Особенности больших программных проектов

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

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

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

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

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

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

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

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

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

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

    Документированность ПИ является, пожалуй, основной ха­рактеристикой, облегчающей сопровождение и модификацию ПИ.

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

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

    Сравнение эффективности работы бригад программистов по целям в решении задач

    Оценки (1 — наилучшая, 5 — наихудшая)

    бри­гады

    Цель, поставленная при

    решении задачи

    по

    затра­там

    труда

    по длине программы

    по объему использованной

    памяти

    по чи­табельности

    программ

    по четкости выходных данных

    суммар­ный

    вес

    1. Оптимизировать затраты

    труда 1 4 4 5 3 17

    2. Оптимизировать длину

    программы 2 1 2 3 5 3

    3. Оптимизировать объем

    требуемой памяти 5 2 1 4 4 6

    4. Получить читабельную

    (ясную) программу 4 3 3 2 2 14

    5. Добиться четкости

    выходных данных 3 5 5 1 1 15

    ______________________________________________________________________________________________________

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

    2. Коллективный характер разработки программного обеспечения. Бригада главного программиста

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

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

    Пусть объем проектируемого ПИ оценивается в 50000 строк (исходных команд), а производительность одного программиста примем равной 5000 строк в год. Пусть, далее, срок разработки данного ПИ ограничен двумя годами. Тогда, очевидно, для создания такого ПИ достаточно пяти программистов. Однако, поскольку составные части ПИ (модули) взаимосвязаны, то при их создании программисты должны взаимодействовать между собой. Пусть время, затраченное на взаимодействие с каждым коллегой, обходится каждому программисту в 250 строк/год, тогда в соответствии со схемой их взаимодействия, представлен­ной на рис. 1 а, производительность каждого программиста составляет только 4000 строк/год. Таким образом, для реализации проекта в 5000 строк в течение двух лет необходимо уже не пять, а восемь программистов, производительность каждого при этом составляет только 3250 строк/год. Так как для успешной работы такой группы необходим руководитель, то окончательно имеем группу из девяти человек, производительность каждого при этом будет составлять всего 3000 строк/год .

    Хотя приведенный пример и носит иллюстративный характер, так как производительность труда программистов, оцениваемая числом строк в единицу времени, по данным Дж. Фокса может различаться на 2 порядка, он, тем не менее, отражает суть проблемы, называемой «коммуникационным взрывом». В настоя­щее время существуют методы ограничения влияния коммуника­ционного взрыва и повышения производительности труда про­граммистов. Одним из таких методов является организация работ в группе по принципу хирургической бригады — бригады главного программиста. Как правило, главный программист — это высоко­квалифицированный специалист с хорошими организаторскими способностями. Его производительность может в несколько раз превышать производительность остальных членов бригады. Воз­главляя бригаду, он одновременно является и техническим руководителем проекта. В состав бригады могут входить также администратор, старший программист и библиотекарь. Поддерживая тесную связь с главным программистом, стар­ший программист разрабатывает наиболее сложные компоненты ПИ, осуществляя при этом взаимодействие с остальными членами бригады.

    На рис. 1в приведена схема взаимодействия в бригаде главного программиста, состоящей из пяти человек. Так как и главный программист, и старший программист являются высококвалифицированными специалистами, производительность которых может значительно превышать 5000 строк/год, средняя производительность в такой бригаде также может превышать 5000 строк/год по сравнению с 4000 в предыдущем примере. Включение в бригаду администратора, занимающегося распреде­лением времени, размещением исполнителей и другими админи­стративно-хозяйственными вопросами, не является обязательными и справедливо только при разработке больших программных проектов.

    Рис 1. Разработка программного обеспечения группой программистов: а— из 5 человек, б — из 9 человек, в — бригадой главного программис­та из 5 человек

    Что касается оптимальной численности бригады главного программиста, то большинство специалистов единодушны в том, что число членов бригады должно быть равным 7±2.

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

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

    1. Руководство определением требований.

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

    3. Непосредственно проектирование возглавляется главным архитектором проекта и его службой. Главный архитектор не заменяет и не подменяет руководителя проекта. Его функции ограничиваются научно-технической стороной разработки, т. е. наиболее творческой составляющей создания ПИ.

    4.Отдел разработки ПО состоит из описанных выше бригад главного программиста, которые в случае необходимости могут группироваться по отдельным подсистемам или иным компонентам ПИ. Руководитель отдела обеспечивает оперативное управление всеми этими бригадами программистов.

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

    6. Группа или отдел качества (надежности) создается на самом раннем этапе разработки ПИ. Она является самостоятель­ным подразделением, чем обеспечивается большая объективность тестирования и оценки качества.

    Организационная структура разработки программного обес­печения

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

    3. Психологические факторы при формировании программистских коллективов

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

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

    • в 52% случаев — неправильные действия руководителя;

    • в 33% случаев — психологическая несовместимость сотруд­ников;

    • в 15% случаев — профессиональная некомпетентность и другие недостатки подбора и расстановки кадров.

    Если же учесть, что под неправильными действиями по отношению к подчиненным понимаются невнимание к сотрудни­кам, неуместные публичные сообщения об их недостатках и промахах и т. д., в результате чего 40—50% подчиненных в течение 2—3 месяцев работают хуже; что не использование возможности публично заслуженно поощрить работника в 87% случаев приводит к тому, что этот работник не улучшает свою работу, т. е. не полностью реализуются его потенциальные возможности; а также учесть, что при подборе и расстановке кадров психологические аспекты также играют важную роль, то становится понятным, что примерно в 90% случаев причиной конфликтных ситуаций, существенно снижающих эффективность работы, является неучёт психологических факторов.

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

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

    Формирование производственной группы — процесс сложный. Основу его составляет анализ деятельности, которой будет заниматься группа. С этой целью изучается весь производ­ственный цикл на предприятии, определяется место рассматривае­мой группы в технологическом процессе, ее основные цели и задачи. Всю эту информацию можно получить благодаря изучению основной документации предприятия и её плановых заданий.

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

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

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

    | Данные по психофизиологической совместимости можно получить с помощью анкетных методик. Одной из таких методик, например, является «опросник темперамента» Яна Стрелляу, предназначенный для изучения свойств нервной системы на уровне деятельности. Определив тип темперамента человека, можно судить о его совместимости с людьми, характеризуемыми другими типами: «Холерики достаточно коммуникабельны, хотя и уступают в этом сангвиникам. Обычно стараются играть роль лидеров. Плохо уживаются с меланхоликами и другими холерика­ми. Меланхолики склонны к уединению, а в реакциях общения напоминают формы коммуникативного поведения флегматиков, не стремятся к лидерству, более легко уживаются с флегматиками и сангвиниками»

    К анкетным методикам также относится «личностный опрос­ник» Г. Айзенка , который определяет такие факторы личности, как интроверсия, экстраверсия и нейротизм. Опросник предполагает существование взаимосвязи между индивидуально-типологическими особенностями высшей нервной деятельности и свойствами личности, хотя эта зависимость и не является абсолютной. Вводя в опросник шкалу нейротизма, автор предло­жил разделение типов не только по экстраверсии — интроверсии, но и стабильности. Шкала стабильности получила название нейротизм. «Нейротизм — понятие, близкое к эмоциональной лабильности, неуравновешенности, тревожности. Чем ниже индекс нейротизма, тем личность более эмоционально устойчива, менее тревожна».

    Для экстраверсии, определяемой с помощью методики, ха­рактерно общительное, активное, оптимистическое, самоуверенное поведение; для интроверсии — поведение необщительное, пассив­ное, вдумчивое, спокойное. Человеку с высшим показателем неустойчивости свойственно поведение под влиянием настрое­ния — вспыльчивое, в то время как устойчивым индивидам — спокойное, беззаботное, надежное, непринужденное.

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

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

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

    • адекватное распределение функций в группе в соответствии с индивидуальными особенностями и профессиональной специали­зацией;

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

    • координирование совместной деятельности;

    • решение проблемы совместной деятельности.

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

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

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

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

    1. анализ деятельности;

    2. формирование организационной структуры;

    3. стабилизация отношений.

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

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

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

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

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

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

    4. Коллективная разработка программ - «Коллективная игра»

    (По материалам статей Алистэра Коуберна)

    Что же такое разработка программного обеспечения? Что включает в себя это понятие, и к какому виду деятельности его можно отнести? Каким правилам нужно следовать, чтобы проект окончился успешно? Почему при равных стартовых условиях проект А с треском проваливается, а проект Б приносит деньги и славу своим разработчикам? Каждый, кто работает в области программирования и занимается управлением и постановкой процесса, рано или поздно начинает задавать себе эти вопросы. Ответов на них нет. Вернее, их множество, что, по сути, то же самое. И единственно возможным вариантом становится сочетание собственного опыта и учебы на чужих открытиях и ошибках.

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

    Основные положения, которые Алистэр Коуберн защищает в каждой своей работе, касаются человекоцентричности процесса разработки ПО. Главное в любом проекте - люди, они решают все. Именно они могут вытащить проект из глубокого кризиса, но, с другой стороны, именно они создают проблемы с дисциплиной, не выполняют правила и предписания. Следовательно, заключает Коуберн, надо определить, какой подход будет лучше всего использовать сильные стороны человеческого характера, подавляя и регулируя слабые. За последние семь лет Алистэр написал несколько статей и книг на эту тему. Некоторые из них вошли в уже классический набор трудов по так нызываемым "гибким методологиям". Одна из его излюбленных тем, которую он поднимает во многих своих работах - модель разработки ПО как коллективной игры, направленной на достижение определенного результата (создание программного обеспечения) при неких заданных условиях (ограниченность в человеческих, временных и финансовых ресурсах). Эта модель позволяет по-новому посмотреть на отрасль, работая в которой мы привыкли оперировать исключительно техническими и инженерными метафорами. Проблемы успешности и неуспешности проекта приобретают другую окраску, позволяют нам находить нестандартные выходы из сложных ситуаций.

    Инженерная модель программирования не оправдывает себя

    Разработка программного обеспечения не всегда относилась к инженерным наукам. Таковой ее предложили считать в 1968 году, чтобы спровоцировать людей к участию в работе новой отрасли . Провокация оказалась очень удачной. К сожалению, этого нельзя сказать о полезности такой модели для тех, кто в ней работает. Даже после 35-летнего опыта использования инженерной модели процент успешных проектов в сфере производства ПО продолжает оставаться низким. Мы не можем определить взаимосвязь между успехом проекта и "чистотой" процесса его разработки. Наконец, мы видим, что эта модель не помогает профессионалам решать практические вопросы, находить выход из сложных ситуаций в реальных проектах. Некоторые могут возразить, что "инженерная" модель не работает, потому что мы недостаточно хорошо ей следуем. Однако во время "разбора полетов" нередко выясняется, что проекты, в которых разработчики не следовали никакому четкому процессу, оканчивались успешно, в то время как строгие процессы далеко не всегда приводили проект к благополучному завершению. Инженерная модель программирования не проходит один жизненно важный тест, а именно, не предлагает правильных решений в сложных ситуациях. Если мы посоветуем руководителю проекта или программисту "делать больше программного инжиниринга", смогут ли они хотя бы

    • правильно интерпретировать эту фразу?

    • понять, что именно подразумевается под словами программный инжиниринг?

    • почерпнуть из этих слов дельный совет, который поможет им при работе над проектом?

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

    Таким образом, нашей отрасли надо найти другую модель, которая могла бы

    • Объяснить, почему одни проекты удаются, а другие - нет;

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

    • Подсказывать участникам проекта правильное решение проблем, возникающих по ходу проекта.

    Хотя словари определяют игру как "развлечение", значение этого термина за последнее столетие существенно изменилось. Многим руководителям претит сама идея того, что производство программного обеспечения можно считать игрой: Естественно, руководителям не хочется, чтобы люди проводили рабочее время в развлечениях. Причина проста - производство программного обеспечения является, с экономической точки зрения, игрой, крайне ограниченной в ресурсах. Термин "игра" довольно часто подразумевает некий элемент развлечения, и это прекрасно, когда люди рассматривают работу над проектом как развлечение (это называется "командным" или "рабочим духом"). Однако сейчас термин "игра" все чаще лишается своей легкой, фривольной и непродуктивной составляющей. В современной науке в категорию игр попадает такое количество разнообразных видов деятельности, что иногда трудно найти в них что-то общее. Обязательным условием игры является следование правилам. Как только участники игры перестают следовать ее правилам, игра прекращается (таким образом, игрой можно назвать только добровольную деятельность, при условии, что у участников всегда есть возможность прекратить ее и действовать другим образом).

    Модель коллективной игры Виды игр, коллективные игры, последовательность игр

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

    1. Оно (производство ПО) может быть конечным или бесконечным.

    2. Оно может быть основано на конкуренции или на взаимопомощи.

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

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

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

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

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

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

    Таким образом, программисты ставят перед собой две цели:

    1. Поставить заказчику систему;

    2. Создать основу для следующей игры.

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

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

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

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

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

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

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

    Кооперация и коммуникация

    В сущности, вся разработка программного обеспечения состоит в том, что люди что-то изобретают в процессе общения:

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

    • Они вырабатывают решение, правильность которого не гарантирована, и которое может изменяться в процессе работы;

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

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

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

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

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

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

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

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

    Можно легко вообразить, что "объяснить текущий дизайн программного продукта" не что иное, как запечатлеть существующие проектные решения в каком-то графическом формате (например, Unified Modeling Language, UML). Но передача информации - далеко не механическое занятие Общение больше похоже на "прикосновение к общим переживаниям и опыту" . При этом конечно, общение будет принимать те формы, которые подсказывает людям их опыт. Разработчики, которые работали раньше над другими проектами, будут обращаться к прошлым проектным решениями и ситуациям. Те, кто раньше вместе не работал, но обладают взаимопониманием, будут более подробно описывать свое понимание алгоритмов и шаблонов проектирования. Третья группа будет вынуждена использоваться простую буквенную документацию - UML диаграммы или комментарии в программном коде.

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

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

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

    Интересно, что такая изменчивая и непредсказуемая игра, какой является создание программного обеспечения, допускает и прямо противоположные техники работы. Один из примеров приведен в статье Cone of Silence (можно перевести как "Тихая гавань" - в этой статье описана стратегия преднамеренного затруднения общения между некоторыми членами команды разработчиков).

    Изобретательность

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

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

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

    Реквизит и маркеры для игр

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

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

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

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

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

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

    Вместо заключения

    Итак, подведем итоги. Мы познакомились с критикой привычной "инженерной" модели создания программного обеспечения и перечислили основные ее недостатки:

    1. Она не описывает необходимые составляющие успешного проекта, например, талант и навыки, единство и сплоченность команды, межличностную коммуникацию [Boehm].

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

    3. Несмотря на 35-летний опыт использования термин "software engineering" люди до сих пор не могут однозначно его интерпретировать, что приводит к прямо противоположным рекомендациям относительно процесса работы.

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

    После этого мы рассмотрели новую модель, которую Алистэр Коуберн предлагает в качестве альтернативы - модель коллективной игры:

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

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

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

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

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

    6. Первая и вторая цель игры претендуют на одни и те же ресурсы и конкурируют между собой.

    Контрольные вопросы

    1. Чем продиктован коллективный характер разработки ПО?

    2. Каковы функции главного программиста в бригаде программистов?

    3. Чем бригада главного программиста похожа на бригаду хирургов?

    4. Какова структура бригады главного программиста?

    5. Поясните главные компоненты организационной структуры разработки большого программного проекта?

    6. Какова особенность организации работы программистов в ХР-процессе?

    7. Почему психологические факторы играют особую роль при формировании программистских коллективов?

    8. Каким образом психологические факторы участвуют в конкретных моделях конструирования, например, в ХР-процессе?

    9. В каких случаях, при создании каких проектов инженерная модель программирования не оправдывает себя? Почему?

    10. Каким образом модель «коллективной игры» используется в программировании?

    11. В каких известных вам моделях конструирования присутствуют элементы коллективной игры?

    12. Без каких концепций, свойств, реквизитов и маркеров коллективная игра невозможна?

    Глава 20 Стандартизация по. Экономические аспекты создания по

    1.Краткая характеристика программных средств как объекта разработки и стандартизации

    В стоимостном исчислении ПО и информационные услуги составляют более половины объёма рынка всех продуктов информационных технологий. На российском рынке программных средств (ПС) заметно определённое завоевание отечественными производителями таких направлений, как бухгалтерские системы, системы распознавания текстов, различные корпоративные и управленческие программы, а также системы распределённой обработки данных. Характеризуя общие тенденции в области информатизации, следует отметить высокую динамичность изменений технических и потребительских свойств ИТ и средств их реализации. В настоящее время срок смены поколений аппаратных и программных средств составляет 3 – 4 года, что предъявляет высокие требования к срокам и качеству их разработки, особенно ПС. Опыт организации работ на всех фазах жизненного цикла ПС показывает, что это сложная, трудоёмкая и длительная работа, требующая высокой квалификации специалистов и новых подходов к проектированию на основе широкого использования методов программной индустрии, стандартизации и сертификации.

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

    Технические особенности разработки программных средств

    Рост объёмов и сложности ПС и баз данных (БД) информационных систем (ИС), а также требований к их качеству привели к созданию программной индустрии с большими коллективами специалистов и применению технологий автоматизированного проектирования и сопровождения, базирующихся на стандартах и нормативных документах. Комплекс таких документов должен регламентировать технологические процессы и объекты проектирования комплексов программ на всех этапах их жизненного цикла (ЖЦ). Структура ЖЦ ПС базируется на трёх группах процессов:

    1. основные (приобретение, поставка, разработка, эксплуатация, сопровождение);

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

    3. организационные (управление проектами, создание инфраструктуры проекта, определение, оценка и совершенствование ЖЦ ПС, обучение).

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

    Экономические особенности разработки программных средств

    Высокая стоимость и большие ресурсы, используемые при создании сложных ПС и БД, привели к необходимости детального технико-экономического анализа и обоснования проектов ИС до начала их осуществления. Создание ПС и БД не завершается после первичных испытаний и сертификации 1-й версии, и длительное время они развиваются и модифицируются в серию версий в ходе сопровождения разработки и эксплуатации ПС. Программы и данные в ИС являются наиболее гибкими компонентами, подверженными изменению в течение всего их жизненного цикла. Поэтому они должны контролироваться и упорядочиваться участниками проекта. Для координации их действий применяют специальные методы, методики и средства автоматизации конфигурационного управления. Они позволяют на основе отслеживания динамики изменения ПС и БД представить специалистам и руководителям состояние проекта и его компонентов в любой момент времени и не допускать хаоса при модификации программ и данных. Процессы документирования и конфигурационного управления играют стабилизирующую роль во всём ЖЦ ПС. Поэтому они располагаются на первых позициях в стандартах и обеспечивают отражение состояния и динамики проектов. Их строгое выполнение определяет технико-экономические показатели (ТЭП) проекта, его качество, длительность применения и конкурентоспособность ПС и ИС в целом. Освоение основ экономики создания и применения ИС и их компонентов позволяет рационализировать капиталовложения в средства автоматизации, прогнозировать затраты и длительность разработки систем, научно планировать создание крупных ПС и БД. Так как их разработка требует больших затрат и происходит в условиях ограниченных ресурсов, надо осуществлять баланс между достигаемым их качеством и ресурсами для их реализации, поддерживая его на всём ЖЦ. При этом особенно остро стоит задача борьбы с ростом ошибок в сложных ПС и БД, угрожающим безопасности и надёжности ИС . Для их сокращения применяют типизацию проектов ИС в определённых проблемно ориентированных областях, сборочное программирование, процессы, средства и стандарты управления конфигурацией и качеством ПС и БД.

    Вопросы оценки трудоёмкости разработки ПС в свете требований стандартизации

    Современный подход к оценке трудоёмкости разработки ПС состоит в учёте особенностей ЖЦ ПС на различных этапах и влияния технологических факторов не только на трудозатраты, но и на уровень качества, надёжность и экономические показатели ПС.

    Разработка ПС является важнейшим элементом основных процессов ЖЦ и состоит из следующих работ и задач, сгруппированных в 5 групп (этапов) :

    1. Анализ разработки:

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

    б) анализ требований:

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

    2. Проектирование:

    а) проектирование программной архитектуры (применительно к каждому программному объекту):

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

    • оформление архитектуры программного объекта;

    • разработка и документальное оформление общего (эскизного) проекта внешних интерфейсов и интерфейсов между компонентами объектов;

    • разработка и документальное оформление общего (эскизного) проекта базы данных;

    • разработка и документальное оформление предварительной версии документации пользователя;

    • разработка и документальное оформление предварительных требований к тестированию программного объекта, разработка графика сборки программного продукта;

    • оценка и документальное оформление архитектуры программного объекта и эскизных проектов.

    б) техническое проектирование ПС:

    • разработка и документальное оформление технического проекта для каждого программного объекта. Компоненты программного объекта должны быть уточнены на уровне программных модулей, которые можно программировать, компилировать и тестировать независимо. Распределение технических требований к компонентам между программными модулями;

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

    • разработка технического проекта базы данных;

    • уточнение документации пользователя;

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

    • оценка технического проекта и требований к тестированию, документальное оформление оценки.

    3. Программирование:

    а) программирование и тестирование компонентов ПС:

    • разработка и документальное оформление каждого программного модуля и базы данных;

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

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

    • уточнение документации пользователя;

    • уточнение программы сборки ПС;

    • оценка запрограммированных элементов программного объекта и документальное оформление оценки;

    б) сборка ПС:

    • разработка плана сборки и тестирования, документальное оформление плана;

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

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

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

    4. Квалификационные испытания (тестирование) ПС:

    • проведение квалификационных испытаний на соответствие квалификационным требованиям к программному объекту;

    • уточнение документации пользователя (при необходимости);

    • проведение аудиторской проверки и документальное оформление результатов;

    • доработка программного продукта по результатам аудиторской проверки (при необходимости);

    • подготовка ПС к вводу в действие.

    5. Внедрение ПС:

    а) ввод в действие ПС:

    • разработка и документальное оформление плана ввода в действие программного продукта в среде эксплуатации, определенной в договоре;

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

    б) обеспечение приемки ПС:

    • обеспечение проведения заказчиком оценки готовности к приемке и приемочным испытаниям; документальное оформление результатов оценки готовности;

    • поставка программного продукта заказчику;

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

    Вспомогательные процессы ЖЦ

    1) Документирование – процесс формализованного описания информации, созданной в процессе или работе жизненного цикла. Данный процесс состоит из набора работ, при помощи которых планируют, проектируют, разрабатывают, выпускают, редактируют, распространяют и

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

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

    Организационные процессы ЖЦ

    1) Управление – процесс, состоящий из общих работ и задач, которые могут быть использованы любой стороной, управляющей соответствующим процессом. Администратор отвечает за управление продуктом, проектом, работами и задачами соответствующего процесса, который состоит из подготовки и определения области управления; планирования; выполнения и контроля; проверки и оценки; завершения.

    2) Создание инфраструктуры – процесс установления и обеспечения инфраструктуры, необходимой для любого другого процесса. Инфраструктура может содержать технические и программные средства, инструментальные средства, методики, стандарты и условия для разработки. Этот процесс состоит из подготовки процесса; создания инфраструктуры; сопровождения инфраструктуры.

    3) Усовершенствование – процесс установления, оценки, измерения, контроля и улучшения любого процесса жизненного цикла ПС. Процесс состоит из создания процесса; оценки процесса; усовершенствования процесса.

    4) Обучение – процесс обеспечения первоначального и продолженного обучения персонала. Должно быть запланировано и заранее выполнено обучение персонала с целью готовности его к работам по разработке программного проекта. Данный процесс состоит из подготовки процесса; разработки учебных материалов; реализация плана обучения. Методика оценки трудоёмкости должна охватывать все указанные выше работы процесса разработки ПС, а также вспомогательные и организационные процессы.

    2. Основные понятия и положения технологии разработки программных средств

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

    1) проблемы рационального структурного построения ПС, включающие:

    • оптимизацию структуры ПС по критерию максимального использования ресурсов ЭВМ;

    • контроль вычислительного процесса и обеспечение надёжности ПС;

    • обеспечение простой корректировки ПС и др.;

    2) Проблемы технологии разработки пс, включающие:

    • разработку моделей алгоритмов и др. компонентов ИС;

    • автоматизацию программирования на основе унификации типовых компонент программ;

    • обеспечение отладки и испытаний программ;

    • автоматизацию изготовления документации и др.;

    3) проблемы стандартизации и унификации ПС, включающие:

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

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

    • стандартизацию методов и требований к обеспечению и измерению качества ПС;

    • стандартизацию языков программирования.

    По длительности ЖЦ ПС можно разделить на 2 класса : а) с малым, б) большим временем жизни.

    ПС с малым временем ЖЦ (до 3 лет) и объёмом 1 – 10 тысяч команд разрабатываются обычно одним специалистом.

    ПС с большим временем ЖЦ (10 – 20 лет, из которых 70 – 90 % приходится на эксплуатацию и сопровождение), с объёмом 10 – 1000 тысяч команд разрабатываются большими коллективами специалистов и создаются на основе промышленного регламентированного проектирования. ЖЦ таких программ включает в себя этапы: системный анализ, проектирование, эксплуатацию, сопровождение. Наиболее специфическим, трудно формализуемым и тесно связанным с функциональным назначением является этап системного анализа, на котором формируются назначение и основные показатели качества ПС.

    Этапы проектирования, эксплуатации и сопровождения сильно различаются целями, задачами, методами и средствами. Процесс эксплуатации идёт параллельно и независимо от этапа сопровождения и сводится к исполнению программ на ЭВМ и обеспечению достоверности и надёжности результатов.

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

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

    Технологическая поддержка является детализацией документов методической поддержки, регламентирующей конкретную технологию обеспечения ЖЦ программ. Эти документы определяют допустимую трудоёмкость и длительность каждого этапа и обеспечивают нужное качество при допустимых затратах ресурсов.

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

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

    Важное значение имеют результаты статического анализа программных средств. Статический анализ (СА) – это процесс анализа исходного текста программы без её выполнения на ЭВМ. СА программ проводится:

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

    2. подготовки исходных данных для проведения динамического анализа ПС и разработки плана тестирования ПС;

    3. оценки конструктивных характеристик программы, степени простоты модификации и сопровождения программы;

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

    5. оценки текстовой сложности программы, затрат на ее разработку и освоение;

    6. экспертизы идентичности программ при установлении авторства и разрешении правовых споров;

    7. определения количественных характеристик при оценке уровня качества программы.

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

    • модульная структура ПС;

    • логическая структура отдельного программного модуля;

    • характеристика текста программы.

    Модульная структура анализируемого ПС представляется в виде графа вызовов; списка путей вызовов; матрицы вызовов и достижимости; точек вызовов; метрик иерархии вызовов.

    Логическая структура отдельного программного модуля представляется в виде графа управления; путей тестирования; метрик структуры управления.

    Характеристики текста программ включают в себя: статистические данные о комментированности программы и текстовые метрики Холстеда.

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

    Иерархическая сложность: I = N / L, где N – количество вершин в графе вызовов модулей; L – количество уровней. Иерархическая сложность характеризует среднюю ширину уровня в графе вызовов, т.е. количество проектных решений, принимаемых на отдельном шаге разработки программы.

    Структурная сложность: S = D / N, где D – количество ребер в графе вызовов модулей; N – количество вершин. Тестируемость – это свойство ПС, заключающееся в их приспособленности к эффективному применению контрольных тестов, зависящей от степени разветвления вычислительного процесса и доступности модулей.

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

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

    3. Критерии оценки технологий проектирования программных средств

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

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

    Различают функциональные и конструктивные критерии качества ПС.

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

    Вторые критерии оценивают сложность программ, надёжность функционирования, ресурсы ЭВМ, корректность программ и др.

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

    Для управления качеством необходима формализация технологии проектирования, а также независимое измерение, контроль и анализ критериев качества ПС и влияющих на них факторов. Управление качеством ПС включает:

    1. анализ системных требований к ПС и ранжирование критериев качества,

    2. разработку методик и стандартов контроля выполнения правил модульно-иерархического построения ПС,

    3. создание методов и технологии поэтапного контроля выполнения заданных требований к качеству ПС,

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

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

    Почти всегда критерии качества связаны с экономическим эффектом от применения ПС. Его можно выразить доходом, повышением производительности труда или прибыли, снижением затрат, энергопотребления и др. экономическими показателями. Во многих случаях наиболее просто и обобщённо экономический эффект можно описать доходом Э от использования ПС в течение ЖЦ продолжительностью t: Э = Эид – C сум,

    где Эид – идеальная эффективность применения программ;

    C сум – суммарные потери и затраты, снижающие предельный доход.

    Это снижение происходит вследствие затрат на разработку Cр, сопровождение Cс, эксплуатацию Сэ и из-за потерь в результате недостаточной надёжности Сн.

    Тогда Э = Эид – Ср – Сс – Сэ – Сн.

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

    Основные факторы, влияющие на трудоёмкость разработки ПС

    Качество и эффективность технологии определяется прежде всего затратами на разработку:

    Ср = С1р + С2р + С3р + С4р + С5р,

    где С1р – затраты, связанные с непосредственной разработкой ПС;

    С2р – затраты на изготовление опытного образца (5 – 10 %), часто не учитываемые из-за малости;

    С3р – затраты на программные средства автоматизации технологии;

    С4р – затраты на аппаратные средства автоматизации технологии (машинное время работы ЭВМ);

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

    В результате можно считать, что для практических целей проведения анализа можно пользоваться формулой

    Cр = С1р + С3р + С4р.

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

    Распределение затрат по этапам разработки

    По опыту эксплуатации трудоёмкость отдельных этапов разработки различается в 2 – 4 раза, а загрузка отдельных категорий специалистов на них – в 3 – 5 раз. Это надо учитывать при планировании и организации проектирования ПС, а также при прогнозировании затрат на непосредственную разработку программ. Так же неравномерно в зависимости от этапов изменяется и потребность в машинном времени С4р, причём для разных ЭВМ (моделирующих, технологических, реализующих) эта потребность находится в широком диапазоне и является максимальной для этапа динамической отладки. Такие оценки затрат машинного времени позволяют рационально планировать и прогнозировать необходимую аппаратную оснащённость разработок по этапам и в целом на весь ЖЦ. Упорядоченный подход к организации проектирования сложных ПС с учётом вышеизложенного позволяет создавать ПС с высоким качеством и допустимыми затратами, если использовать современные технологии, методы и системы автоматизации проектирования, выбирая их на основе системного и технико-экономического анализа достигаемого эффекта и ресурсов на весь ЖЦ.

    4.Общие сведения о сертификации информационных систем и программных средств

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

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

    С технической точки зрения, качество – это совокупность свойств продукции, обуславливающих её способность удовлетворять определённые потребности в соответствии с её назначением. Весь объём признаков и характеристик программной продукции, относящийся к её способности удовлетворять потребностям пользователей ИС, определяет качество программного обеспечения (ПО).

    Такие признаки и характеристики определяют свойства ПО, по которым его качество описывается и оценивается. К ним относятся:

    1. функциональные возможности,

    2. надёжность,

    3. практичность,

    4. эффективность,

    5. сопровождаемость,

    6. мобильность.

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

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

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

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

    Кроме этого сертифицированная продукция маркируется знаком соответствия, зарегистрированным в установленном порядке по правилам соответствующей системы сертификации, относящейся к данной группе продукции.

    Орган, возглавляющий систему сертификации однородной продукции, называется центральным органом системы сертификации или центром по сертификации. В его подчинении находятся органы, проводящие сертификацию соответствия, и испытательные лаборатории, проводящие испытания определённой продукции. При объединении этих функций в одном юридическом лице используется термин «сертификационный центр». Эти органы подвергаются периодически аккредитации – процедуре официального признания (соответствующим уполномоченным органом) компетентности и возможности выполнения конкретных работ в заданной области.

    Взаимоотношения между участниками – разработчиками (продавцами), пользователями (покупателями) и органами сертификации и аккредитации, а также их права и обязанности регулируются Законом № 184-ФЗ от 27.12.02 «О техническом регулировании». Ниже рассматриваются отдельные главы, статьи и пункты данного закона, дающие наиболее полное представление об устанавливаемых этим законом нововведениях.

    Особенности сертификации программного обеспечения

    Рекомендованные выше шесть характеристик качества ПО представляют основу для оценки и сертификации программ различных классов. При этом необходимо предварительно решить вопросы установления метрик, важности каждой характеристики, уровней ранжирования, критериев оценки и разработки моделей оценивания применительно к конкретным условиям применения ПО в определённой организации. Важность каждой характеристики качества меняется в зависимости от класса ПО, а также от различных точек зрения на их важность со стороны пользователя, разработчика и руководителя. В соответствии с этим разработчиками могут использоваться различные метрики для одних и тех же характеристик ПО, потому что одни и те же метрики не применимы для всех фаз ЖЦ ПО. Так, если пользователя интересует только качество конечной продукции, то разработчики заинтересованы и в качестве промежуточных результатов на всех фазах ЖЦ, так как без этого конечный результат может быть не оптимальным или вовсе не отвечать заданным требованиям.

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

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

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

    Таблица 1 - Характеристики свойств ПО

    Наименование свойств

    Коэффициент важности

    Ранг свойства

    1

    Функциональные возможности

    0,35

    1

    2

    Надёжность

    0,25

    2

    3

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

    0,20

    3

    4

    Эффективность

    0,15

    4

    5

    Мобильность

    0,03

    5

    6

    Практичность

    0,02

    6

    С учётом полученных данных применительно к рассмотренному классу ПО можно выделить:

    1. основные свойства – функциональные возможности, надёжность, сопровождаемость, эффективность;

    2. дополнительные свойства – мобильность, практичность.

    Большинство из приведенных свойств присуще ПО и других классов. Однако степень их важности будет отличаться, и не исключено выявление новых свойств. Так, для ИС военного назначения наиболее важным свойством может быть надёжность, для систем управления технологическими процессами – эффективность, а для ПО универсальных ИС широкого применения – мобильность и функциональные возможности.

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

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

    1) объективные (количественные), характеризуемые реально измеряемыми физическими величинами;

    2) субъективные (качественные), характеризуемые, как правило, фактом практического наличия или отсутствия того или иного свойства у ПО и оцениваемые соответственно 1 или 0.

    Использование качественных показателей хотя и вносит элемент субъективизма в оценку ПО, но позволяет с определённой достоверностью, зависящей от опыта и квалификации разработчика, заказчика или пользователя, учесть степень влияния таких свойств на качество всей ИС.

    Степень субъективизма может быть значительно снижена при использовании метода групповых экспертных оценок. Поскольку стандартом определено, что предложенные в нём характеристики – не истина в последней инстанции, а только образуют основу для дальнейшего уточнения и описания качества ПО, допустимо расширять состав соответствующих свойств и номенклатуры показателей их оценки, устанавливать свои собственные модели процесса оценивания и методы формирования и проверки метрик, связанных с этими показателями, для охвата различных областей применения и стадий ЖЦ.

    С учётом этого в качестве примера совокупности показателей качества ПО для одной из ИС может служить следующая совокупность:

    1) Количественные пк:

    а) функциональные ПК решения задач, определяемые назначением ИС, – среднее время решения задачи, пропускная способность, время ответа и другие;

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

    в) среднее время восстановления после программного отказа;

    г) коэффициент загрузки оперативной памяти;

    д) коэффициент загрузки производительности;

    е) ёмкость программ;

    ж) время изменения логической структуры базы данных и выходных форм;

    2) Качественные пк:

    а) информативность текстов;

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

    в) защищённость от НСД;

    г) степень «дружественности» пользовательского интерфейса и ряд других.

    Модель процесса оценивания качества и сертификации ПО должна отражать основные этапы, требуемые для оценивания по характеристикам, рекомендуемым стандартом, в соответствии с которым процесс состоит из трёх стадий:

    1) установление (определение) требований к качеству,

    2) подготовка к оцениванию,

    3) процедура оценивания.

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

    Подготовка к оцениванию включает в себя:

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

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

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

    Процедура оценивания включает:

    а) измерение, результатом которого является получение измеренного

    признака свойств в масштабе выбранной метрики;

    б) ранжирование, устанавливающее отнесение измеренного признака

    к тому или иному уровню;

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

    5. Методы оценки технико-экономических показателей программных средств на различных этапах их жизненного цикла

    Порядок и методология проведения статического анализа программных средств

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

    Независимо от способа проведения СА (автоматизированного или ручного) следует учитывать особенности СА на различных этапах.

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

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

    2) Программирование

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

    3) Тестирование и отладка

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

    Методика оценки трудоёмкости разработки программных средств

    Трудоемкость разработки ПС рассчитывается с учетом объективных и субъективных факторов:

    • количество строк исходного текста, написанных разработчиком (без учета текста, сгенерированного автоматически, использованного из библиотек и т.д.);

    • сложность разрабатываемого ПС;

    • степень новизны разрабатываемого ПС;

    • уровень требований к показателям качества ПС;

    • условия и средства разработки ПС;

    • опыт и квалификация разработчика.

    Методика оценки трудоёмкости сопровождения программных средств

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

    Методика охватывает работы процесса сопровождения, а также вспомогательные и организационные процессы, относящиеся к сопровождению в соответствии с ГОСТ Р ИСО/МЭК 12207-99. Процесс сопровождения состоит из работ : подготовка процесса; анализ проблем и изменений; внесение изменений; проверка и приемка при сопровождении; перенос; снятие с эксплуатации.

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

    • объем ПС в тыс. строк исходного текста (как написанного разработчиком вручную, так и сгенерированного автоматически);

    • объем документации в тыс. строк (только эксплуатационная документация и документация сопровождения);

    • сложность программ;

    • язык программирования и другие средства разработки ПС;

    • наличие аналогов ПС;

    • степень участия службы сопровождения в разработке ПС;

    • характер поставки ПС;

    • характер внедрения ПС;

    • объем доработок (количество строк исходного текста).

    Методика прогнозирования стоимостных показателей информационных систем

    Различают методы прогнозирования:

    1. сопоставительно-аналоговый метод;

    2. метод экспертных оценок;

    3. метод статистического прогнозирования;

    4. нормативно-калькуляционный и

    5. сметно-калькуляционный методы.

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

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

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

    ГОСТ устанавливает три метода оценки уровня качества любой продукции, в том числе и информационных систем :

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

    2. комплексный (сопоставление оцениваемой и базовой ИС по одному обобщённому показателю),

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

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

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

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

    Обобщённый показатель может быть выражен:

    1. главным показателем, отражающим основное назначение, например, производительностью;

    2. интегральным показателем качества, например, экономической эффективностью;

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

    Применяют средние взвешенные арифметические и геометрические показатели качества.

    Контрольные вопросы

    1. На какие группы делятся процессы жизненного цикла программ?

    2. Что включает статический анализ программ?

    3. Что понимают под функциональными критериями качества ПО?

    4. Что понимают под конструктивными критериями качества ПО?

    5. Укажите основные факторы, влияющие на трудоемкость разработки ПО?

    6. Какие основные характеристики качества вы можете назвать?

    7. Какие факторы учитываются при оценке трудоемкости разработки ПО?

    8. Какие факторы учитываются при оценке трудоемкости сопровождения ПО?

    9. Перечислите известные вам методики прогнозирования стоимостных показателей ПО?

    10. В чем заключается особенность сертификации ПО?

    11. Перечислите количественные показатели качества ПО?

    12. Перечислите качественные показатели качества ПО?

    Список литературы

    1. Орлов С. Технологии разработки программного обеспечения. Учебное пособие. 2-е изд./С. Орлов. – СПб.: Питер, 2003. - 480 с.

    2. Рудаков А.В. Технология разработки программных продуктов : учеб. Пособие для студ.сред.проф.образования / А.В. Рудаков. – 3-е изд., стер. – М. : издательский центр «Академия», 2007. – 208 с.

    3. Вендров А.М. Проектирование программного обеспечения экономических информационных систем: Учебник. – М.: Финансы и статистика, 2002. – 352 с.