|
|
|
содержание .. 2 3 4 5 ..
Основные этапы жизненного цикла ПО (лекция по программной инженерии)
Одним из основных понятий программной инженерии является понятие жизненного цикла ПО (software life cycle). Жизненный цикл ПО это период времени с момента принятия решения о необходимости создания ПО до момента его полного изъятия из эксплуатации. Жизненный цикл ПО состоит из определенных этапов. В соответствии с различными международными и национальными стандартами, регламентирующими этапы и процессы жизненного цикла ПО эти этапы могут носить различные названия. В данном курсе мы будем использовать следующие обобщенные названия этих этапов: · Подготовка (сбор требований) · Планирование (оценка, расписание) · Моделирование (анализ требований, проектирование) · Конструирование (кодирование, интеграция, тестирование) · Развертывание (поставка, внедрение и сопровождение) Заметим, что часто под жизненным циклом понимают непосредственно процесс разработки в этом случае выделают такие этапы как: анализ требования. проектирование, кодирование, тестирование. Модели, описывающие разные варианты последовательностей этих этапов, будут рассмотрены в теме нашего курса «Модели жизненного цикла ПО». Организации работ над программным проектом в рамках моделей и в рамках каждого из этапов рассматривается в разделе курса «Управление программными проектами». Поясним суть каждого из этапов жизненного цикла. 1. Подготовка (сбор требований, анализ бизнес-процессов, разработка концепции, постановка задачи). На этапе подготовки осуществляется активное взаимодействие между фирмой-разработчиком ПО и фирмой-заказчиком, заключается контракт, собираются и формулируются требования, определяющие характеристики и функции разрабатываемого ПО. При разработке ПО этот этап исключительно важен. Ошибки, допущенные на этом этапе, даже при условии безупречного выполнения последующих этапов могут привести к тому, что разработанный программный продукт не будет соответствовать требованиям практики, сферы его применения. Для создания конкурентоспособных продуктов в ходе выполнения этого этапа должны быть получены четкие ответы на следующие вопросы: - Что должна делать программа? - В чем состоят реальные проблемы, разрешению которых она должна способствовать? - Что представляют собой входные данные? - Какими должны быть выходные данные? Ответы на вопросы этого этапа должны быть зафиксированы в документе, называемым «задание на разработку», который должен быть подписан представителями заказчика и исполнителя. Этот документ обычно содержит следующие укрупненные разделы: - общая характеристика задачи; - описание входных данных; - описание выходных данных; - описание алгоритмов решения задачи; - источники разработки. Рассмотрим эти разделы подробнее. В разделе «Общая характеристика задачи» должно как минимум три подраздела: назначение системы, экономическая эффективность и участники проекта. Назначение программы - это четкое представление о том, что зачем создается данная программа (это действительно необходимо подробно описать, так как часто заказчик и разработчик вкладывают разный смысл в одни и те же понятия). В разделе «экономическая эффективность» нужно определить насколько внедрение данной программы будет способствовать увеличению экономической эффективности конкретной фирмы, то есть насколько сократятся непродуктивные затраты пользователя после внедрения данной программы. Иногда экономическую эффективность можно выразить в денежном эквиваленте (например, суммированием затрат сотрудников, сокращенных в результате внедрения новой программы). Но чаще всего используют такие показатели эффективности как снижение времени на решение задач, уменьшение количества сотрудников, привлекаемых для решения задач, снижение накладных расходов. Чем полнее и ярче будет подана предполагаемая экономическая эффективность, тем легче будет продать программу. В разделе «Участники проекта» должны быть перечислены все подразделения заказчика, которые участвуют в решении задачи до и после внедрения программы. Желательно также указать графическое представление подразделений и связей между ними. Это очень облегчит дальнейший этап - определение спецификаций. В разделе «Входные данные» должны быть подробно описаны все документы, являющиеся источником данных для решения задачи. Учитывая структуру подразделений, участвующих в проекте нужно обойти их и собрать у сотрудников организации образцы всех таких документов. Если данные не документированы (например, телефонный звонок) сотрудник должен так или иначе дать их формальное описание. Пропуск хотя бы одного документа на данном этапе может привести к серьезным проблемам на этапе внедрения. Для каждого документа должна быть получена информация о его структуре, о том, откуда он поступает и с какой частотой. Если же программа разрабатывается не под конкретного заказчика и предназначена для автоматизации каких-либо реальных производственных задач, то для описания входных данных необходимо обратиться к экспертам. Причем желательно привлекать экспертов с реальных предприятий. Программы, которые проектируются на основе книжных описаний конкретной задачи, плохо продаются. Аналогично должны быть описаны выходные данные. Причем следует указать необходимость наличия физической копии. Например, некоторые данные можно хранить в базе данных и просматривать на экране, а другие нужно в обязательном порядке распечатывать. В разделе «Алгоритмы решения задачи» должны быть описаны не алгоритмы, используемые в разрабатываемой программе, а алгоритмы, которые используются для решения задачи на момент обследования. Возможно, это уже используемая устаревшая программа или ручная технология. В процессе обследования может быть выявлено, что некоторые документы, имеющие отношение к разрабатываемой программе, являются выходными для одного отдела и входными для другого. Именно такие документы должны «исчезнуть» в первую очередь после того, как программ будет внедрена. Необходимо абсолютно четко понять существующий алгоритм формирования выходной информации на основе входной. Для выяснения этого алгоритма не надо стесняться быть нудным и надоедливымJ. В разделе «Источники разработки» должна содержаться информация о том, откуда получены сведения, на основе которых описаны входные, выходные данные и алгоритмы решения задачи: фамилии и должности сотрудников, желательно даты бесед, законы, номера внутренних инструкция. 2. Планирование. На этапе планирования определяется · объем работ, · риск работ, · необходимые трудозатраты, · рабочие задачи · план-график работ 3. Моделирование. Этап моделирования состоит из двух подэтапов: анализ требований и проектирование. Результат этих этапов обычно фиксируется в виде диаграмм и графических схем в документе, называемом «Техническое задание». В определенной степени анализ требований можно рассматривать как формулировку выводов, следующих из результатов этапа сбора требования. На этом этапе требования анализируются и формулируются в виде ряда строгих спецификаций, явно определяющих функции, интерфейс и рабочие характеристики разрабатываемого ПО. В число таких характеристик могут входить скорость выполнения, объем потребляемой памяти, гибкость применения и др. Данный этап должен завершиться составлением и подписанием документа «Техническое задание». , в котором, как правило, содержатся следующие разделы - название системы (полное и сокращенное название, версию); - цели создания; - характеристика области применения; - перечень автоматизируемых функций и требования к системе в целом (требования к соблюдению режимов безопасности, функциональной согласованности, к интерфейсу, степень взаимодействия с другими программами); - информационная база (все используемые файлы, их структура, организация взаимодействия пользователя с данными); - программное обеспечение (интегрированные среды программирования, СУБД); - аппаратное обеспечение (обычно указывается нижние пределы характеристик аппаратного обеспечения, но следует указать и оптимальную конфигурацию); - график работ. В некоторых разделах техническое задание похоже на задание на разработку, с тем отличием, что в техническом задании указывается не то, как данные обрабатываются в настоящей момент, а как они должны обрабатываться создаваемой программой. Основная задача проектирования состоит в разработки архитектуры ПО. Архитектура ПО определяет структуру ПС (задает ее разбиение на компоненты, связи между ними, их интерфейсы), а также основные принципы проектирования и развития системы. Современные программы разрабатываются на основе модульной технологии. Модуль это физически и логически независимая часть ПС. Физическая независимость подразумевает, что каждый модуль описан в отдельном файле. Логическая независимость подразумевает, что модуль решает логически объединенную между собой группу задач. В качестве модульной структуры программы принято использовать древовидную структуру, называемую модульное дерево ПС. В вершинах такого дерева размещаются программные модули, а стрелки указывают их подчиненность. В тексте модуля, из которого исходит стрелка, должна быть ссылка на тот модуль, на который она показывает. Другими словами, каждый модуль может обращаться только к подчиненным ему модулям. На этапе проектирования необходимо описать модульное дерево, то есть количество модулей, их подчиненность, для каждого модуля определить функциональность. Для каждого модуля должна быть составлено собственное описание – спецификация. Сложно ввести стандарт на степень детализации спецификации модуля, но обычно придерживаются следующих рекомендаций. В спецификации модуля приводится только интерфейсная часть. Можно высказать пожелания к общим типам данных и классов объектов, которые могут быть доступны из других модулей. Если описываются спецификации на подпрограммы, в них указывает назначение подпрограммы, а также количество и тип формальных параметров, их порядок, тип возвращаемого значения для функции. Кроме того, следует указать изменение изображение на экране или вывод печатного документа, который может произойти в результате вызова подпрограммы. Существуют различные методы разработки структуры программы. В процессе ее создания модульная структура может по-разному формироваться и использоваться для определения порядка кодирования. К двум основным методам разработки структуры программы относят метод восходящей разработки («снизу вверх») и нисходящей разработки («сверху вниз»). Существуют различные методы разработки структуры программы. В процессе ее создания модульная структура (т.е. структура модулей – компонент программы) может по-разному формироваться и использоваться для определения порядка кодирования. К двум основным методам разработки структуры программы относят метод восходящей разработки («снизу вверх») и нисходящей разработки («сверху вниз»). Метод восходящей разработки заключается в следующем. Сначала строится модульная структура программы в виде дерева путем описания всех режимов работы программы. Затем поочередно программируются модули, начиная с самого нижнего уровня. Для каждого программируемого в данный момент модуля должны быть заранее созданы те модули, к которым он может обращаться. После того как все модули созданы, производится их поочередное тестирование и отладка в том же порядке, в каком велось их программирование. При восходящем методе разработки модулей нижнего уровня глобальная информация для них может быть еще не окончательно определена, поэтому приходится перепрограммировать их позже, если при программировании других модулей производилось существенное уточнение глобальной информации. Метод нисходящей разработки заключается в следующем. Так же как и в предыдущем методе сначала строится модульная структура программы в виде дерева. Затем поочередно кодируются модули, начиная с самого верхнего уровня (головного модуля). К программированию очередного модуля переходят только после того, как запрограммирован модуль, который непосредственно к нему обращается. После того, как все модули описаны, производится их поочередное тестирование и отладка в том же нисходящем порядке. При этом те модули, к которым обращается данный, заменяют заглушками. Каждый модуль-заглушка представляется простым программным фрагментом, основная задача которого - сигнализировать о факте обращения к имитируемому модулю. После завершения тестирования и отладки модуля переходят к тестированию одного из модулей, которые пока представлены заглушками. При этом модуль-заглушку заменяют «полным » модулем, добавляя заглушки в те модули, к которым он обращается в ходе тестирования. Каждый модуль на момент обращения к нему при тестировании имеет «естественное» состояние данных. Таким образом, нисходящий метод позволяет заменить большой объем «отладочного» программирования программированием достаточно простых заглушек используемых модулей. Такой порядок разработки дает возможность своевременно формировать все необходимые глобальные переменные. У данного метода также есть недостаток – необходимость абстрагироваться от базовых возможностей используемого языка, придумывая абстрактные операции, которые позже необходимо реализовывать в модулях нижнего уровня. Кроме классических методов нисходящей и восходящей разработки, в которых модульная структура программы должна быть разработана до начала кодирования, применяют также подходы, при которых модульная структура формируется в процессе создания модулей: конструктивный и архитектурный. Конструктивный подход к разработке программы представляет собой модификацию метода «сверху вниз», при которой модульная структура программы формируется непосредственно в процессе программирования модулей. В процессе программирования головного модуля (исходя из спецификации всей задачи в целом) выделяются подзадачи. Для каждой выделенной подзадачи создается описание реализующего ее фрагмента программы, который в дальнейшем может быть представлен некоторым поддеревом модулей. Ответственность за выполнение выделенной функции несет головной модуль этой ветки. Аналогичные действия производятся при создании любого другого модуля, выбранного из текущего состояния дерева подпрограммы. Архитектурный подход к разработке программы – это модификация метода «снизу вверх», при котором модульная структура формируется в процессе программирования каждого модуля. При этом на первый план выходит другая цель: повышение уровня используемого языка, а не разработка конкретной программы. То есть для данной предметной области выделяются типовые функции, каждая из которых может использоваться при решении различных задач в этой области, и затем программируются модули, выполняющие эти функции. Процесс выделения таких функций связан с накоплением и обобщением опыта решения задач в заданной предметной области, поэтому обычно сначала выделяются и реализуются отдельными модулями боле простые функции, а затем постепенно появляются модули, использующее ранее созданные функции. Такой набор модулей создается в расчете на то, что при разработке той или иной программы заданной предметной области некоторые их этих модулей могут оказаться приемлемыми. Это позволяет существенно сократить трудоемкость разработки конкретной программы путем подключения к ней заранее заготовленных и проверенных на практике модулей нижнего уровня. Такие модули могут многократно использоваться в разных программах, поэтому архитектурный подход позволяет бороться с дублированием в программировании. 4. Конструирование. Конструирование ПО включает в себя кодирование, интеграцию и тестирование. Кодирование заключается в переводе на язык программирования конструкций, записанных на языке проектирования. Правила оформления текста программа см. в пособии Мирошниченко Е.А. «МЕТОДИЧЕСКИЕ УКАЗАНИЯ по организации и оформлению исходного текста программ» (Задание для самостоятельной работы.) К правилам указанным в этом пособии следует добавить замечание по нотациям (нотация – соглашение о правилах создания имен). В нотации Паскаля каждое слово, составляющие идентификатор, начинается с прописной буквы (MaxLength). Венгерская нотация отличается от предыдущей наличием префикса, соответствующего типу величины (iMaxLength). Согласно нотации Camel, с прописной буквы начинается каждое слово, составляющее идентификатор, кроме первого (maxLength). Отметим, что в C# для именования программных объектов чаще всего используют нотации Паскаля и Camel. Также распространена нотация, где между словами, составляющими идентификатор ставятся знаки подчеркивания (max_length), Интеграция программной системы – это процесс объединения отдельных (протестированных) модулей с целью получения системы, требуемой проектом. Тестирование, отладка и оптимизация. (В литературе часто этот этап просто называют тестированием). На этом этапе производится всесторонняя проверка программ, цель которой убедиться в том, что ПО является качественным. Существует стандарты качества ПО, один из которых (ISO/IEC 9126-1) будет рассмотрен в нашем курсе. На данном этапе пока определим качественную программу следующим образом. Качественная программа – это программа, выполняющая заранее объявленные действия известным способом и не выполняющая никаких необъявленных действий. Существует определенные методы тестирования, которые буду рассмотрены в разделе курса «Тестирование ПО». По поводу того как должно выполняться тестирование, среди разных программистов нет еденного мнения, но они единодушны в том, как тестирование не должно выполняться. Тестирование программы (или ее отдельных модулей) не должен выполнять программист (или группа программистов), создавший эту программу (модуль). Рассмотрим этот этап более подробно. Существуют три аспекта проверки программы на: - правильность; - эффективность реализации; - вычислительную сложность. Проверка правильности (верификация программы) удостоверяет, что программа делает в точности то, для чего она была предназначена. Статистика свидетельствует, что стоимость такого тестирования программного продукта составляет не менее 50 процентов стоимости начальной разработки и 70 процентов всей стоимости поддержки программного продукта. Но сколько бы сил и денег не было потрачено на тестирование необходимо понимать, что тесты могут доказать наличие ошибок в программе, но они не могут доказать их отсутствия. Один из общих законов программирования гласит, что ни одна программа не дает желаемых результатов при первой попытке ее трансляции и выполнения. На рисунке изображена диаграмма процентного соотношения причин появления тех или иных ошибок при обработке данных.
Из диаграммы видно, что большинство ошибок совершаются именно на этапе кодирования. На следующем рисунке показа стоимость исправления ошибок на различны этапах ЖЦ.
Существуют два типа программных ошибок: синтаксические и семантические. Синтаксические ошибки возникают из-за нарушений правил (лексики) языка программирования и выявляются во время компиляции. Такие ошибки могут быть исключены сравнительно легко. Большинство из них можно выявить путем простого просмотра текста программы. Чаще всего программисты оставляют этот этап компилятору, однако сквозной просмотр текста иногда бывает полезен. Скорость исправления ошибок, выявленных компилятора зависит от степени знакомства программиста с данным языком. Семантические или логические ошибки приводят к некорректным вычислениям или ошибкам во время выполнения программы (run-time error). Математическая безупречность алгоритма не гарантирует правильности его перевода в программу. Аналогично разумный вид получаемых результатов не дает достаточной гарантии правильности программы. В общем случае нельзя дать общего решения для проведения проверки на правильность программы. Конечно, самым лучшим способом тестирования программы является поставка ее пользователю сразу же после завершения программирования. Единственное слабое место такого метода – этот пользователь больше никогда не купит у вас не одной программы. Выявление и устранение ошибок часто имеет циклический характер. Устранение одной ошибки может породить другую ошибку. Особенно это касается работы с глобальными переменными. Как правило, устранение таких ошибок заключается в разработке и проведении наборов тестов, то есть выполнении программы с тщательно подобранными проверочными данными для которых известен правильный ответ. При подготовке к тестированию следует придерживаться следующих правил: 1. Чем раньше спроектирован тест, тем вероятнее выявление ошибок. Поэтому лучше готовить тесты еще на этапе проектирования системы. 2. Недопустима хаотичность процесса тестирования. Он должен быть документирован и полностью управляем. 3. Необходимы повторяемость и завершенность тестов. 4. Следует избегать добавления новых тестов в процессе тестирования. Первым шагом семантической проверки является ручной прогон, то есть программист моделирует прохождение данных через его программу с помощью карандаша и листа бумаги. Это скучная и утомительная работа, однако, большинство ошибок может быть выявлено именно на этой стадии. Разумеется, таким образом нельзя проверить всевозможные комбинации данных. Однако можно проверить всевозможные типы или наиболее вероятные комбинации данных. Если они дают правильные результаты, предполагается, что непроверенные комбинации также дали бы правильные результаты. Отдельно тестируется каждый модуль программы. Если программа хорошо спроектирована, то после этого остается проверить только интерфейс между модулями. Следует особо подчеркнуть, что первоначальное тестирование процедур модуля выполняется программистом путем написание коротких «программок», которые вызывают процедуры в различными наборами параметров. Начинающему программисту такой подход может показаться очень расточительным с точки зрения расходования рабочего времени, но это единственный способ более или менее эффективной борьбы с ошибками в программе. Очень часто тесты (файлы с тестовыми данными) создаются вручную. Следовательно, их число редко превышает два-три десятка. Иногда применяют генераторы тестовых данных – специальные программы, формирующие данные в соответствии со спецификациями задаваемыми программистами. Данные могут группироваться в записи, имеющие установленные форматы. Тестовые данные могут также систематически или случайно выбираться из другого заданного набора данных для уменьшения их общего количества, над которыми выполняется тест. Кроме того, необходимо на завершающем этапе тестирования следует прогнать программу на реальном объеме данных и посмотреть насколько интерфейс программы выдержит такую нагрузку. (Очень часто программа, прекрасно работающая для двух десятков записей в базе данных через год, когда база будет насчитывать сотни тысяч записей, будет выполняться несколько минут). Если прогон программы на тестовых данных дает неверный результат, то необходимо найти и исправить ошибку. При отладке программы используют три основных способа: - распечатка текущего состояния - точка останова - трассировка Распечатка текущего состояния используется с целью фиксации фактических значений переменных для проверки хода вычислений. Для этого во время отладки программы в местах, которые программист считает критическими, помещают функции вывода на экран текущего состояния переменных. После окончания теста вызовы этих функций удаляются и программа снова перекомпилируется. Метод «точки останова» обычно применяют при разного рода зацикливаниях. В текст программы включают функции останова программы, например можно вывести на экран сообщение «Достигнута точка n» и вызвать функцию getch(). Этот метод имеет смысл объединять с методом деления пополам. Точка останова ставится в средине программы, если программа выполнилась до этой точки, что точка останова ставиться в средине второй половины программы, если нет, то в средине первой и т.д. Таким образом, область поиска ошибки постепенно сужается. Трассировка – это пошаговое выполнение программы с возможностью просматривать состояние всех переменных. Она может оказаться очень эффективной, но значительно замедляет выполнение программы и, не будучи тщательно спланированной, приводит к колоссальным объемам выдаваемой информации. Проверка вычислительной сложности, как правило, заключается в экспериментальном анализе сложности алгоритма или экспериментальном сравнении двух алгоритмов и более, решающих одну и ту же задачу. Проверка эффективности реализации (оптимизация) направлена на отыскание способа заставить правильную программу работать быстрее или расходовать меньше памяти. Теоретически, оптимизация не является обязательным условием разработки программы. Множество программ может быть поставлено (и поставляется) сразу же после отладки. Однако существует целый ряд программ, критичных как к скорости выполнения, так и к размеру. К таким программам относятся, например, программы графического вывода в силу большого объема вычислений, связанных с графическими преобразованиями. Очевидно, что оптимизация должна проводиться опытными программистами, хорошо знакомыми с тонкостями языка и компилятора. Поэтому сегодня чаще оптимизируются только фрагменты программы, влияющие на скорость вывода на экран изображений. При проектировании больших систем оптимизацию производится в два этапа. Сначала оптимизируется текст программы на языке высокого уровня, а затем наиболее критичные ко времени выполнения процедуры переписывают на языке ассемблера. Чтобы улучшить программу, пересматриваются результаты реализации в процессе построения алгоритма. Не рассматривая все возможные варианты и направления оптимизации программ, приведем здесь некоторые полезные способы, направленные на увеличение скорости выполнения программ. Первый способ основан на следующем правиле. Сложение и вычитание выполняются быстрее, чем умножение и деление. Целочисленная арифметика быстрее арифметики вещественных чисел. Таким образом, X+X лучше, чем 2*X, а (2i+j)*0,5 хуже, чем (i+i+j)*0,5. Умножение выполняется быстрее чем деление, например sum*=0,5 лучше чем sum/=2;При выполнении операций над целыми числами следует помнить, что благодаря применению двоичной системы счисления умножение числа, кратные двум, можно заменить соответствующим количеством сдвигов влево. Поэтому 10*А выполняется дольше, чем (A<<3)+(A<<1). (Действительно 10*A=8*A+2*A). Второй способ заключается в удалении избыточных вычислений. Пример, вычисление квадратных корней уравнения root1=(-b+sqrt(b*b-4*a*c))/(2*a); root2=(-b+sqrt(b*b-4*a*c))/(2*a); Лучшим решением является следующее denomA=a+a; denomC=c+c; diskrim=sqtr(b*b-denomA*demonС); root1=(-b+diskrim)/demomA; root2=(-b-diskrim)/demomA; Легко увидеть, что в первом случае потребовалось выполнить четыре операции сложения/вычитания, восемь операций умножения, две операции деления, два вызова функции sqrt, во втором — пять операций сложения/вычитания, два умножения, два деления и одно обращение к функции sqrt. Третий способ проверки эффективности реализации основан на способности некоторых компиляторов строить коды для вычисления логических выражений так, что вычисления прекращаются, если результат становится очевидным. Например, в выражении A||B||C, если A имеет значение «истина», то переменные В и С уже не проверяются. Таким образом, можно сэкономить время, разместив переменные A,B,С так, чтобы первой стояла переменная, которая вероятнее всего будет истинной, а последней та, которая реже всего принимает истинное значение. Однако следует быть осторожным в следующем примере: ROOL(A)||B||C. ROOL(A) может и чаще принимает значение «истина», но представляет собой вызов функции, возможно выполняющей сложные и длительные вычисления. Тогда может оказаться, что запись В||С||ROOL(A) является более эффективной. Четвертый прием - исключение циклов. Пример. Рассмотрим следующий пример: сформировать одномерный массив, каждый элемент которого должен быть равен сумме элементов строки двумерного массива. for (i=0;i<1000;i++) a[i]=0; for (i=0;i<1000;i++) for (j=0;j<10;j++) a[i]+=c[i][j]; можно переписать так for (i=0;i<1000;i++) { b=c[i][0]; for (j=1;j<10;j++) b+=c[i][j]; a[i]=b; } В данном пример выигрыш достигается, во-первых, за счет уменьшения количества циклов (два, а не три), а во-вторых, за счет того, что с введением временной переменной b уменьшено количество операций вычисления адресов элементов массива. Пятый прием – развертывание циклов. Пример. Следующий фрагмент for(i=0; i<1000; i++) for(j=0; j<3; j++) a[i]+=c[i][j]; можно переписать так: for(i=0; i<1000; i++) a[i]+=c[i][0]+c[i][1]+c[i][2]; Выигрыш в скорости вычислений вполне очевиден. Шестой прием – разгрузка участков повторяемости, то есть вынос из циклов выражений, которые могут быть вычислены вне циклов. Например, for (int i=0; i<1000; i++) { if (P==S) y=1; else y=S+25; x[i]=(y+i)/2; } лучше переписать if (P==S) y=1; else y=S+25; for (int i=0; i<1000; i++) x[i]=(y+i)/2; В данном случае используется так называемая чистка цикла вверх. Однако в следующем примере таким образом нельзя разгрузить цикл: for (int i=0; i<10; i++) { x*=i; if (z>0) c=chr(x); else a=x+2; } Действительно, при вычислении значений переменных с и a используется переменная x, значение которой вычисляется в цикле. Однако, значение переменных все равно определяется значением переменной x, вычисленной на последней итерации цикла. Поэтому эффективнее переписать данный фрагмент следующим образом, применяя чистку цикла вниз: for (int i=0; i<10; i++) x*=i; if (z>0) c=chr(x); else a=x+2;
Кроме указанных способов оптимизации полезно производить чистку программы, то есть удаление из нее ненужных объектов и конструкций: - удаление идентичных операторов; - удаление несущественных операторов, то есть операторов не влияющих на результат программы; - удаление бесполезных операторов, вычисляющих вспомогательные переменные, используемые только для постановки в другие выражения; - удаление функций, к которым нет обращений; - удаление объявленных, но неиспользуемых переменных, операций и т.д. Также существует ряд способов экономного расходования памяти: - совмещение по памяти не существующих одновременно статических переменных, то есть несвязанные переменные следует объявлять в различных модулях, а не в теле главной программы. - изменение времени жизни переменной - перемещение оператора объявление переменной ближе к фрагменту, где переменная используется - экономия стека: при передаче массива в качестве параметра подпрограммы, следует использовать указатель на массив.
Кроме того, следует делать текст программы более компактным (если это не приводит к ухудшению читабельности). Необходимо следить за дублированием в различных ветвях алгоритмов, и сокращать текст программы за счет оформления повторяющихся фрагментов текста в виде функций. Однако не следует слишком злоупотреблять созданием процедур: наличие большого количества процедур, состоящих из 2-3 операторов, вряд ли можно считать приемлемым. Это далеко не полный перечень способов оптимизации. Здесь приведены лишь самые очевидные из них. Следует, кроме того, заметить, что не всегда стоит увлекаться погоней за быстродействием, так как при этом чаще ухудшается удобочитаемость программы. - 5. Развертывание (внедрение и сопровождение). Внедрение – это процесс запуска программы в промышленную эксплуатацию. Этот этап характерен для программ, разрабатываемых на заказ. При внедрении разработчик устанавливает продукт на компьютеры заказчика (инсталлирует его) и проверяет весь его рабочий цикл. Это этап эксплуатации системы. Если программа работает устойчиво, начинается этап обучения пользователей. (В договоре необходимо заранее указать объем учебных часов, которые разработчики должны посвятить обучению заказчика.) Сопровождение – это процесс поддержки внедренной программы. Сопровождение предусматривает оказание консультаций, а также внесение необходимых изменений в программу. Каким бы изощренным ни было тестирование программ, к сожалению, в больших программных комплексах чрезвычайно тяжело устранить абсолютно все ошибки. Устранение обнаруженных при сопровождении — задача этого этапа. По мере выявления и исправления ошибок в ходе сопровождения их количество постепенно уменьшается. Однако через какое-то время кривая ошибок вновь начинает расти. Можно предположить, что происходить нечто вроде интерференции волн различной частоты – два процесса накладываются друг на друга, приводя систему к краху. Первый процесс – порождение новых ошибок при исправлении предыдущих, второй – повышение квалификации пользователей при работе с программой и как следствие использование ими тех возможностей программы, которые они раньше не использовали. Выполняемый в ходе сопровождения анализ опыта эксплуатации программы позволяет обнаруживать узкие местам или неудачные проектные решения в тех или иных частях программного комплекса. В результате такого анализа может быть принято решение о проведении работ по совершенствованию разработанной системы. Кроме описанного выше сопровождение может включать в себя проведение консультаций, обучение пользователей системы, оперативное снабжение пользователей информацией о новых версиях системы и т.п. Качественное проведение этапа сопровождения в большой степени определяет коммерческий успех программного продукта. Все исправления, вносимые на этапе сопровождения, приводят к изменению структуры программы в сторону ее ухудшения и, в конечном счете, к дезорганизации системы. В конце концов, наступает момент, когда дальнейшее исправление ошибок в программе теряет всякий смысл. С этого момента, можно считать, что программа умерла. На самом деле, незначительное число программ доживают до собственной «смерти». Чаще программа заменяется на новую или новую версию данной. Новая версия программы обычно учитывает ошибки предыдущей, а также дополнительные требования, возникшие в связи с появлением новой техники и более глубоким осмыслением задачи пользователем.
В заключении темы, чтобы продемонстрировать сложности работы в команде, принимающей участие в программном проекте, приведем шарж «качели», появившейся более 35 лет назад, который прекрасно иллюстрирует степень взаимопонимание участников команды.
Контрольные вопросы по теме 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. Охарактеризуйте этап сопровождения ПС.
Как было отмечено выше, существуют различные международные и национальные стандарты, регламентирующие этапы и процессы жизненного цикла ПО. Основным законом, определяющим место, цели и задачи стандартизации в России является закон РФ «О техническом регулировании». В законе дано следующее определение стандарта: «стандарт - документ, в котором в целях добровольного многократного использования устанавливаются характеристики продукции, правила осуществления и характеристики процессов производства, эксплуатации, хранения, перевозки, реализации и утилизации, выполнения работ или оказания услуг. Стандарт также может содержать требования к терминологии, символике, упаковке, маркировке или этикеткам и правилам их нанесения». Можно сказать, что стандарт – это специальным образом оформленный договор между всеми участниками определенного вида деятельности (например, производства и потребления определенной продукции). Состав процессов жизненного цикла ПО в современном мире регламентируется международным стандартом ISO/IEC 12207:1999 «Information Technologies – Software Life Cycle Process» (Информационные технологии – Процессы жизненного цикла ПО). ISO (International Organization for Standardization) - международная организации по стандартизации. IEC – International Electrotechnical Commission – международная комиссия по электротехнике. Переводом этого стандарта является российский стандарт ГОСТ Р ИСО/МЭК 12207-99 «Информационная Технология. Процессы жизненного цикла программных средств». Этот стандарт описывает структуру жизненного цикла программного обеспечения и его процессы (а не содержание этапов). Процесс жизненного цикла определяется как совокупность взаимосвязанных действий, преобразующих некоторые входные данные в выходные. Каждый процесс характеризуется определенными задачами и методами их решения, а также исходными данными и результатами. Всего в данном стандарте специфицировано 17 процессов, в составе которых выделено 74 вида работ, которые в свою очередь разделены на 232 решаемые задачи. Все процессы в соответствии со стандартом делятся на основные, организационные и вспомогательные. Основные процессы протекают под управлением главных участников, вовлеченных в жизненный цикл ПС – заказчика и разработчика-поставщика ПС. Вспомогательные и организационные процессы выделены, как подчиненные относительно основных, так как они могут быть целенаправленными составными частями других процессов и порождаться основными процессами. В стандарте достаточно определенно и однозначно изложено, что должны делать, что могут делать и что рекомендуется делать основным участникам ЖЦ – заказчику, поставщику, разработчику. В то же время не указывается, какими методами должны производиться те или иные работы. Для определения методов выполнения работ необходимо пользоваться стандартами и руководствами более низкого уровня. Основные процессы - приобретение, поставка, разработка, эксплуатация, сопровождение. Организационные процессы – управление, усовершенствование, создание инфраструктуры, обучение. Вспомогательные процессы – документирование, управление конфигурацией, обеспечение качества, верификация, аттестация, совместная оценка, аудит, разрешение проблем. Процесс разработки (development process) предусматривает действия, выполняемые разработчиком и охватывает работы по созданию ПО в соответствии с заданными требованиями, включая оформление проектной и эксплуатационной документации, а также подготовку материалов, необходимых для проверки работоспособности и соответствия качества программных продуктов, материалов, необходимых для обучения персонала, и т. д. По стандарту процесс разработки включает следующие действия: • подготовительную работу - выбор модели жизненного цикла, стандартов, методов и средств разработки, а также составление плана работ; • анализ требований к системе - определение ее функциональных возможностей, пользовательских требований, требований к надежности и безопасности, требований к внешним интерфейсам и т. д.; • проектирование архитектуры системы - определение состава необходимого оборудования, программного обеспечения и операций, выполняемых обслуживающим персоналом; • анализ требований к программному обеспечению - определение функциональных возможностей, включая характеристики производительности, среды функционирования компонентов, внешних интерфейсов, спецификаций надежности и безопасности, эргономических требований, требований к используемым данным, установке, приемке, пользовательской документации, эксплуатации и сопровождению; • проектирование архитектуры программного обеспечения — определение структуры программного обеспечения, документирование интерфейсов его компонентов, разработку предварительной версии пользовательской документации, а также требований к тестам и плана интеграции; • детальное проектирование программного обеспечения – подробное описание компонентов программного обеспечения и интерфейсов между ними, обновление пользовательской документации, разработка и документирование требований к тестам и плана тестирования компонентов программного обеспечения, обновление плана интеграции компонентов; • кодирование и тестирование программного обеспечения — разработку и документирование каждого компонента, а также совокупности тестовых процедур и данных для их тестирования, тестирование компонентов, обновление пользовательской документации, обновление плана интеграции программного обеспечения; • интеграцию программного обеспечения - сборку программных компонентов в соответствии с планом интеграции и тестирование программного обеспечения на соответствие квалификационным требованиям, представляющих собой набор критериев или условий, которые необходимо выполнить, чтобы квалифицировать программный продукт, как соответствующий своим спецификациям и готовый к использованию в заданных условиях эксплуатации; • квалификационное тестирование программного обеспечения — тестирование программного обеспечения в присутствии заказчика для демонстрации его соответствия требованиям и готовности к эксплуатации; при этом проверяется также готовность и полнота технической и пользовательской документации • интеграцию системы - сборку всех компонентов системы, включая программное обеспечение и оборудование; • квалификационное тестирование системы - тестирование системы на соответствие требованиям к ней и проверка оформления и полноты документации; • установку программного обеспечения - установку программного обеспечения на оборудовании заказчика и проверку его работоспособности; • приемку программного обеспечения - оценку результатов квалификационного тестирования программного обеспечения и системы в целом и документирование результатов оценки совместно с заказчиком, окончательную передачу программного обеспечения заказчику.
Так же в России действует ГОСТ Р ИСО/МЭК 15288-2005 «Системная инженерия – Процессы жизненного цикла систем». Это российский аналог международного стандарта ISO/IEC 15288 System life cycle processes. Устанавливает последовательность этапов и перечень процессов ЖЦ разработки любых крупных проектов, в том числе и ПС. Введен в России с 1 января 2007г. Наиболее прогрессивный стандарт, в котором учтен международный опыт разработки сложных систем. В стандарте ГОСТ 15288 сделана попытка сформулировать общую модель ЖЦ, справедливую для любых типов проектов. В таблице 1 приведены цели и результаты для 6 этапов (стадий), которые составляют ЖЦ ПС согласно ГОСТ 15288. Таблица 1 Стадии жизненного цикла согласно ГОСТ Р ИСО/МЭК 15288-2005
Необходимо отметить, что стандарт ГОСТ 15288 - это первый в России стандарт, тесно увязанный со стандартами серии ISO 9000 и детально описывающий все этапы ЖЦ ПС.
Контрольные вопросы по теме 1. Что такое стандарт? 2. Какие два основных стандарта на ЖЦ программных систем Вы знаете? В чем их принципиальное отличие? 3. Что такое процесс жизненного цикла в соответствии с стандартом ГОСТ Р ИСО/МЭК 12207-99 «Информационная Технология. Процессы жизненного цикла программных средств»? 4. Какие процессы относятся к основным, организационным, вспомогательным в соответствии с стандартом ГОСТ Р ИСО/МЭК 12207-99 «Информационная Технология. Процессы жизненного цикла программных средств»? 5. Какие этапы (стадии) ЖЦ выделены в стандарте ГОСТ Р ИСО/МЭК 15288-2005 «Системная инженерия – Процессы жизненного цикла систем»?
содержание .. 2 3 4 5 ..
|
|