Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Основы разработки программного обеспечения на примере языка С. Учебное пособие для СПО
.pdf
реализации и архитектуру целевой машины как самые общие
требования к реализации. Например, если рассмотреть программу,
вычисляющую периметр треугольника по длинам его сторон, то краткое
описание может иметь следующий вид.
1. Общее описание задачи
Программа вычисления периметра треугольника по длинам его сторон.
Язык реализации - Си. Архитектура - х86.
Во втором разделе описывается интерфейс программы. Под
интерфейсом понимаются все данные, методы и средства,
предназначенные для взаимодействия с внешними программами,
пользователями, периферией (датчиками и исполнительными
устройствами). Этот раздел удобно рассматривать с трех точек зрения:
входы;
выходы;
хранимые данные.
Каждую из этих позиций можно разделить на подразделы с учетом
сложности и типа описываемого взаимодействия. В случае программы
расчета периметра треугольника удобно разделить входные/выходные
данные на данные, подаваемые/возвращаемые в среду ОС, и на
вводимые данные с клавиатуры/выводимые на экран сообщения.
2. Интерфейс
2.1. Входные данные
2.1.1. Данные, вводимые с клавиатуры
Три целых положительных числа, меньшие 100 - длины сторон в
десятичной системе исчисления.
2.1.2. Параметры - данные, передаваемые из среды ОС.
Параметры, передаваемые из среды ОС, отсутствуют.
В качестве хранимых данных в разделе описания интерфейса
Основы разработки программного обеспечения на примере языка СС.В. Синицын, О.И. Хлытчиев
31

рассматриваются все внутренние данные ПО, доступные извне во
время выполнения. Например, программный модуль может иметь
экспортируемую переменную, которая и должна быть описана в этом
подразделе. Возможна и другая ситуация, когда модуль использует чьюто внешнюю (видимую извне) переменную.
Если спецификация описывает отдельный модуль, то удобно делить
раздел описания интерфейсных требований на подразделы для каждой
отдельной функции модуля, включающие входы/выходы, внутренние/
внешние переменные функций. Когда язык программирования
определен в требованиях к реализации, целесообразно указывать
заголовки функций на выбранном языке.
При описании интерфейса часто приходится накладывать ограничения
на диапазон входных значений. Во многих случаях эти ограничения
могут быть обусловлены свойствами самого типа данных,
передаваемых на вход программы. Но чаще они определяются
особенностями алгоритма обработки вводимых значений. Например,
нельзя делить на нуль.
В любом случае при описании ограничений на входные данные мы не
можем гарантировать, что они безусловно будут соблюдаться
пользователями системы. Но программа должна разрабатываться с их
учетом, поэтому в функциональных требованиях стоит предусматривать
соответствующую проверку входных значений.
Третий раздел спецификации содержит функциональные требования к
ПО. Здесь должна быть подробно в виде требований описана вся
функциональность ПО, включая все особые случаи. В нашем примере
переданные числа могут оказаться не сторонами треугольника (не
удовлетворять основному правилу треугольника), поэтому необходимо
четко указать, что программа должна делать в таком случае.
Требования могут дополнительно комментироваться, однако каждое
требование выделяется в тексте отдельным предложением со словом
"должен" (должна, должно). Это позволяет четко отделить требования и
комментарии/описания, а также однозначно пронумеровать все
требования.
Требования к ПО должны отвечать на вопрос "что должна делать
Основы разработки программного обеспечения на примере языка СС.В. Синицын, О.И. Хлытчиев
32

программа?". Следует четко различать вопросы "что должна делать
программа?" и "как она должна это делать?". Вопрос "что?" - это
определение функциональности, а вопрос "как?" - это определение
алгоритма. Сам алгоритм относится уже к архитектуре системы, за
исключением особых случаев, когда требуется реализация конкретных
алгоритмов, например шифрование, расчет контрольной суммы, но
даже в этих случаях следует минимально ограничивать реализацию.
Итак, требования к ПО содержат в себе определение функциональности,
а алгоритмы и детали реализации - это архитектура ПО.
В случаях, когда спецификация пишется для целой программы,
требования можно разбить на разделы, отражающие основные
функциональные области системы.
Например, для программы расчета периметра треугольника вся
функциональность может быть разделена на следующие подразделы.
3. Функциональные требования
ввод данных;
проверка корректности данных;
расчет периметра;
вывод результатов (или типа ошибки).
Для каждого функционального подраздела далее формулируются
требования. Например, для проверки корректности данных можно
записать следующие требования:
3.1. Программа должна выводить на экран приглашающее сообщение
<ссылка на пункт о выводе сообщения> и вводить с клавиатуры три
числа.
3.2. Программа должна проверить, являются ли введенные три числа
длинами сторон треугольника согласно основному правилу
треугольника (сумма двух любых сторон треугольника больше длины
третьей стороны), и если введенные числа не соответствуют этому
правилу, то надо вывести сообщение об ошибке <ссылка на пункт о
выводе сообщения о соответствующей ошибке>.
3.3. Программа должна проверить, что каждое из введенных трех чисел
Основы разработки программного обеспечения на примере языка СС.В. Синицын, О.И. Хлытчиев
33

меньше 100 и больше 0, и если введенные числа не принадлежат этому
интервалу, то надо вывести сообщение об ошибке <ссылка на пункт о
выводе сообщения о соответствующей ошибке>.
ПРИМЕЧАНИЕ. Заметим, что контроль диапазона значений может быть
оговорен в функциональном разделе "Ввод данных", тогда пункт 3.3
может отсутствовать, но это значительно усложнит требование 3.1.
В дополнение к функциональным требованиям четвертый раздел
спецификации содержит тест-требования. В тест-требованиях
указывается, что необходимо проверить при тестировании. Или,
другими словами, на основании каких внешних проявлений можно
убедиться, что необходимая функциональность реализована в системе.
Сам раздел должен отражать основные области эквивалентности
входов или области, в которых поведение программы будет схожим.
Если выделить такие области и протестировать поведение программы
для какого-либо одного значения из каждой области, то с большой
вероятностью можно будет утверждать и о поведении программы на
всей области определения ее входных значений.
Обычно удобно начинать тест-требование со слов "Проверить, что...".
Например, для входов программы расчета периметра треугольника
можно сформулировать следующее тест-требование:
Проверить, что если значение одного из входов больше или равно 100,
то программа выдаст сообщение об ошибке, указанное в пункте <ссылка
на пункт описания интерфейса с соответствующим сообщением об
ошибке>.
Заметим, что подобное тест-требование существенно отличается от:
Проверить, что если значение любого из входов больше или равно 100,
то программа выдаст сообщение об ошибке, указанное в пункте <ссылка
на пункт описания интерфейса с соответствующим сообщением об
ошибке>.
Ибо такая формулировка ТРЕБУЕТ, чтобы подобные значения, например
150, были при проверке последовательно заданы для каждой из сторон
треугольника, а на самом деле еще и для всех пар сторон.
Основы разработки программного обеспечения на примере языка СС.В. Синицын, О.И. Хлытчиев
34

Дополнительно тест-требование может задавать некоторый приоритет
функций, явно не прописанный в требованиях к программе. Так, при
входных значениях 1, 2, 100 не вполне ясно, какие сообщения должна
выдавать программа - о превышении максимальной длины (100) или о
невозможности построить треугольник с этими сторонами (1+2<100).
Тест-требование может гласить:
Проверить, что <описание ситуации>, оба сообщения <ссылка на
пункты описания интерфейса с соответствующими сообщениями об
ошибках> выводятся программой.
Составление тестов более подробно рассматривается в разделе 9
данного учебника.
После определения указанных разделов начинается процесс
кодирования. Результат - код программы/функции/модуля - тоже может
рассматриваться как пятый раздел спецификации. Для сложных
программ рекомендуется начинать этот раздел с подраздела 5.1
описания алгоритма в виде блок-схемы или псевдокода и только потом
переходить к подразделу 5.2 - коду программы.
Проектирование и реализация
Рассмотрим эту часть подробнее на элементарном примере. Пусть нам
надо выбрать максимальное значение из трех заданных параметров A, B
и C. Назовем эту задачу (функцию) MAX3(A, B, C).
Основы разработки программного обеспечения на примере языка СС.В. Синицын, О.И. Хлытчиев
35

Рис. 2.3(а). Схема решения задачи MAX3(A, B, C)
Основы разработки программного обеспечения на примере языка СС.В. Синицын, О.И. Хлытчиев
36

Рис. 2.3(б). Улучшенная схема решения задачи MAX3(4, B, C)
Основы разработки программного обеспечения на примере языка СС.В. Синицын, О.И. Хлытчиев
37

Рис. 2.3(в). Схема решения задачи MAX2(MAX, Р)
Рис. 2.3(г). Линейная схема решения задачи MAX3(A, B, C)
Одно из наиболее простых решений может быть изображено схемой
(рис. 2.3(а)
).
Такая схема достаточно проста для понимания, но ее дальнейшее
развитие для 4-х, 5-и и более параметров выглядит весьма
затруднительно. В этом смысле куда более привлекательным выглядит
решение на рис. 2.3(б)
. Оно более соответствует идеологии
структурного программирования и позволяет неограниченно
Основы разработки программного обеспечения на примере языка СС.В. Синицын, О.И. Хлытчиев
38

наращивать количество обрабатываемых параметров.
Основу его составляет простой программный фрагмент, состоящий из
элемента (рис. 2.3(в)
) проверки условия: значение, ранее выбранное как
максимальное, действительно является таковым по отношению к
очередному проверяемому параметру. И если указанное условие
нарушается, то запоминается новое максимальное значение.
Фактически элемент, изображенный на рис. 2.3(в)
, представляет собой
функцию MAX2(MAX, X), которая из двух переданных ей элементов
MAX и X выбирает большее значение и запоминает его в MAX.
Осознание полезности выделенной структуры в отдельную функцию на
этапе проектирования архитектуры приводит к куда более простому
программному коду основной функции MAX3(A, B, C) (рис. 2.3(г)
). Это
линейная последовательность трех операций.
Именно к подобной архитектуре должен стремиться разработчик на
этапе проектирования.
При реализации сегментирование текста программы на отдельные
процедуры позволяет легче читать и сопровождать (вносить
необходимые изменения) код. При решении больших и сложных задач
производится деление всего комплекса на программные модули, каждый
из которых пишется и транслируется отдельно. Это позволяет разделить
разработку между несколькими исполнителями.
Проверка реализации (верификация)
После написания кода составляется шестой раздел - тест-план, который
содержит в себе реальные данные и ожидаемые результаты для
проверки программы согласно функциональным требованиям к задаче и
тест-требованиям. Тест-план можно рассматривать как часть
спецификации, но зачастую он является отдельным документом.
По тест-плану пишется тест-модуль (тест-драйвер), который
автоматически выполняет ("прогоняет") все тесты из тест-плана. Задача
тест-модуля - обеспечить возможность повторяемости тестов после
исправления обнаруженных ошибок.
Основы разработки программного обеспечения на примере языка СС.В. Синицын, О.И. Хлытчиев
39

В процессе анализа обнаруженные несоответствия выявляются, и
устраняется их причина. Это может быть ошибка реализации
(кодирования), ошибка в требованиях, которые подлежат изменению.
Наконец, это может быть ошибкой самих тестов, которые неправильно
трактуют указанную в требованиях ситуацию.
Рассмотрим очень похожую на 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
Основы разработки программного обеспечения на примере языка СС.В. Синицын, О.И. Хлытчиев
40
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
