Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Программирование на языке высокого уровня Лекции 09.03.01

.pdf
Скачиваний:
29
Добавлен:
10.01.2021
Размер:
1.1 Mб
Скачать

Для определения пользователем горячих клавиш для других интерфейсных элементов используется компонент THotKey. Для выбора даты может использоваться один из двух компонентов - TDateTimePicker или TMonthCalendar. Эти компоненты отличаются внешним видом на этапе выполнения.

Для включения в форму стандартной панели состояния используется компонент TStatusBar. Ее содержимое может состоять из одной строки (это определяется установкой свойства SimplePanel), или из неспольких отдельных панелей, которые формируются в редакторе панелей. Этот редактор вызывается путем выбора в контекстном меню пункта Panels Editor.

Программирование на языке высокого уровня 09.03.01

61

Раздел 8. Технология создания программ на языке программирования высокого уровня. Лекции

38-42.

Тема 49. Восходящая разработка программ. Достоинства и недостатки.

Традиционно проектирование программного приложения производится сверху вниз, а программирование – снизу вверх, реализуя тем самым восходящий подход.

Уровень1

 

 

 

 

 

 

 

 

Уровень 2

 

 

Уровень 2

 

Уровень 2

 

 

 

 

 

 

 

 

Уровень 3

 

Уровень 3

 

 

 

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

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

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

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

-вносятся изменения в уже написанные программные модули;

Программирование на языке высокого уровня 09.03.01

62

-перепрограммируется большая часть модулей;

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

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

Тема 50. Нисходящая разработка программ

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

ипроверенной.

Врамках нисходящего подхода возможно несколько вариантов последовательного программирования модулей.

Уровень1

1 1

 

 

 

 

 

 

 

 

 

 

 

Уровень 2

2 2

 

 

Уровень 2

3 3

 

 

Уровень 2

4 6

 

 

 

 

 

 

 

 

 

 

 

Уровень 3 5 4

 

Уровень 3

6 5

 

 

 

 

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

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

Программирование на языке высокого уровня 09.03.01

63

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

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

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

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

Определяя порядок разработки модулей, следует учитывать шесть факторов:

1)зависимость по данным;

2)доступные ресурсы;

3)требование обеспечить выдачу результатов модулей, проверяемых раньше;

4)необходимость прежде всего обеспечить готовность вспомогательных модулей;

5)сложность модулей – при прочих равных следует начинать со сложных модулей;

6)обработка исключительных ситуаций, связанных с

неправильными данными – модули, обрабатывающие правильные данные, должны программироваться и тестироваться раньше модулей, имеющих дело с неправильными данными.

Темы 51-52. Модульное программирование. Основные принципы разбиения программы на модули. Элементы стиля программирования

Модуль – это последовательность логически связанных фрагментов, оформленных как отдельная часть программы. Основными преимуществами модульного программирования являются:

1)возможность разделения работы между несколькими программистами;

2)возможность создания библиотек модулей для их дальнейшего использования;

3)

увеличение

числа контрольных точек

для наблюдения

за

ходом выполнения проекта;

 

 

4)

облегчение тестирования.

 

 

Модуль имеет

три основных атрибута: он

выполняет одну

или

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

Программирование на языке высокого уровня 09.03.01

64

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

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

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

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

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

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

Коммуникационно прочный модуль – это процедурно прочный модуль с одним дополнительным ограничением: все его функции связаны по данным.

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

Функционально прочный модуль – это модуль, выполняющий одну определенную функцию.

Сцепление модулей – это мера взаимодействия модулей по данным, которая характеризуется как способом передачи данных, так и свойствами самих этих данных.

Два модуля сцеплены по содержимому, если один прямо ссылается на содержимое другого.

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

Группа модулей сцеплена по внешним данным, если они ссылаются на один и тот же глобальный элемент данных.

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

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

Два модуля сцеплены по данным, если один вызывает другой и все входные и выходные параметры вызываемого модуля – простые элементы данных.

В дополнение к прочности и сцеплению есть и другие характеристики, оказывающие воздействие на независимость модулей. Это размеры модуля (от 10 до 100 операторов языка программирования), предсказуемость модуля (модуль не должен хранить следы своих состояний

при последовательных вызовах), минимизация доступа к

данным,

отсутствие внутренних процедур.

 

Программирование на языке высокого уровня 09.03.01

65

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

Тема 53. Понятие о принципах тестирования программ.

Согласно

мнению

экспертов

основное

время

при

программировании тратится на тестирование и отладку.

 

Отладка –

это процесс действий, которые необходимо

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

 

Тестирование

– это

последовательные и

систематические

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

Тестирование в процессе создания программ.

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

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

int i;

char s[MAX];

for (i=0,(s[i]=getchar())!=’\n’ && i<MAX-1;i++)

;

s[i]=’\0’;

В данном примере не обрабатываются строки, не содержащие

‘\n’.

Пример:

int factorial(int n)

{

int fac; fac = 1; while (n--)

fac *= n; return fac;

}

Программирование на языке высокого уровня 09.03.01

66

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

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

Систематическое тестирование.

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

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

которая

автоматически

генерирует

массив,

подвергающийся

тестированию.

 

 

 

Даже

при разработке самых

простых

программ может

понадобиться большое количество тестов. Например, модуль, решающий квадратное уравнение должен быть подвергнут не менее, чем семи тестам, и это не считая проверки диапазонов арифметических значений: a=b=c=0; a=b=0, c=10; a=0, b=5, c=17; a=1, b=6, c=2; a=3, b=7, c=0; a=3, b=2, c=5; a=7, b=c=0.

Рассмотрим набор тестов для полной проверки программы, вводящей три целых числа и печатающей сообщение о том, является ли треугольник разносторонним, равнобедренным или равносторонним. 54% программистов выполняют только одну проверку на равнобедренный треугольник, только 28% программистов три раза проверяют неравенство треугольника, а 44% вообще не проверяли неравенство треугольника. 30% не пробовали подавать на вход не

числовые данные.

 

 

 

 

При

проведении

тестов

необходимо

знать

правильный

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

Программирование на языке высокого уровня 09.03.01

67

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

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

Стрессовое тестирование.

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

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

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

Автоматизация тестирования.

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

В дополнение к возвратным тестам полезно использовать и замкнутые тесты, которые содержат в себе и вводимые данные, и ожидаемые результаты.

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

качество

тестирования, определить, в какой мере тесты проверяют

алгоритм

программы. Например, можно контролировать выполнение

Программирование на языке высокого уровня 09.03.01

68

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

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

Для автоматизации тестов разрабатываются также специальные языки.

Исполнители тестов

Тестирование, проводимое создателем кода или кем-то другим, имеющим, тем не менее, доступ к исходному коду, называется тестированием белого ящика. При таком тестировании необходимо отрешиться от содержания самого программного кода и придумывать как можно более изощренные проверки. Цель тестирования – найти ошибки, а не объявить программу работающей. Следовательно, тесты должны быть жесткими, и если использование таких тестов приводит к обнаружению проблем, то это является доказательством действенности избранной стратегии тестирования.

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

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

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

При этом, главное правило тестирования – делать его.

Тема 54. Отладка программ.

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

Типовыми советами при отладке программ могут быть:

Программирование на языке высокого уровня 09.03.01

69

-необходимо проверить соответствие форматов при вводевыводе;

-необходимо убедиться в отсутствии неинициализированных локальных переменных;

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

-необходимо просмотреть стек вызовов функций;

-необходимо попытаться объяснить свой код кому-нибудь

 

ещё.

 

 

 

 

Для

полноценной

отладки

необходимо

сделать

ошибку

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

Также следует регистрировать любым способом все

действия,

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

Согласно статистике, большая часть проблем

заключается

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

Если при добавлении отладочного кода ошибка перестает проявляться, то проблема, скорее всего, связана с распределением памяти.

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

Тема 55. Понятие о надежности программного обеспечения.

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

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

Программирование на языке высокого уровня 09.03.01

70