Все приказы отдавайте устно. Не оставляйте записей и документов, которые могут обернуться против вас.
Технология создания ПО требует выполнить определенные работы, связанные с составлением проектной документации. Новичкам часто кажется, что написание спецификаций является не очень важной частью процесса разработки или даже ненужной тратой времени. Однако это не так, документация проекта содержит в себе все основные мысли, решения, принятые в ходе бесконечных обсуждений, договоренности и требования заказчика. Кроме того, четкая фиксация информации помогает выявить неточности и противоречия, а также определить ясную и четкую политику, которая может стать доступной всему коллективу в документальном виде. Сама же документация становится достаточно формальным описанием будущей системы и позволяет впоследствии проводить верификацию.
В ходе каждого процесса (этапа) разработки формируется определенный набор документов (выходные данные), которые являются входными данными для следующих процессов (этапов). Практически каждый документ базируется на ранее созданных документах и включает в себя дополнительные уточнения описания конечного продукта или связанных с его построением процессов.
В свое время Г. Майерсом [5] была предложена модель разработки ПО как модель трансляции одного описания программного продукта в другое. Если встать на эту позицию, то надо предполагать, что первичные требования заказчика - описание продукта на языке очень высокого уровня. Коллектив разработчиков просто транслирует его поэтапно, постепенно доводя это описание до уровня машинной реализации. При этом, кроме формально исполняемых документов - программ, создаются и другие документы - эксплуатационные. Часть из них - инструкции по эксплуатации исполняют люди.
Таким образом, для процесса "Разработка требований" можно определить следующий набор документов:
Для процесса "Проектирование" характерны следующие документы:
Процесс "Реализация" формирует на выходе код программы.
"Тестирование" включает в себя создание таких документов, как:
На рис. 2.1 приведены основные документы и результаты, получаемые в ходе разработки ПО. Здесь рассматривается обобщенная модель и обобщенные типы документов. Из соображений компактности изображения названия закодированы латинскими буквами. В реальной разработке их количество существенно больше, часто возникают ситуации замены приведенных документов другими типами, добавления новых видов документов или невыполнения части этапов при разработке.
На начальном этапе формируется общее представление о потребностях в будущем продукте и ставится задача разработки (SOW - Statement Of Work). Это обычно и есть первичное описание необходимого продукта.
(рис 2.1) Основные документы, создаваемые при разработке ПО
Далее идет разработка системных требований, т.е. требований ко всему разрабатываемому изделию, детально определяющих все свойства будущего продукта (SYS - System requirements). Далее обычно удается определить, какую часть работы в системе будет выполнять аппаратура, какую - программное обеспечение, а какую - человек.
Поэтому на основе SYS-документации составляются требования к ПО (SRD - Software Requirements Document), которые детализируют все требования SYS, относящиеся к программной части. Эти требования также являются частью конечного продукта. Основная задача требований к ПО - определить, что должна делать система, а не как она это будет делать. Параллельно идет уточнение требований к аппаратной части (HRD - Hardware Requirements Document) и разработка организационных требований (ORD), включающих в себя описание необходимых документов, и установление протокола взаимодействия пользователей с программной системой.
На основе требований к ПО вся программная система разбивается на набор функциональных областей, требования к каждой области детализируются в документе, описывающем архитектуру программной системы. Здесь же описываются интерфейсы функциональных областей, и этот документ нужно рассматривать как часть конечного продукта.
Каждая функциональная область делится на модули, которые в свою очередь могут снова делиться на модули. Требования к модулю, описание его работы и его интерфейсы приводятся в документе DDD (Detailed Design Description), который также входит в состав конечного продукта. Здесь уже можно определять, как должен работать модуль, однако и тут степень детализации может быть разной, и часть алгоритмических решений может быть оставлена кодировщику.
Под интерфейсом модуля (или функциональной области) понимаются все функции, типы, константы и переменные, используемые для взаимодействия модуля с другими модулями, т.е. все, что связывает модуль с "внешним миром".
Таким образом, возможно отделение реализации модуля от "внешнего мира". Для других модулей будет доступен только интерфейс, а про реализацию они могут ничего не знать. Если реализация некоторого объекта недоступна для других модулей, а доступ происходит лишь на уровне экспортируемых модулем функций, то можно говорить об абстрактном или скрытом типе. Использование абстрактных типов упрощает разработку и повышает надежность общей системы.
На основе описаний модулей выполняется кодирование и интеграция уже с использованием особенностей выбранного языка программирования. Результат этого этапа - исполняемая программа (загрузочный модуль), соответствующая требованиям к ПО.
После разработки кода программы начинается этап тестирования (верификации), заключающийся в проверке соответствия поведения кода отдельных модулей DDD-требованиям, собранных функциональных областей - требованиям к функциональным областям (FA - Functional Areas TEST), собранной в целом системе функциональных областей - SRD-требованиям к ПО. Готовая система тестируется совместно с аппаратной частью, определенной в HRD, и в совокупности проверяется соответствие требованиям к системе SYS. На каждом этапе формируются отчеты о тестировании (или отчеты о прогоне тестов). Иногда такие отчеты могут составлять часть конечного продукта или входить в состав документации, предоставляемой сертифицирующему органу.
Необходимо заметить, что все этапы разработки не являются независимыми, а наоборот, постоянно происходит "трансляция" одного описания в другое - более детальное. При этом на каждом этапе разработки требований идет проверка соответствия текущих требований требованиям, уже определенным в предыдущем документе, т.е. соответствие SYS - SRD, соответствие SRD архитектуре программной системы и т.д. Часто ведется трассировка требований, т.е. для любого требования последующего документа можно проследить требование, из которого оно было определено в предшествующем документе. При этом первичными требованиями является SYS.
Ф. Брукс [10] дает следующую оценку трудоемкости для основных этапов ЖЦ разработки ПО:
Считая, что оба вида тестирования относятся к (I) интеграционному процессу, получаем диаграмму распределения трудозатрат, приведенную на рис. 2.2
(рис 2.2) Распределение трудозатрат
Из приведенной оценки и необходимых для разработки системы документов видно, что процесс кодирования является не самым большим и не самым трудоемким этапом разработки ПО, однако ключевым. Именно в ходе кодирования создается конечный продукт, ради получения которого и проводятся все вышеописанные действия.
Отметим важное свойство программного текста - пишется один раз (на этапе кодирования), а читается много раз как на всех последующих этапах разработки, так и при внесении изменений в код. Поэтому "читабельность" - важнейшая черта программного текста.
В случае несложной программы, модуля или функции всю документацию можно объединить в общую спецификацию программы, описывающую требования к ПО, его интерфейс, тест-требования и некоторые другие аспекты.
Стоит отметить, что спецификация или ее отдельные разделы могут проходить инспекции, дорабатываться, утверждаться, поэтому на работу с этим документом накладываются различные ограничения. Как минимум необходимо, чтобы в спецификации были указаны ее автор и текущая версия. Для отслеживания всех действий рекомендуется вести таблицу изменений, отмечать в ней, кто, когда, что и почему изменил, и указывать номер новой версии. Пример таблицы изменений можно увидеть в приложении Б.
Спецификация делится на разделы, соответствующие разным документам при разработке ПО. Схема написания спецификации, рекомендованной для данного учебного курса, полностью приведена в приложении А.
Первый раздел - это краткое описание конечного продукта (аналог SOW). Описание должно быть достаточно кратким, но давать четкое понимание назначения продукта. Здесь же следует указывать язык реализации и архитектуру целевой машины как самые общие требования к реализации. Например, если рассмотреть программу, вычисляющую периметр треугольника по длинам его сторон, то краткое описание может иметь следующий вид.
1. Общее описание задачи
Программа вычисления периметра треугольника по длинам его сторон. Язык реализации - Си. Архитектура - х86.
Во втором разделе описывается интерфейс программы. Под интерфейсом понимаются все данные, методы и средства, предназначенные для взаимодействия с внешними программами, пользователями, периферией (датчиками и исполнительными устройствами). Этот раздел удобно рассматривать с трех точек зрения:
Каждую из этих позиций можно разделить на подразделы с учетом сложности и типа описываемого взаимодействия. В случае программы расчета периметра треугольника удобно разделить входные/выходные данные на данные, подаваемые/возвращаемые в среду ОС, и на вводимые данные с клавиатуры/выводимые на экран сообщения.
2. Интерфейс
2.1. Входные данные
2.1.1. Данные, вводимые с клавиатуры
Три целых положительных числа, меньшие 100 - длины сторон в десятичной системе исчисления.
2.1.2. Параметры - данные, передаваемые из среды ОС.
Параметры, передаваемые из среды ОС, отсутствуют.
В качестве хранимых данных в разделе описания интерфейса рассматриваются все внутренние данные ПО, доступные извне во время выполнения. Например, программный модуль может иметь экспортируемую переменную, которая и должна быть описана в этом подразделе. Возможна и другая ситуация, когда модуль использует чью-то внешнюю (видимую извне) переменную.
Если спецификация описывает отдельный модуль, то удобно делить раздел описания интерфейсных требований на подразделы для каждой отдельной функции модуля, включающие входы/выходы, внутренние/внешние переменные функций. Когда язык программирования определен в требованиях к реализации, целесообразно указывать заголовки функций на выбранном языке.
При описании интерфейса часто приходится накладывать ограничения на диапазон входных значений. Во многих случаях эти ограничения могут быть обусловлены свойствами самого типа данных, передаваемых на вход программы. Но чаще они определяются особенностями алгоритма обработки вводимых значений. Например, нельзя делить на нуль.
В любом случае при описании ограничений на входные данные мы не можем гарантировать, что они безусловно будут соблюдаться пользователями системы. Но программа должна разрабатываться с их учетом, поэтому в функциональных требованиях стоит предусматривать соответствующую проверку входных значений.
Третий раздел спецификации содержит функциональные требования к ПО. Здесь должна быть подробно в виде требований описана вся функциональность ПО, включая все особые случаи. В нашем примере переданные числа могут оказаться не сторонами треугольника (не удовлетворять основному правилу треугольника), поэтому необходимо четко указать, что программа должна делать в таком случае.
Требования могут дополнительно комментироваться, однако каждое требование выделяется в тексте отдельным предложением со словом "должен" (должна, должно). Это позволяет четко отделить требования и комментарии/описания, а также однозначно пронумеровать все требования.
Требования к ПО должны отвечать на вопрос "что должна делать программа?". Следует четко различать вопросы "что должна делать программа?" и "как она должна это делать?". Вопрос "что?" - это определение функциональности, а вопрос "как?" - это определение алгоритма. Сам алгоритм относится уже к архитектуре системы, за исключением особых случаев, когда требуется реализация конкретных алгоритмов, например шифрование, расчет контрольной суммы, но даже в этих случаях следует минимально ограничивать реализацию. Итак, требования к ПО содержат в себе определение функциональности, а алгоритмы и детали реализации - это архитектура ПО.
В случаях, когда спецификация пишется для целой программы, требования можно разбить на разделы, отражающие основные функциональные области системы.
Например, для программы расчета периметра треугольника вся функциональность может быть разделена на следующие подразделы.
3. Функциональные требования
Для каждого функционального подраздела далее формулируются требования. Например, для проверки корректности данных можно записать следующие требования:
3.1. Программа должна выводить на экран приглашающее сообщение <ссылка на пункт о выводе сообщения> и вводить с клавиатуры три числа.
3.2. Программа должна проверить, являются ли введенные три числа длинами сторон треугольника согласно основному правилу треугольника (сумма двух любых сторон треугольника больше длины третьей стороны), и если введенные числа не соответствуют этому правилу, то надо вывести сообщение об ошибке <ссылка на пункт о выводе сообщения о соответствующей ошибке>.
3.3. Программа должна проверить, что каждое из введенных трех чисел меньше 100 и больше 0, и если введенные числа не принадлежат этому интервалу, то надо вывести сообщение об ошибке <ссылка на пункт о выводе сообщения о соответствующей ошибке>.
ПРИМЕЧАНИЕ. Заметим, что контроль диапазона значений может быть оговорен в функциональном разделе "Ввод данных", тогда пункт 3.3 может отсутствовать, но это значительно усложнит требование 3.1.
В дополнение к функциональным требованиям четвертый раздел спецификации содержит тест-требования. В тест-требованиях указывается, что необходимо проверить при тестировании. Или, другими словами, на основании каких внешних проявлений можно убедиться, что необходимая функциональность реализована в системе.
Сам раздел должен отражать основные области эквивалентности входов или области, в которых поведение программы будет схожим. Если выделить такие области и протестировать поведение программы для какого-либо одного значения из каждой области, то с большой вероятностью можно будет утверждать и о поведении программы на всей области определения ее входных значений.
Обычно удобно начинать тест-требование со слов "Проверить, что...". Например, для входов программы расчета периметра треугольника можно сформулировать следующее тест-требование:
Проверить, что если значение одного из входов больше или равно 100, то программа выдаст сообщение об ошибке, указанное в пункте <ссылка на пункт описания интерфейса с соответствующим сообщением об ошибке>.
Заметим, что подобное тест-требование существенно отличается от:
Проверить, что если значение любого из входов больше или равно 100, то программа выдаст сообщение об ошибке, указанное в пункте <ссылка на пункт описания интерфейса с соответствующим сообщением об ошибке>.
Ибо такая формулировка ТРЕБУЕТ, чтобы подобные значения, например 150, были при проверке последовательно заданы для каждой из сторон треугольника, а на самом деле еще и для всех пар сторон.
Дополнительно тест-требование может задавать некоторый приоритет функций, явно не прописанный в требованиях к программе. Так, при входных значениях 1, 2, 100 не вполне ясно, какие сообщения должна выдавать программа - о превышении максимальной длины (100) или о невозможности построить треугольник с этими сторонами (1+2<100). Тест-требование может гласить:
Проверить, что <описание ситуации>, оба сообщения <ссылка на пункты описания интерфейса с соответствующими сообщениями об ошибках> выводятся программой.
Составление тестов более подробно рассматривается в разделе 9 данного учебника.
После определения указанных разделов начинается процесс кодирования. Результат - код программы/функции/модуля - тоже может рассматриваться как пятый раздел спецификации. Для сложных программ рекомендуется начинать этот раздел с подраздела 5.1 описания алгоритма в виде блок-схемы или псевдокода и только потом переходить к подразделу 5.2 - коду программы.
Рассмотрим эту часть подробнее на элементарном примере. Пусть нам надо выбрать максимальное значение из трех заданных параметров A, B и C. Назовем эту задачу (функцию) MAX3(A, B, C).
(рис 2.3(а)) Схема решения задачи MAX3(A, B, C)
(рис 2.3(б)) Улучшенная схема решения задачи MAX3(4, B, C)
(рис 2.3(в)) Схема решения задачи MAX2(MAX, Р)
(рис 2.3(г)) Линейная схема решения задачи MAX3(A, B, C)
Одно из наиболее простых решений может быть изображено схемой (рис. 2.3(а)).
Такая схема достаточно проста для понимания, но ее дальнейшее развитие для 4-х, 5-и и более параметров выглядит весьма затруднительно. В этом смысле куда более привлекательным выглядит решение на рис. 2.3(б). Оно более соответствует идеологии структурного программирования и позволяет неограниченно наращивать количество обрабатываемых параметров.
Основу его составляет простой программный фрагмент, состоящий из элемента (рис. 2.3(в)) проверки условия: значение, ранее выбранное как максимальное, действительно является таковым по отношению к очередному проверяемому параметру. И если указанное условие нарушается, то запоминается новое максимальное значение.
Фактически элемент, изображенный на рис. 2.3(в), представляет собой функцию MAX2(MAX, X), которая из двух переданных ей элементов MAX и X выбирает большее значение и запоминает его в MAX.
Осознание полезности выделенной структуры в отдельную функцию на этапе проектирования архитектуры приводит к куда более простому программному коду основной функции MAX3(A, B, C) (рис. 2.3(г)). Это линейная последовательность трех операций.
Именно к подобной архитектуре должен стремиться разработчик на этапе проектирования.
При реализации сегментирование текста программы на отдельные процедуры позволяет легче читать и сопровождать (вносить необходимые изменения) код. При решении больших и сложных задач производится деление всего комплекса на программные модули, каждый из которых пишется и транслируется отдельно. Это позволяет разделить разработку между несколькими исполнителями.
После написания кода составляется шестой раздел - тест-план, который содержит в себе реальные данные и ожидаемые результаты для проверки программы согласно функциональным требованиям к задаче и тест-требованиям. Тест-план можно рассматривать как часть спецификации, но зачастую он является отдельным документом.
По тест-плану пишется тест-модуль (тест-драйвер), который автоматически выполняет ("прогоняет") все тесты из тест-плана. Задача тест-модуля - обеспечить возможность повторяемости тестов после исправления обнаруженных ошибок.
В процессе анализа обнаруженные несоответствия выявляются, и устраняется их причина. Это может быть ошибка реализации (кодирования), ошибка в требованиях, которые подлежат изменению. Наконец, это может быть ошибкой самих тестов, которые неправильно трактуют указанную в требованиях ситуацию.
Рассмотрим очень похожую на MAX3(A, B, C) задачу MAXNUMBER(A, B, C), в разделе 3 которой основное требование звучит следующим образом:
3.1. Программа должна определить номер параметра с максимальным значением.
(рис 2.4(а)) Схема решения задачи MAXNUMBER(A, B, C)
Этому рисунку соответствуют тесты, результаты которых очевидны, но не все:
MAXNUMBER(1, 2, 3) ответ 3
MAXNUMBER(1, 3, 2) ответ 2
MAXNUMBER(3, 1, 2) ответ 1
MAXNUMBER(1, 1, 1) ответ ?
Они дают значения, указывающие на 3-й, 2-й и 1-й параметры соответственно. Совсем не очевиден результат для случая, когда все три параметра имеют одинаковые значения.
Это как раз тот случай, когда следует вернуться к этапу постановки требований и добавить в функциональные требования еще один пункт:
3.2. При одинаковых значениях параметров программа должна выводить порядковый номер с наименьшим значением.
Тогда становится очевидным, что на входную тройку (1, 1, 1) ответ должен быть 1. На тестовый пример (1, 2, 2) - ответ 2. Получение такого решения потребует модификации первичной программной реализации. Строгие отношения неравенства > потребуется сменить на $$\geq$$, что приведет к схеме, представленной на рис. 2.4(б).
(рис 2.4(б)) Модифицированная схема решения задачи MAXNUMBER(A, B, C)
MAXNUMBER(1, 2, 3) ответ 3
MAXNUMBER(1, 3, 2) ответ 2
MAXNUMBER(3, 1, 2) ответ 1
MAXNUMBER(1, 1, 1) ответ 1
MAXNUMBER(1, 2, 2) ответ 2
Дополнительный тест на покрытие:
MAXNUMBER(1, 2, 2) ответ 3
Результат выполнения тест-модуля - отчет о прогоне теста тоже является частью спецификации программы. Тесты, которые нельзя провести в автоматическом режиме, проводятся вручную, и их результаты добавляются в отчет о прогоне теста. Желательно по завершении тестирования проверить не только то, что все требования к программе были выполнены, но и то, что проверен весь программный код и все ветви программы.
На рис. 2.4(б) выделена ветвь, которая не была пройдена (покрыта) первыми пятью тест-примерами (1, 2, 3), (1, 3, 2), (3, 1, 2), (1, 1, 1), (1, 2, 2). Поэтому специально для покрытия этой части кода добавлен еще один набор входных значений (2, 1, 3), также выдающий номер третьего параметра, но при вычислении которого была задействована не пройденная ранее ветвь программы. Более детально вопросы тестирования и покрытия кода будут рассмотрены позже.
Напишите программу, выполняющую кодирование входной строки перестановкой символов по правилу 2-3-1.
Соображения
Необходимо представить себе поведение программы в целом. Хотим ли мы получить программу кодирования одной единственной строки, или желателен диалоговый режим управления кодированием группы строк, каждая из которых вводится после некоторого приглашающего сообщения? Из общих соображений простоты общения и проверки работоспособности второй вариант (циклический ввод) представляется более предпочтительным.
Выводы
Первый раздел требований (спецификации) может быть сформулирован так:
1. Общее описание задачи.
Необходимо разработать программу, выполняющую ввод и преобразование строки символов путем их перестановки по правилу 2-3-1. Программа должна обрабатывать строки последовательно, каждый раз предупреждая пользователя о необходимости очередного ввода.
Соображения
Теперь необходимо принять решения по основным позициям внешнего проекта программы.
Каждый автор может принять собственное решение по этим пунктам. В любом случае свои решения в рамках лабораторного практикума необходимо согласовать с преподавателем.
Выводы
В данном варианте предлагается несколько усложненный вариант требований, предполагающий разбивку строки на слова и выполнение заданных правил перестановки только в пределах отдельного слова. В нем не накладывается сложных ограничений на разделитель слов. Им может быть многоточие или произвольная последовательность точек, запятых и пробелов.
2. Внешний проект.
2.1. Вход.
2.1.1. Входная строка должна вводиться с клавиатуры после вывода на экран приглашающего сообщения.
2.1.2. Входная строка представляет собой последовательность слов, разделенных (ограниченных) символами-разделителями ","; "."; " " (запятая, точка, пробел). Признаком конца ввода строки с клавиатуры является нажатие клавиши "Enter". Длина строки не должна превышать длины строки экрана (80 символов).
2.1.3. Слово входной строки может состоять из букв (русского и латинского алфавита) и/или цифр.
2.1.4. Первому слову в строке может предшествовать последовательность пробелов.
2.1.5. Признаком конца слова является любой символ-ограничитель (см. 2.1.2). Последнее слово строки может не иметь за собой ограничителя.
2.1.6. Ввод пустой строки является указанием пользователя на необходимость закончить работу программы.
2.2. Вывод.
2.2.1. Сообщения программы. Сообщения программы выводятся с новой строки. Курсор после вывода устанавливается на новую строку.
2.2.1.1. "Введите строку для кодирования" - приглашающее сообщение программы. Указывает на необходимость ввода с клавиатуры входной строки.
2.2.1.2. "Работа закончена" - завершающее сообщение программы. Выводится после ввода пустой строки. Работа программы заканчивается.
2.2.1.3. "Ошибка во входной строке" - информационное сообщение программы. Выводится после ввода входной строки, не соответствующей пункту 2.1. Работа программы продолжается с ввода новой строки.
2.2.2. Результат.
2.2.2.1. Выходная строка представляет собой последовательность преобразованных слов, организованную (в смысле разделителей и ограничителей) идентично входной строке.
2.2.2.2. Преобразованные слова выходной строки получаются из соответствующих слов входной строки применением к ним процедуры кодирования.
2.2.2.3. При выводе на экран выходная строка располагается строго под входной (разделитель под разделителем, слово под словом).
3. Функция преобразования.
3.1. Преобразование входной строки. Преобразованию подвергаются только правильные строки.
3.1.1. Преобразование слов входной строки производится путем перестановки каждой тройки символов слова в порядке 2-3-1.
3.1.2. Если в слове количество символов не кратно трем, то преобразование последних символов слова должно производиться по сокращенной схеме.
3.1.2.1. Последние два символа переставляются в порядке 2-1.
3.1.2.1. Единственный последний символ слова остается на своем месте.
3.1.3. Символы-разделители (ограничители) слов остаются в выходной строке на тех же местах, которые они занимали во входной строке.
3.2. Контроль входной строки.
3.2.1. Входная строка считается правильной, если она соответствует требованиям, описанным в пункте 2.1.
3.2.2. Если обнаружено, что входная строка не соответствует пункту 2.1, то на экран (в стандартный поток вывода) должно выдаваться сообщение пункта 2.2.1.3 и снова должен запрашиваться ввод входной строки.
3.3. Вывод результата.
3.3.1. Перед ожиданием ввода строки программа должна вывести на экран (в стандартный поток вывода) сообщение пункта 2.2.1.1 и перевести курсор на новую строку для ввода строки.
3.3.2. Выходная строка должна выводиться строго под входной строкой.
3.3.3. После ввода пустой входной строки программа должна вывести на экран (в стандартный поток вывода) сообщение пункта 2.2.1.2 и завершить свою работу.
4. Требования по проверке функций программной реализации.
4.1. Проверить, что при правильном вводе строки производится ее преобразование в соответствии с п.п. 3.1.
4.1.1. В том числе проверить, что правильно обрабатывается строка, начинающаяся с пробелов.
4.1.2. В том числе проверить, что правильно обрабатывается строка, содержащая слова, длина которых не кратна трем.
4.1.3. В том числе проверить, что правильно обрабатывается (остается без изменения) строка, состоящая из одних разделителей.
4.2. Проверить, что при вводе пустой строки производится вывод сообщения п.п. 2.3.2 и выполнение программы заканчивается.
4.3. Проверить, что выводится сообщение п.п. 2.3.3 и повторяется приглашение к вводу как реакция программы на неправильный ввод строки.
4.3.1. Строка содержит символы, отличные от пробелов, перед первым словом.
4.3.2. В строке встретился недопустимый символ алфавита (недопустимый разделитель слов или недопустимый символ в слове).
4.3.3. Длина строки превышает 80 символов (не считая признака конца строки).
4.4. Проверить, что выходная строка располагается с начала строки экрана и строго под значением входной строки, в том числе при длине строки, строго равной 80 символам.
Замечания
В данном варианте требования по проверке функций программной реализации сгруппированы в соответствии с описанием интерфейса (раздел спецификации 2). В некоторых случаях удобнее разрабатывать и структурировать требования по проверке в соответствии с описанием функций проектируемой системы (раздел спецификации 3).
Соображения
Работа над программной реализацией должна начинаться с проектирования основной последовательности действий и/или основных информационных объектов, подлежащих обработке. Последнее предпочтительней, так как дает хорошее основание к модульной декомпозиции программы. Если проще представить себе процедурную форму описания, то, записав последовательность проектируемых действий в виде предложений естественного языка, можно затем проанализировать глагольные группы и существительные. Существительные, особенно подлежащее, часто являются хорошими кандидатами для информационных объектов. Глаголы - кандидаты в процедуры (операции над объектами). Например, в нашем случае:
Даже самый простой предварительный анализ подобного описания позволяет нам выделить основной объект "входную строку" и список действий: "ввести", "преобразовать", а также операцию "проверка состояния - строка пустая". Если продолжать декомпозицию дальше, то легко можно выделить объект "сообщение" и соответствующую ему операцию "вывести". Конечно, многие проектные решения определяются программистом на основании его собственного опыта, интуиции, но во всех случаях рекомендуется рассматривать и оценивать несколько вариантов. Например, форма представления строки - список в связном представлении или массив; параметр процедуры "вывести сообщение" - текст сообщения или его номер и т.п.
Выводы
Конечно, все сказанное выше применимо только при разработке достаточно простых задач, объем документации которых не превышает нескольких десятков страниц. В случае выполнения коллективной работы над большим программным комплексом (десятки и сотни тысяч строк программного кода) должны применяться более сложные процедуры и приемы организации и хранения документации, взаимодействия разработчиков.
Созданный специально для встроенных систем, ГОСТ Р 51904-2002 "Программное обеспечение встроенных систем. Общие требования к разработке и документированию" регламентирует общие требования к разработке и документированию программного обеспечения. Во многом этот ГОСТ повторяет общеизвестные международные стандарты типа DO-178B, принятые при сертификации авиационного встроенного программного обеспечения.
Одним из принципиальных моментов является использование не водопадной модели жизненного цикла проекта, выделяющей его отдельные стадии (этапы), а процессной модели. Таким образом, в рамках ГОСТ Р 51904-2002 и DO-178B программный проект и производство программного продукта рассматриваются как совокупность параллельно текущих и взаимодействующих процессов.
В документе определяются шесть основных процессов программного проекта (рис. 2.5), из которых три можно отнести к производственным: планирование, разработка и верификация, а три - к поддерживающим: обеспечение качества, взаимодействие с сертифицирующим органом и управление конфигурациями. При этом разработка рассматривается как совокупность процессов определения требований, проектирования, кодирования и интеграции ПО. А одним из принципиальных свойств документации декларируется трассируемость.
(рис 2.5) Основные и поддерживающие процессы разработки
Трассируемость должна обеспечивать прослеживаемость того:
Как правило, трассируемость реализуется в виде указателей (опорных точек, якорей) и ссылок. Например, каждому требованию присваивается свой уникальный номер - его указатель, а в тесте, проверяющем реализацию этого требования, ставится ссылка на этот номер.
Прослеживание трассируемости должно обеспечивать проверку того, что:
Одним из ключевых вопросов, определяющих требования к документированию проекта в рамках данного стандарта, является понятие критичности отказов системы, которые предлагается классифицировать по следующим категориям.
Категория A - катастрофическая: отказная ситуация, препятствующая безопасному функционированию объекта управления.
Категория B - опасная/критическая: отказная ситуация, приводящая к уменьшению возможностей объекта управления или способности персонала справиться с неблагоприятными эксплуатационными режимами, при которых возникают:
Категория C - существенная: отказная ситуация, приводящая к снижению возможностей объекта управления или способности персонала справиться с неблагоприятными эксплуатационными режимами, при которых могут возникать, например, большое снижение гарантийных резервов или функциональных возможностей, перегрузки или условия, вызывающие ухудшение работоспособности персонала.
Категория D - несущественная: отказная ситуация, незначительно уменьшающая безопасность объекта и требующая действий персонала, которые осуществимы в пределах их возможностей. Несущественная отказная ситуация может включать в себя, например, незначительное уменьшение гарантийных резервов или функциональных возможностей, незначительное увеличение рабочей нагрузки персонала или некоторое неудобство для персонала.
Одним из ключевых вопросов разработки является понятие жизненного цикла. При этом процесс жизненного цикла программного обеспечения рассматривается как совокупность процессов планирования и разработки, объединяемых и взаимодействующих посредством интеграционных процессов.
Задачей процесса планирования является определение и координация операций процесса разработки и интеграционных процессов. Задачей процесса разработки является собственно выпуск программного продукта. А интеграционные процессы обеспечивают корректность, целостность и доверие к данным разработки.
Различные программные компоненты в плане разработки могут иметь различные жизненные циклы. Возможный пример иллюстрируется рисунком 1.5. Так, компонента 1 проходит в процессе реализации типичный жизненный цикл, а компонента 2 минует фазу проектирования, что может быть осуществлено из-за ее структурной простоты, позволяющей произвести кодирование прямо на основании сформулированных требований. В свою очередь, компонента 3, являющаяся заимствованным программным кодом, сразу после определения требований может быть вовлечена в процесс интеграции.
Наиболее сложный пример представлен жизненным циклом компоненты 4. При этом предполагается, что первичные требования реализуются и исследуются. Затем происходит уточнение требований, реализация нового прототипа и повторная интеграция, по итогам которой формируются окончательные требования. Завершающая стадия включает проектирование, кодирование и окончательную интеграцию. Таким образом, компонента 4 проходит две фазы прототипа перед финальной фазой реализации.
При определении жизненного цикла программного обеспечения должны быть заданы критерии начала и завершения каждой процедуры процесса. Другими словами, должно быть сформулировано условие, выполнение которого по отношению ко входным данным процедуры позволяет решить вопрос о возможности ее начала. Кроме того, должно быть сформулировано условие, анализ которого по отношению к выходу процедуры позволяет судить о том, что процедура завершена.
Задачи процесса планирования включают в себя:
Таблицы - приложения к ГОСТу дают представление о составе документов, которые должны быть разработаны и находиться под управлением процесса планирования. Там же определяется уровень (категория) конфигурационного управления соответствующей документацией.
Для уровней критичности A, B и C требования по составу документов идентичны, а для разработки программного обеспечения, относящегося к уровню D, они значительно упрощены. Так, для уровня D не являются обязательными определение критериев перехода от одной процедуры жизненного цикла к другой, фиксация инструментальных средств, разработка стандартов. Принципиально необходимым считается только определение процедур интеграционных процессов и процессов разработки программного обеспечения.
В свою очередь, требования к конфигурационному управлению документами процесса планирования идентичны для уровней A и B, но упрощены для программных проектов уровня C и D.
Процедуры процесса разработки включают в себя:
В процессе планирования должны быть разработаны планы (процедуры) сертификации, разработки программного обеспечения, верификации, управления конфигурациями и обеспечения качества. Все эти процедуры оказываются завязаны по общим данным так, что выходы одних являются входами для других или служат своего рода обратной связью, позволяющей вырабатывать необходимые корректирующие воздействия.
При планировании должны быть решены вопросы определения инструментального и методического обеспечения процессов жизненного цикла, организации коллектива проекта и процедур гарантии качества.
При этом можно упрощенно рассматривать процесс разработки как процесс последовательной трансляции:
В процессе проектирования архитектуры обычно появляются дополнительные требования низкого уровня, часть из которых вообще не может быть напрямую ассоциирована с требованиями высокого уровня. Однако в большинстве случаев прослеживаемость проектных решений сверху вниз существует и должна быть обеспечена средствами трассируемости документации программного проекта (составная часть средств управления конфигурациями).
Состав требований к процессу разработки не зависит от уровня критичности программного обеспечения, вариации уровней требований предусмотрены только для процедур конфигурационного управления, которые могут быть ослаблены для проектов категорий C и D по отношению к документам, описывающим архитектуру (проекта) программного обеспечения.
Процесс верификации программного обеспечения - это не просто тестирование. Тестирование не может показать отсутствие необходимой функциональности. Процедуры процесса верификации должны обеспечивать:
Средства проверки соответствий могут быть различны: логический анализ, структурный анализ, формальные инспекции, тестирование. В процессе планирования должны быть определены процедуры и методы верификации, применяемые на различных шагах процесса разработки к различным видам документов.
При доказательстве соответствия требований одного уровня другим чаще всего используются различные виды анализа, в том числе в форме формальной инспекции. Для верификации программного кода обычно проводят тестирование.
В зависимости от уровня критичности программного обеспечения в ГОСТ Р 51904-2002 устанавливаются различные уровни детальности проверки программного кода в процессе верификации:
a) проверка того, что все требования к программному обеспечению реализованы (100%-е покрытие требований в процессе тести-рования);
b) проверка того, что выполнено требование (а) и при этом все команды программного кода были выполнены в процессе тестирования (100%-ное покрытие кода в процессе тестирования);
c) проверка того, что выполнено требование (b) и при этом все ветви программного кода были выполнены в процессе тестирования (100%-ное покрытие ветвей программного кода в процессе тестирования);
d) проверка того, что выполнено требование (с) и при этом все условия разветвления программного кода были независимо проверены в процессе тестирования.
Очевидно, что требование (а) полностью ориентировано на тестирование программного обеспечения как "черного ящика". Другими словами, исследователь программного кода при этом рассматривает объект исследования только снаружи. Он оказывает входные воздействия, определяемые требованиями, и наблюдает значения на выходе, сравнивая их с ожидаемыми (вытекающими из требований). Никаких сведений о внутреннем устройстве (структуре и особенностях реализации) программного кода при таком подходе не должно использоваться.
При выполнении тестирования, соответствующего уровням требований (b) и (с), в ряде случаев удается оставаться в рамках концепции "черного ящика", по крайней мере, на этапе проверки требований. При таком подходе считается, что ничего не известно о внутреннем устройстве программы. Все заключения о ее правильном или неправильном поведении делаются на основе анализа ее внешних, наблюдаемых свойств.
Большинство сред поддержки тестирования (эмуляторов, отладчиков) позволяют произвести сбор покрытий программного кода и предоставить необходимую для анализа статистику. Но выявление причин недостаточного уровня покрытия требует сопоставления функциональных требований и способа их реализации в программном коде. По меньшей мере исследованию подвергается граф управления программы.
Поэтому выполнение тестирования по уровням требований (b) и (c), как правило, можно рассматривать в рамках концепции "серого ящика". Такой подход предполагает использование при исследовании объекта некоторых свойств его структуры. Но надо заметить, что эти сведения должны привлекаться только для анализа причин непокрытия кода. Ни в коем случае они не должны использоваться для прогнозирования ожидаемой реакции программы.
Причинами выявленного непокрытия могут быть как недокументированные свойства программного кода ("закладки", "баги", "мертвый код"), так и неполная трактовка (отображение в тесты) требований к программному коду со стороны тестировщика. В последнем случае в процедуру тестирования должны быть добавлены дополнительные тесты.
Одним из важнейших поддерживающих процессов является процесс конфигурационного управления. Основная задача процесса управления конфигурациями - обеспечение гарантии того, что организация-разработчик имеет все необходимые данные для подтверждения факта соответствия произведенного продукта требованиям.
Управление конфигурациями можно определить как процесс, с помощью которого руководство проекта имеет возможность на постоянной основе идентифицировать, устанавливать связи, сопровождать и управлять различными компонентами проекта. Этот процесс гарантирует целостность компонент и прослеживаемость всех изменений, возникающих в любой момент жизненного цикла проекта.
Базовым понятием процесса является (Configuration Item) объект (Элемент) конфигурационного управления (ОКУ). Под объектами конфигурационного управления могут пониматься все основные результаты деятельности проекта. Такие результаты идентифицируются и контролируются с помощью процесса управления конфигурациями. Объектами конфигурационного управления могут быть элементы аппаратуры, программы, документация, процедуры и материалы обучения, средства обслуживания и т.д. В целях идентификации объектам конфигурационного управления могут быть присвоены номера.
Еще один термин, используемый в процессе конфигурационного управления - базовая конфигурация (Baseline). Под базовой конфигурацией (БК) понимается объект конфигурационного управления (отдельный элемент или совокупность элементов), который прошел процедуру утверждения и может быть изменен только в рамках процедуры управления изменениями.
Базовая конфигурация - это своего рода фотоснимок, "замороженная ситуация" требований, спецификаций или результатов, находящихся в разработке. Она может быть представлена документом или набором документов. Создание базовой конфигурации - обычно фиксация некоторого условия, возникающего при завершении каждого из основных шагов процесса разработки.
Базовая конфигурация может состоять из совокупности однородных документов, например совокупность требований, коды совокупности программных модулей. Но базовая конфигурация может состоять и из совокупности разнородных по своей сути ОКУ, например требования и соответствующий программный код, тест-план, результаты прогона тест-плана.
Таким образом, процесс конфигурационного управления призван обеспечивать следующее:
Табл. 2.1 дает представление о составе документов, которые должны быть разработаны и находиться под контролем процесса управления конфигурациями. Там же определяется уровень (категория) конфигурационного управления соответствующей документацией.
| Цель процесса управления конфигурацией | Ссылка на раздел | КК1 | КК2 |
|---|---|---|---|
| Идентификация конфигурации | 9.2.1 | * | * |
| Базовая линия | 9.2.3 а), б), в), г), д) | * | |
| Трассируемость | 9.2.3 е), ж) | * | * |
| Отчетность о дефектах | 9.2.4 | * | |
| Контроль изменений - целостность и идентификация | 9.2.5 а), б) | * | * |
| Контроль изменений - трассируемость | 9.2.5 в), г), д) | * | |
| Просмотр изменений | 9.2.6 | * | |
| Отчетность о состоянии конфигурации | 9.2.7 | * | |
| Получение документа из архива | 9.2.8 а) | * | * |
| Защита от несанкционированных изменений | 9.2.8 б1) | * | * |
| Выбор носителей, обновление, копирование | 9.2.8 б2), б 3), б4), в) | * | |
| Выпуск версии | 9.2.8 г) | * | |
| Хранение данных | 9.2.8 д) | * | * |
Обозначения:
* - цель должна быть удовлетворена для документов данной категории; пробел - удовлетворение цели на усмотрение разработчика.
Различаются два уровня конфигурационного управления документацией: КК1 и КК2. Уровень КК1 предполагает полный контроль над конфигурациями проекта. Уровень КК2 допускает отсутствие большой части элементов и процедур. При КК2 обязательными остаются процедура идентификации, прослеживаемость (трассируемость), управление изменениями, доступность и сохранность данных с соблюдением ограничений доступа (предотвращение несанкционированных изменений).
Синхронизацию всех процессов должен гарантировать процесс обеспечения качества программной разработки.
Обеспечение (гарантия) качества - это совсем не тестирование и не верификация результата. Основная задача процесса (Software Quality Assurance Process) - наблюдение за соблюдением стандартов проекта. При этом записи, ведущиеся в рамках процесса (quality records), являются составной частью документации проекта и попадают под конфигурационное управление.
При выполнении проекта процесс обеспечения качества должен давать гарантии того, что все необходимые стандарты разработаны в соответствии с требованиями, все процедуры жизненного цикла выполняются в соответствии со стандартами, а все отклонения от утвержденных планов и стандартов выявляются, рассматриваются в утвержденном порядке и устраняются. Одним из механизмов процесса является аудит. Заметим, что задача аудита, в отличие от задачи верификации, - поиск соответствия. Верификация и, в частности, тестирование ориентированы на выявление несоответствий. При аудите производится поиск соответствий, а обнаруженные несоответствия фиксируются (один из видов записей процесса) и предоставляются на рассмотрение руководству проекта. При этом одной из задач процесса является предотвращение возможных несоответствий.
Таким образом, можно рассматривать процесс обеспечения качества как процесс-наблюдатель за другими процессами. Но это не пассивный наблюдатель, фиксирующий нарушения. Процесс обеспечения качества призван активно участвовать в разработке стандартов и процедур проекта, обеспечивая выполнение требований заказчика и ГОСТ Р 51904-2002.
Дополнительно в документе определяются требования к используемому инструментарию, документации по заимствованным компонентам, правила сертификации и т.п.
Все приказы отдавайте устно. Не оставляйте записей и документов, которые могут обернуться против вас.
Технология создания ПО требует выполнить определенные работы, связанные с составлением проектной документации. Новичкам часто кажется, что написание спецификаций является не очень важной частью процесса разработки или даже ненужной тратой времени. Однако это не так, документация проекта содержит в себе все основные мысли, решения, принятые в ходе бесконечных обсуждений, договоренности и требования заказчика. Кроме того, четкая фиксация информации помогает выявить неточности и противоречия, а также определить ясную и четкую политику, которая может стать доступной всему коллективу в документальном виде. Сама же документация становится достаточно формальным описанием будущей системы и позволяет впоследствии проводить верификацию.
В ходе каждого процесса (этапа) разработки формируется определенный набор документов (выходные данные), которые являются входными данными для следующих процессов (этапов). Практически каждый документ базируется на ранее созданных документах и включает в себя дополнительные уточнения описания конечного продукта или связанных с его построением процессов.
В свое время Г. Майерсом [5] была предложена модель разработки ПО как модель трансляции одного описания программного продукта в другое. Если встать на эту позицию, то надо предполагать, что первичные требования заказчика - описание продукта на языке очень высокого уровня. Коллектив разработчиков просто транслирует его поэтапно, постепенно доводя это описание до уровня машинной реализации. При этом, кроме формально исполняемых документов - программ, создаются и другие документы - эксплуатационные. Часть из них - инструкции по эксплуатации исполняют люди.
Таким образом, для процесса "Разработка требований" можно определить следующий набор документов:
Для процесса "Проектирование" характерны следующие документы:
Процесс "Реализация" формирует на выходе код программы.
"Тестирование" включает в себя создание таких документов, как:
На рис. 2.1 приведены основные документы и результаты, получаемые в ходе разработки ПО. Здесь рассматривается обобщенная модель и обобщенные типы документов. Из соображений компактности изображения названия закодированы латинскими буквами. В реальной разработке их количество существенно больше, часто возникают ситуации замены приведенных документов другими типами, добавления новых видов документов или невыполнения части этапов при разработке.
На начальном этапе формируется общее представление о потребностях в будущем продукте и ставится задача разработки (SOW - Statement Of Work). Это обычно и есть первичное описание необходимого продукта.
(рис 2.1) Основные документы, создаваемые при разработке ПО
Далее идет разработка системных требований, т.е. требований ко всему разрабатываемому изделию, детально определяющих все свойства будущего продукта (SYS - System requirements). Далее обычно удается определить, какую часть работы в системе будет выполнять аппаратура, какую - программное обеспечение, а какую - человек.
Поэтому на основе SYS-документации составляются требования к ПО (SRD - Software Requirements Document), которые детализируют все требования SYS, относящиеся к программной части. Эти требования также являются частью конечного продукта. Основная задача требований к ПО - определить, что должна делать система, а не как она это будет делать. Параллельно идет уточнение требований к аппаратной части (HRD - Hardware Requirements Document) и разработка организационных требований (ORD), включающих в себя описание необходимых документов, и установление протокола взаимодействия пользователей с программной системой.
На основе требований к ПО вся программная система разбивается на набор функциональных областей, требования к каждой области детализируются в документе, описывающем архитектуру программной системы. Здесь же описываются интерфейсы функциональных областей, и этот документ нужно рассматривать как часть конечного продукта.
Каждая функциональная область делится на модули, которые в свою очередь могут снова делиться на модули. Требования к модулю, описание его работы и его интерфейсы приводятся в документе DDD (Detailed Design Description), который также входит в состав конечного продукта. Здесь уже можно определять, как должен работать модуль, однако и тут степень детализации может быть разной, и часть алгоритмических решений может быть оставлена кодировщику.
Под интерфейсом модуля (или функциональной области) понимаются все функции, типы, константы и переменные, используемые для взаимодействия модуля с другими модулями, т.е. все, что связывает модуль с "внешним миром".
Таким образом, возможно отделение реализации модуля от "внешнего мира". Для других модулей будет доступен только интерфейс, а про реализацию они могут ничего не знать. Если реализация некоторого объекта недоступна для других модулей, а доступ происходит лишь на уровне экспортируемых модулем функций, то можно говорить об абстрактном или скрытом типе. Использование абстрактных типов упрощает разработку и повышает надежность общей системы.
На основе описаний модулей выполняется кодирование и интеграция уже с использованием особенностей выбранного языка программирования. Результат этого этапа - исполняемая программа (загрузочный модуль), соответствующая требованиям к ПО.
После разработки кода программы начинается этап тестирования (верификации), заключающийся в проверке соответствия поведения кода отдельных модулей DDD-требованиям, собранных функциональных областей - требованиям к функциональным областям (FA - Functional Areas TEST), собранной в целом системе функциональных областей - SRD-требованиям к ПО. Готовая система тестируется совместно с аппаратной частью, определенной в HRD, и в совокупности проверяется соответствие требованиям к системе SYS. На каждом этапе формируются отчеты о тестировании (или отчеты о прогоне тестов). Иногда такие отчеты могут составлять часть конечного продукта или входить в состав документации, предоставляемой сертифицирующему органу.
Необходимо заметить, что все этапы разработки не являются независимыми, а наоборот, постоянно происходит "трансляция" одного описания в другое - более детальное. При этом на каждом этапе разработки требований идет проверка соответствия текущих требований требованиям, уже определенным в предыдущем документе, т.е. соответствие SYS - SRD, соответствие SRD архитектуре программной системы и т.д. Часто ведется трассировка требований, т.е. для любого требования последующего документа можно проследить требование, из которого оно было определено в предшествующем документе. При этом первичными требованиями является SYS.
Ф. Брукс [10] дает следующую оценку трудоемкости для основных этапов ЖЦ разработки ПО:
Считая, что оба вида тестирования относятся к (I) интеграционному процессу, получаем диаграмму распределения трудозатрат, приведенную на рис. 2.2
(рис 2.2) Распределение трудозатрат
Из приведенной оценки и необходимых для разработки системы документов видно, что процесс кодирования является не самым большим и не самым трудоемким этапом разработки ПО, однако ключевым. Именно в ходе кодирования создается конечный продукт, ради получения которого и проводятся все вышеописанные действия.
Отметим важное свойство программного текста - пишется один раз (на этапе кодирования), а читается много раз как на всех последующих этапах разработки, так и при внесении изменений в код. Поэтому "читабельность" - важнейшая черта программного текста.
В случае несложной программы, модуля или функции всю документацию можно объединить в общую спецификацию программы, описывающую требования к ПО, его интерфейс, тест-требования и некоторые другие аспекты.
Стоит отметить, что спецификация или ее отдельные разделы могут проходить инспекции, дорабатываться, утверждаться, поэтому на работу с этим документом накладываются различные ограничения. Как минимум необходимо, чтобы в спецификации были указаны ее автор и текущая версия. Для отслеживания всех действий рекомендуется вести таблицу изменений, отмечать в ней, кто, когда, что и почему изменил, и указывать номер новой версии. Пример таблицы изменений можно увидеть в приложении Б.
Спецификация делится на разделы, соответствующие разным документам при разработке ПО. Схема написания спецификации, рекомендованной для данного учебного курса, полностью приведена в приложении А.
Первый раздел - это краткое описание конечного продукта (аналог SOW). Описание должно быть достаточно кратким, но давать четкое понимание назначения продукта. Здесь же следует указывать язык реализации и архитектуру целевой машины как самые общие требования к реализации. Например, если рассмотреть программу, вычисляющую периметр треугольника по длинам его сторон, то краткое описание может иметь следующий вид.
1. Общее описание задачи
Программа вычисления периметра треугольника по длинам его сторон. Язык реализации - Си. Архитектура - х86.
Во втором разделе описывается интерфейс программы. Под интерфейсом понимаются все данные, методы и средства, предназначенные для взаимодействия с внешними программами, пользователями, периферией (датчиками и исполнительными устройствами). Этот раздел удобно рассматривать с трех точек зрения:
Каждую из этих позиций можно разделить на подразделы с учетом сложности и типа описываемого взаимодействия. В случае программы расчета периметра треугольника удобно разделить входные/выходные данные на данные, подаваемые/возвращаемые в среду ОС, и на вводимые данные с клавиатуры/выводимые на экран сообщения.
2. Интерфейс
2.1. Входные данные
2.1.1. Данные, вводимые с клавиатуры
Три целых положительных числа, меньшие 100 - длины сторон в десятичной системе исчисления.
2.1.2. Параметры - данные, передаваемые из среды ОС.
Параметры, передаваемые из среды ОС, отсутствуют.
В качестве хранимых данных в разделе описания интерфейса рассматриваются все внутренние данные ПО, доступные извне во время выполнения. Например, программный модуль может иметь экспортируемую переменную, которая и должна быть описана в этом подразделе. Возможна и другая ситуация, когда модуль использует чью-то внешнюю (видимую извне) переменную.
Если спецификация описывает отдельный модуль, то удобно делить раздел описания интерфейсных требований на подразделы для каждой отдельной функции модуля, включающие входы/выходы, внутренние/внешние переменные функций. Когда язык программирования определен в требованиях к реализации, целесообразно указывать заголовки функций на выбранном языке.
При описании интерфейса часто приходится накладывать ограничения на диапазон входных значений. Во многих случаях эти ограничения могут быть обусловлены свойствами самого типа данных, передаваемых на вход программы. Но чаще они определяются особенностями алгоритма обработки вводимых значений. Например, нельзя делить на нуль.
В любом случае при описании ограничений на входные данные мы не можем гарантировать, что они безусловно будут соблюдаться пользователями системы. Но программа должна разрабатываться с их учетом, поэтому в функциональных требованиях стоит предусматривать соответствующую проверку входных значений.
Третий раздел спецификации содержит функциональные требования к ПО. Здесь должна быть подробно в виде требований описана вся функциональность ПО, включая все особые случаи. В нашем примере переданные числа могут оказаться не сторонами треугольника (не удовлетворять основному правилу треугольника), поэтому необходимо четко указать, что программа должна делать в таком случае.
Требования могут дополнительно комментироваться, однако каждое требование выделяется в тексте отдельным предложением со словом "должен" (должна, должно). Это позволяет четко отделить требования и комментарии/описания, а также однозначно пронумеровать все требования.
Требования к ПО должны отвечать на вопрос "что должна делать программа?". Следует четко различать вопросы "что должна делать программа?" и "как она должна это делать?". Вопрос "что?" - это определение функциональности, а вопрос "как?" - это определение алгоритма. Сам алгоритм относится уже к архитектуре системы, за исключением особых случаев, когда требуется реализация конкретных алгоритмов, например шифрование, расчет контрольной суммы, но даже в этих случаях следует минимально ограничивать реализацию. Итак, требования к ПО содержат в себе определение функциональности, а алгоритмы и детали реализации - это архитектура ПО.
В случаях, когда спецификация пишется для целой программы, требования можно разбить на разделы, отражающие основные функциональные области системы.
Например, для программы расчета периметра треугольника вся функциональность может быть разделена на следующие подразделы.
3. Функциональные требования
Для каждого функционального подраздела далее формулируются требования. Например, для проверки корректности данных можно записать следующие требования:
3.1. Программа должна выводить на экран приглашающее сообщение <ссылка на пункт о выводе сообщения> и вводить с клавиатуры три числа.
3.2. Программа должна проверить, являются ли введенные три числа длинами сторон треугольника согласно основному правилу треугольника (сумма двух любых сторон треугольника больше длины третьей стороны), и если введенные числа не соответствуют этому правилу, то надо вывести сообщение об ошибке <ссылка на пункт о выводе сообщения о соответствующей ошибке>.
3.3. Программа должна проверить, что каждое из введенных трех чисел меньше 100 и больше 0, и если введенные числа не принадлежат этому интервалу, то надо вывести сообщение об ошибке <ссылка на пункт о выводе сообщения о соответствующей ошибке>.
ПРИМЕЧАНИЕ. Заметим, что контроль диапазона значений может быть оговорен в функциональном разделе "Ввод данных", тогда пункт 3.3 может отсутствовать, но это значительно усложнит требование 3.1.
В дополнение к функциональным требованиям четвертый раздел спецификации содержит тест-требования. В тест-требованиях указывается, что необходимо проверить при тестировании. Или, другими словами, на основании каких внешних проявлений можно убедиться, что необходимая функциональность реализована в системе.
Сам раздел должен отражать основные области эквивалентности входов или области, в которых поведение программы будет схожим. Если выделить такие области и протестировать поведение программы для какого-либо одного значения из каждой области, то с большой вероятностью можно будет утверждать и о поведении программы на всей области определения ее входных значений.
Обычно удобно начинать тест-требование со слов "Проверить, что...". Например, для входов программы расчета периметра треугольника можно сформулировать следующее тест-требование:
Проверить, что если значение одного из входов больше или равно 100, то программа выдаст сообщение об ошибке, указанное в пункте <ссылка на пункт описания интерфейса с соответствующим сообщением об ошибке>.
Заметим, что подобное тест-требование существенно отличается от:
Проверить, что если значение любого из входов больше или равно 100, то программа выдаст сообщение об ошибке, указанное в пункте <ссылка на пункт описания интерфейса с соответствующим сообщением об ошибке>.
Ибо такая формулировка ТРЕБУЕТ, чтобы подобные значения, например 150, были при проверке последовательно заданы для каждой из сторон треугольника, а на самом деле еще и для всех пар сторон.
Дополнительно тест-требование может задавать некоторый приоритет функций, явно не прописанный в требованиях к программе. Так, при входных значениях 1, 2, 100 не вполне ясно, какие сообщения должна выдавать программа - о превышении максимальной длины (100) или о невозможности построить треугольник с этими сторонами (1+2<100). Тест-требование может гласить:
Проверить, что <описание ситуации>, оба сообщения <ссылка на пункты описания интерфейса с соответствующими сообщениями об ошибках> выводятся программой.
Составление тестов более подробно рассматривается в разделе 9 данного учебника.
После определения указанных разделов начинается процесс кодирования. Результат - код программы/функции/модуля - тоже может рассматриваться как пятый раздел спецификации. Для сложных программ рекомендуется начинать этот раздел с подраздела 5.1 описания алгоритма в виде блок-схемы или псевдокода и только потом переходить к подразделу 5.2 - коду программы.
Рассмотрим эту часть подробнее на элементарном примере. Пусть нам надо выбрать максимальное значение из трех заданных параметров A, B и C. Назовем эту задачу (функцию) MAX3(A, B, C).
(рис 2.3(а)) Схема решения задачи MAX3(A, B, C)
(рис 2.3(б)) Улучшенная схема решения задачи MAX3(4, B, C)
(рис 2.3(в)) Схема решения задачи MAX2(MAX, Р)
(рис 2.3(г)) Линейная схема решения задачи MAX3(A, B, C)
Одно из наиболее простых решений может быть изображено схемой (рис. 2.3(а)).
Такая схема достаточно проста для понимания, но ее дальнейшее развитие для 4-х, 5-и и более параметров выглядит весьма затруднительно. В этом смысле куда более привлекательным выглядит решение на рис. 2.3(б). Оно более соответствует идеологии структурного программирования и позволяет неограниченно наращивать количество обрабатываемых параметров.
Основу его составляет простой программный фрагмент, состоящий из элемента (рис. 2.3(в)) проверки условия: значение, ранее выбранное как максимальное, действительно является таковым по отношению к очередному проверяемому параметру. И если указанное условие нарушается, то запоминается новое максимальное значение.
Фактически элемент, изображенный на рис. 2.3(в), представляет собой функцию MAX2(MAX, X), которая из двух переданных ей элементов MAX и X выбирает большее значение и запоминает его в MAX.
Осознание полезности выделенной структуры в отдельную функцию на этапе проектирования архитектуры приводит к куда более простому программному коду основной функции MAX3(A, B, C) (рис. 2.3(г)). Это линейная последовательность трех операций.
Именно к подобной архитектуре должен стремиться разработчик на этапе проектирования.
При реализации сегментирование текста программы на отдельные процедуры позволяет легче читать и сопровождать (вносить необходимые изменения) код. При решении больших и сложных задач производится деление всего комплекса на программные модули, каждый из которых пишется и транслируется отдельно. Это позволяет разделить разработку между несколькими исполнителями.
После написания кода составляется шестой раздел - тест-план, который содержит в себе реальные данные и ожидаемые результаты для проверки программы согласно функциональным требованиям к задаче и тест-требованиям. Тест-план можно рассматривать как часть спецификации, но зачастую он является отдельным документом.
По тест-плану пишется тест-модуль (тест-драйвер), который автоматически выполняет ("прогоняет") все тесты из тест-плана. Задача тест-модуля - обеспечить возможность повторяемости тестов после исправления обнаруженных ошибок.
В процессе анализа обнаруженные несоответствия выявляются, и устраняется их причина. Это может быть ошибка реализации (кодирования), ошибка в требованиях, которые подлежат изменению. Наконец, это может быть ошибкой самих тестов, которые неправильно трактуют указанную в требованиях ситуацию.
Рассмотрим очень похожую на MAX3(A, B, C) задачу MAXNUMBER(A, B, C), в разделе 3 которой основное требование звучит следующим образом:
3.1. Программа должна определить номер параметра с максимальным значением.
(рис 2.4(а)) Схема решения задачи MAXNUMBER(A, B, C)
Этому рисунку соответствуют тесты, результаты которых очевидны, но не все:
MAXNUMBER(1, 2, 3) ответ 3
MAXNUMBER(1, 3, 2) ответ 2
MAXNUMBER(3, 1, 2) ответ 1
MAXNUMBER(1, 1, 1) ответ ?
Они дают значения, указывающие на 3-й, 2-й и 1-й параметры соответственно. Совсем не очевиден результат для случая, когда все три параметра имеют одинаковые значения.
Это как раз тот случай, когда следует вернуться к этапу постановки требований и добавить в функциональные требования еще один пункт:
3.2. При одинаковых значениях параметров программа должна выводить порядковый номер с наименьшим значением.
Тогда становится очевидным, что на входную тройку (1, 1, 1) ответ должен быть 1. На тестовый пример (1, 2, 2) - ответ 2. Получение такого решения потребует модификации первичной программной реализации. Строгие отношения неравенства > потребуется сменить на $$\geq$$, что приведет к схеме, представленной на рис. 2.4(б).
(рис 2.4(б)) Модифицированная схема решения задачи MAXNUMBER(A, B, C)
MAXNUMBER(1, 2, 3) ответ 3
MAXNUMBER(1, 3, 2) ответ 2
MAXNUMBER(3, 1, 2) ответ 1
MAXNUMBER(1, 1, 1) ответ 1
MAXNUMBER(1, 2, 2) ответ 2
Дополнительный тест на покрытие:
MAXNUMBER(1, 2, 2) ответ 3
Результат выполнения тест-модуля - отчет о прогоне теста тоже является частью спецификации программы. Тесты, которые нельзя провести в автоматическом режиме, проводятся вручную, и их результаты добавляются в отчет о прогоне теста. Желательно по завершении тестирования проверить не только то, что все требования к программе были выполнены, но и то, что проверен весь программный код и все ветви программы.
На рис. 2.4(б) выделена ветвь, которая не была пройдена (покрыта) первыми пятью тест-примерами (1, 2, 3), (1, 3, 2), (3, 1, 2), (1, 1, 1), (1, 2, 2). Поэтому специально для покрытия этой части кода добавлен еще один набор входных значений (2, 1, 3), также выдающий номер третьего параметра, но при вычислении которого была задействована не пройденная ранее ветвь программы. Более детально вопросы тестирования и покрытия кода будут рассмотрены позже.
Напишите программу, выполняющую кодирование входной строки перестановкой символов по правилу 2-3-1.
Соображения
Необходимо представить себе поведение программы в целом. Хотим ли мы получить программу кодирования одной единственной строки, или желателен диалоговый режим управления кодированием группы строк, каждая из которых вводится после некоторого приглашающего сообщения? Из общих соображений простоты общения и проверки работоспособности второй вариант (циклический ввод) представляется более предпочтительным.
Выводы
Первый раздел требований (спецификации) может быть сформулирован так:
1. Общее описание задачи.
Необходимо разработать программу, выполняющую ввод и преобразование строки символов путем их перестановки по правилу 2-3-1. Программа должна обрабатывать строки последовательно, каждый раз предупреждая пользователя о необходимости очередного ввода.
Соображения
Теперь необходимо принять решения по основным позициям внешнего проекта программы.
Каждый автор может принять собственное решение по этим пунктам. В любом случае свои решения в рамках лабораторного практикума необходимо согласовать с преподавателем.
Выводы
В данном варианте предлагается несколько усложненный вариант требований, предполагающий разбивку строки на слова и выполнение заданных правил перестановки только в пределах отдельного слова. В нем не накладывается сложных ограничений на разделитель слов. Им может быть многоточие или произвольная последовательность точек, запятых и пробелов.
2. Внешний проект.
2.1. Вход.
2.1.1. Входная строка должна вводиться с клавиатуры после вывода на экран приглашающего сообщения.
2.1.2. Входная строка представляет собой последовательность слов, разделенных (ограниченных) символами-разделителями ","; "."; " " (запятая, точка, пробел). Признаком конца ввода строки с клавиатуры является нажатие клавиши "Enter". Длина строки не должна превышать длины строки экрана (80 символов).
2.1.3. Слово входной строки может состоять из букв (русского и латинского алфавита) и/или цифр.
2.1.4. Первому слову в строке может предшествовать последовательность пробелов.
2.1.5. Признаком конца слова является любой символ-ограничитель (см. 2.1.2). Последнее слово строки может не иметь за собой ограничителя.
2.1.6. Ввод пустой строки является указанием пользователя на необходимость закончить работу программы.
2.2. Вывод.
2.2.1. Сообщения программы. Сообщения программы выводятся с новой строки. Курсор после вывода устанавливается на новую строку.
2.2.1.1. "Введите строку для кодирования" - приглашающее сообщение программы. Указывает на необходимость ввода с клавиатуры входной строки.
2.2.1.2. "Работа закончена" - завершающее сообщение программы. Выводится после ввода пустой строки. Работа программы заканчивается.
2.2.1.3. "Ошибка во входной строке" - информационное сообщение программы. Выводится после ввода входной строки, не соответствующей пункту 2.1. Работа программы продолжается с ввода новой строки.
2.2.2. Результат.
2.2.2.1. Выходная строка представляет собой последовательность преобразованных слов, организованную (в смысле разделителей и ограничителей) идентично входной строке.
2.2.2.2. Преобразованные слова выходной строки получаются из соответствующих слов входной строки применением к ним процедуры кодирования.
2.2.2.3. При выводе на экран выходная строка располагается строго под входной (разделитель под разделителем, слово под словом).
3. Функция преобразования.
3.1. Преобразование входной строки. Преобразованию подвергаются только правильные строки.
3.1.1. Преобразование слов входной строки производится путем перестановки каждой тройки символов слова в порядке 2-3-1.
3.1.2. Если в слове количество символов не кратно трем, то преобразование последних символов слова должно производиться по сокращенной схеме.
3.1.2.1. Последние два символа переставляются в порядке 2-1.
3.1.2.1. Единственный последний символ слова остается на своем месте.
3.1.3. Символы-разделители (ограничители) слов остаются в выходной строке на тех же местах, которые они занимали во входной строке.
3.2. Контроль входной строки.
3.2.1. Входная строка считается правильной, если она соответствует требованиям, описанным в пункте 2.1.
3.2.2. Если обнаружено, что входная строка не соответствует пункту 2.1, то на экран (в стандартный поток вывода) должно выдаваться сообщение пункта 2.2.1.3 и снова должен запрашиваться ввод входной строки.
3.3. Вывод результата.
3.3.1. Перед ожиданием ввода строки программа должна вывести на экран (в стандартный поток вывода) сообщение пункта 2.2.1.1 и перевести курсор на новую строку для ввода строки.
3.3.2. Выходная строка должна выводиться строго под входной строкой.
3.3.3. После ввода пустой входной строки программа должна вывести на экран (в стандартный поток вывода) сообщение пункта 2.2.1.2 и завершить свою работу.
4. Требования по проверке функций программной реализации.
4.1. Проверить, что при правильном вводе строки производится ее преобразование в соответствии с п.п. 3.1.
4.1.1. В том числе проверить, что правильно обрабатывается строка, начинающаяся с пробелов.
4.1.2. В том числе проверить, что правильно обрабатывается строка, содержащая слова, длина которых не кратна трем.
4.1.3. В том числе проверить, что правильно обрабатывается (остается без изменения) строка, состоящая из одних разделителей.
4.2. Проверить, что при вводе пустой строки производится вывод сообщения п.п. 2.3.2 и выполнение программы заканчивается.
4.3. Проверить, что выводится сообщение п.п. 2.3.3 и повторяется приглашение к вводу как реакция программы на неправильный ввод строки.
4.3.1. Строка содержит символы, отличные от пробелов, перед первым словом.
4.3.2. В строке встретился недопустимый символ алфавита (недопустимый разделитель слов или недопустимый символ в слове).
4.3.3. Длина строки превышает 80 символов (не считая признака конца строки).
4.4. Проверить, что выходная строка располагается с начала строки экрана и строго под значением входной строки, в том числе при длине строки, строго равной 80 символам.
Замечания
В данном варианте требования по проверке функций программной реализации сгруппированы в соответствии с описанием интерфейса (раздел спецификации 2). В некоторых случаях удобнее разрабатывать и структурировать требования по проверке в соответствии с описанием функций проектируемой системы (раздел спецификации 3).
Соображения
Работа над программной реализацией должна начинаться с проектирования основной последовательности действий и/или основных информационных объектов, подлежащих обработке. Последнее предпочтительней, так как дает хорошее основание к модульной декомпозиции программы. Если проще представить себе процедурную форму описания, то, записав последовательность проектируемых действий в виде предложений естественного языка, можно затем проанализировать глагольные группы и существительные. Существительные, особенно подлежащее, часто являются хорошими кандидатами для информационных объектов. Глаголы - кандидаты в процедуры (операции над объектами). Например, в нашем случае:
Даже самый простой предварительный анализ подобного описания позволяет нам выделить основной объект "входную строку" и список действий: "ввести", "преобразовать", а также операцию "проверка состояния - строка пустая". Если продолжать декомпозицию дальше, то легко можно выделить объект "сообщение" и соответствующую ему операцию "вывести". Конечно, многие проектные решения определяются программистом на основании его собственного опыта, интуиции, но во всех случаях рекомендуется рассматривать и оценивать несколько вариантов. Например, форма представления строки - список в связном представлении или массив; параметр процедуры "вывести сообщение" - текст сообщения или его номер и т.п.
Выводы
Конечно, все сказанное выше применимо только при разработке достаточно простых задач, объем документации которых не превышает нескольких десятков страниц. В случае выполнения коллективной работы над большим программным комплексом (десятки и сотни тысяч строк программного кода) должны применяться более сложные процедуры и приемы организации и хранения документации, взаимодействия разработчиков.
Созданный специально для встроенных систем, ГОСТ Р 51904-2002 "Программное обеспечение встроенных систем. Общие требования к разработке и документированию" регламентирует общие требования к разработке и документированию программного обеспечения. Во многом этот ГОСТ повторяет общеизвестные международные стандарты типа DO-178B, принятые при сертификации авиационного встроенного программного обеспечения.
Одним из принципиальных моментов является использование не водопадной модели жизненного цикла проекта, выделяющей его отдельные стадии (этапы), а процессной модели. Таким образом, в рамках ГОСТ Р 51904-2002 и DO-178B программный проект и производство программного продукта рассматриваются как совокупность параллельно текущих и взаимодействующих процессов.
В документе определяются шесть основных процессов программного проекта (рис. 2.5), из которых три можно отнести к производственным: планирование, разработка и верификация, а три - к поддерживающим: обеспечение качества, взаимодействие с сертифицирующим органом и управление конфигурациями. При этом разработка рассматривается как совокупность процессов определения требований, проектирования, кодирования и интеграции ПО. А одним из принципиальных свойств документации декларируется трассируемость.
(рис 2.5) Основные и поддерживающие процессы разработки
Трассируемость должна обеспечивать прослеживаемость того:
Как правило, трассируемость реализуется в виде указателей (опорных точек, якорей) и ссылок. Например, каждому требованию присваивается свой уникальный номер - его указатель, а в тесте, проверяющем реализацию этого требования, ставится ссылка на этот номер.
Прослеживание трассируемости должно обеспечивать проверку того, что:
Одним из ключевых вопросов, определяющих требования к документированию проекта в рамках данного стандарта, является понятие критичности отказов системы, которые предлагается классифицировать по следующим категориям.
Категория A - катастрофическая: отказная ситуация, препятствующая безопасному функционированию объекта управления.
Категория B - опасная/критическая: отказная ситуация, приводящая к уменьшению возможностей объекта управления или способности персонала справиться с неблагоприятными эксплуатационными режимами, при которых возникают:
Категория C - существенная: отказная ситуация, приводящая к снижению возможностей объекта управления или способности персонала справиться с неблагоприятными эксплуатационными режимами, при которых могут возникать, например, большое снижение гарантийных резервов или функциональных возможностей, перегрузки или условия, вызывающие ухудшение работоспособности персонала.
Категория D - несущественная: отказная ситуация, незначительно уменьшающая безопасность объекта и требующая действий персонала, которые осуществимы в пределах их возможностей. Несущественная отказная ситуация может включать в себя, например, незначительное уменьшение гарантийных резервов или функциональных возможностей, незначительное увеличение рабочей нагрузки персонала или некоторое неудобство для персонала.
Одним из ключевых вопросов разработки является понятие жизненного цикла. При этом процесс жизненного цикла программного обеспечения рассматривается как совокупность процессов планирования и разработки, объединяемых и взаимодействующих посредством интеграционных процессов.
Задачей процесса планирования является определение и координация операций процесса разработки и интеграционных процессов. Задачей процесса разработки является собственно выпуск программного продукта. А интеграционные процессы обеспечивают корректность, целостность и доверие к данным разработки.
Различные программные компоненты в плане разработки могут иметь различные жизненные циклы. Возможный пример иллюстрируется рисунком 1.5. Так, компонента 1 проходит в процессе реализации типичный жизненный цикл, а компонента 2 минует фазу проектирования, что может быть осуществлено из-за ее структурной простоты, позволяющей произвести кодирование прямо на основании сформулированных требований. В свою очередь, компонента 3, являющаяся заимствованным программным кодом, сразу после определения требований может быть вовлечена в процесс интеграции.
Наиболее сложный пример представлен жизненным циклом компоненты 4. При этом предполагается, что первичные требования реализуются и исследуются. Затем происходит уточнение требований, реализация нового прототипа и повторная интеграция, по итогам которой формируются окончательные требования. Завершающая стадия включает проектирование, кодирование и окончательную интеграцию. Таким образом, компонента 4 проходит две фазы прототипа перед финальной фазой реализации.
При определении жизненного цикла программного обеспечения должны быть заданы критерии начала и завершения каждой процедуры процесса. Другими словами, должно быть сформулировано условие, выполнение которого по отношению ко входным данным процедуры позволяет решить вопрос о возможности ее начала. Кроме того, должно быть сформулировано условие, анализ которого по отношению к выходу процедуры позволяет судить о том, что процедура завершена.
Задачи процесса планирования включают в себя:
Таблицы - приложения к ГОСТу дают представление о составе документов, которые должны быть разработаны и находиться под управлением процесса планирования. Там же определяется уровень (категория) конфигурационного управления соответствующей документацией.
Для уровней критичности A, B и C требования по составу документов идентичны, а для разработки программного обеспечения, относящегося к уровню D, они значительно упрощены. Так, для уровня D не являются обязательными определение критериев перехода от одной процедуры жизненного цикла к другой, фиксация инструментальных средств, разработка стандартов. Принципиально необходимым считается только определение процедур интеграционных процессов и процессов разработки программного обеспечения.
В свою очередь, требования к конфигурационному управлению документами процесса планирования идентичны для уровней A и B, но упрощены для программных проектов уровня C и D.
Процедуры процесса разработки включают в себя:
В процессе планирования должны быть разработаны планы (процедуры) сертификации, разработки программного обеспечения, верификации, управления конфигурациями и обеспечения качества. Все эти процедуры оказываются завязаны по общим данным так, что выходы одних являются входами для других или служат своего рода обратной связью, позволяющей вырабатывать необходимые корректирующие воздействия.
При планировании должны быть решены вопросы определения инструментального и методического обеспечения процессов жизненного цикла, организации коллектива проекта и процедур гарантии качества.
При этом можно упрощенно рассматривать процесс разработки как процесс последовательной трансляции:
В процессе проектирования архитектуры обычно появляются дополнительные требования низкого уровня, часть из которых вообще не может быть напрямую ассоциирована с требованиями высокого уровня. Однако в большинстве случаев прослеживаемость проектных решений сверху вниз существует и должна быть обеспечена средствами трассируемости документации программного проекта (составная часть средств управления конфигурациями).
Состав требований к процессу разработки не зависит от уровня критичности программного обеспечения, вариации уровней требований предусмотрены только для процедур конфигурационного управления, которые могут быть ослаблены для проектов категорий C и D по отношению к документам, описывающим архитектуру (проекта) программного обеспечения.
Процесс верификации программного обеспечения - это не просто тестирование. Тестирование не может показать отсутствие необходимой функциональности. Процедуры процесса верификации должны обеспечивать:
Средства проверки соответствий могут быть различны: логический анализ, структурный анализ, формальные инспекции, тестирование. В процессе планирования должны быть определены процедуры и методы верификации, применяемые на различных шагах процесса разработки к различным видам документов.
При доказательстве соответствия требований одного уровня другим чаще всего используются различные виды анализа, в том числе в форме формальной инспекции. Для верификации программного кода обычно проводят тестирование.
В зависимости от уровня критичности программного обеспечения в ГОСТ Р 51904-2002 устанавливаются различные уровни детальности проверки программного кода в процессе верификации:
a) проверка того, что все требования к программному обеспечению реализованы (100%-е покрытие требований в процессе тести-рования);
b) проверка того, что выполнено требование (а) и при этом все команды программного кода были выполнены в процессе тестирования (100%-ное покрытие кода в процессе тестирования);
c) проверка того, что выполнено требование (b) и при этом все ветви программного кода были выполнены в процессе тестирования (100%-ное покрытие ветвей программного кода в процессе тестирования);
d) проверка того, что выполнено требование (с) и при этом все условия разветвления программного кода были независимо проверены в процессе тестирования.
Очевидно, что требование (а) полностью ориентировано на тестирование программного обеспечения как "черного ящика". Другими словами, исследователь программного кода при этом рассматривает объект исследования только снаружи. Он оказывает входные воздействия, определяемые требованиями, и наблюдает значения на выходе, сравнивая их с ожидаемыми (вытекающими из требований). Никаких сведений о внутреннем устройстве (структуре и особенностях реализации) программного кода при таком подходе не должно использоваться.
При выполнении тестирования, соответствующего уровням требований (b) и (с), в ряде случаев удается оставаться в рамках концепции "черного ящика", по крайней мере, на этапе проверки требований. При таком подходе считается, что ничего не известно о внутреннем устройстве программы. Все заключения о ее правильном или неправильном поведении делаются на основе анализа ее внешних, наблюдаемых свойств.
Большинство сред поддержки тестирования (эмуляторов, отладчиков) позволяют произвести сбор покрытий программного кода и предоставить необходимую для анализа статистику. Но выявление причин недостаточного уровня покрытия требует сопоставления функциональных требований и способа их реализации в программном коде. По меньшей мере исследованию подвергается граф управления программы.
Поэтому выполнение тестирования по уровням требований (b) и (c), как правило, можно рассматривать в рамках концепции "серого ящика". Такой подход предполагает использование при исследовании объекта некоторых свойств его структуры. Но надо заметить, что эти сведения должны привлекаться только для анализа причин непокрытия кода. Ни в коем случае они не должны использоваться для прогнозирования ожидаемой реакции программы.
Причинами выявленного непокрытия могут быть как недокументированные свойства программного кода ("закладки", "баги", "мертвый код"), так и неполная трактовка (отображение в тесты) требований к программному коду со стороны тестировщика. В последнем случае в процедуру тестирования должны быть добавлены дополнительные тесты.
Одним из важнейших поддерживающих процессов является процесс конфигурационного управления. Основная задача процесса управления конфигурациями - обеспечение гарантии того, что организация-разработчик имеет все необходимые данные для подтверждения факта соответствия произведенного продукта требованиям.
Управление конфигурациями можно определить как процесс, с помощью которого руководство проекта имеет возможность на постоянной основе идентифицировать, устанавливать связи, сопровождать и управлять различными компонентами проекта. Этот процесс гарантирует целостность компонент и прослеживаемость всех изменений, возникающих в любой момент жизненного цикла проекта.
Базовым понятием процесса является (Configuration Item) объект (Элемент) конфигурационного управления (ОКУ). Под объектами конфигурационного управления могут пониматься все основные результаты деятельности проекта. Такие результаты идентифицируются и контролируются с помощью процесса управления конфигурациями. Объектами конфигурационного управления могут быть элементы аппаратуры, программы, документация, процедуры и материалы обучения, средства обслуживания и т.д. В целях идентификации объектам конфигурационного управления могут быть присвоены номера.
Еще один термин, используемый в процессе конфигурационного управления - базовая конфигурация (Baseline). Под базовой конфигурацией (БК) понимается объект конфигурационного управления (отдельный элемент или совокупность элементов), который прошел процедуру утверждения и может быть изменен только в рамках процедуры управления изменениями.
Базовая конфигурация - это своего рода фотоснимок, "замороженная ситуация" требований, спецификаций или результатов, находящихся в разработке. Она может быть представлена документом или набором документов. Создание базовой конфигурации - обычно фиксация некоторого условия, возникающего при завершении каждого из основных шагов процесса разработки.
Базовая конфигурация может состоять из совокупности однородных документов, например совокупность требований, коды совокупности программных модулей. Но базовая конфигурация может состоять и из совокупности разнородных по своей сути ОКУ, например требования и соответствующий программный код, тест-план, результаты прогона тест-плана.
Таким образом, процесс конфигурационного управления призван обеспечивать следующее:
Табл. 2.1 дает представление о составе документов, которые должны быть разработаны и находиться под контролем процесса управления конфигурациями. Там же определяется уровень (категория) конфигурационного управления соответствующей документацией.
| Цель процесса управления конфигурацией | Ссылка на раздел | КК1 | КК2 |
|---|---|---|---|
| Идентификация конфигурации | 9.2.1 | * | * |
| Базовая линия | 9.2.3 а), б), в), г), д) | * | |
| Трассируемость | 9.2.3 е), ж) | * | * |
| Отчетность о дефектах | 9.2.4 | * | |
| Контроль изменений - целостность и идентификация | 9.2.5 а), б) | * | * |
| Контроль изменений - трассируемость | 9.2.5 в), г), д) | * | |
| Просмотр изменений | 9.2.6 | * | |
| Отчетность о состоянии конфигурации | 9.2.7 | * | |
| Получение документа из архива | 9.2.8 а) | * | * |
| Защита от несанкционированных изменений | 9.2.8 б1) | * | * |
| Выбор носителей, обновление, копирование | 9.2.8 б2), б 3), б4), в) | * | |
| Выпуск версии | 9.2.8 г) | * | |
| Хранение данных | 9.2.8 д) | * | * |
Обозначения:
* - цель должна быть удовлетворена для документов данной категории; пробел - удовлетворение цели на усмотрение разработчика.
Различаются два уровня конфигурационного управления документацией: КК1 и КК2. Уровень КК1 предполагает полный контроль над конфигурациями проекта. Уровень КК2 допускает отсутствие большой части элементов и процедур. При КК2 обязательными остаются процедура идентификации, прослеживаемость (трассируемость), управление изменениями, доступность и сохранность данных с соблюдением ограничений доступа (предотвращение несанкционированных изменений).
Синхронизацию всех процессов должен гарантировать процесс обеспечения качества программной разработки.
Обеспечение (гарантия) качества - это совсем не тестирование и не верификация результата. Основная задача процесса (Software Quality Assurance Process) - наблюдение за соблюдением стандартов проекта. При этом записи, ведущиеся в рамках процесса (quality records), являются составной частью документации проекта и попадают под конфигурационное управление.
При выполнении проекта процесс обеспечения качества должен давать гарантии того, что все необходимые стандарты разработаны в соответствии с требованиями, все процедуры жизненного цикла выполняются в соответствии со стандартами, а все отклонения от утвержденных планов и стандартов выявляются, рассматриваются в утвержденном порядке и устраняются. Одним из механизмов процесса является аудит. Заметим, что задача аудита, в отличие от задачи верификации, - поиск соответствия. Верификация и, в частности, тестирование ориентированы на выявление несоответствий. При аудите производится поиск соответствий, а обнаруженные несоответствия фиксируются (один из видов записей процесса) и предоставляются на рассмотрение руководству проекта. При этом одной из задач процесса является предотвращение возможных несоответствий.
Таким образом, можно рассматривать процесс обеспечения качества как процесс-наблюдатель за другими процессами. Но это не пассивный наблюдатель, фиксирующий нарушения. Процесс обеспечения качества призван активно участвовать в разработке стандартов и процедур проекта, обеспечивая выполнение требований заказчика и ГОСТ Р 51904-2002.
Дополнительно в документе определяются требования к используемому инструментарию, документации по заимствованным компонентам, правила сертификации и т.п.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.