Данная лекция посвящена
Первое проявление дефекта - сбой в работе системы. Сбои имеют небольшую продолжительность во времени и могут быть устранены без длительных процедур восстановления. Как правило, сбой вызывает кратковременную порчу данных пользователя без прекращения работы всей системы в целом. Последствия сбоя могут быть существенными с точки зрения пользователя, особенно если данные являются критически важными, однако бесперебойная работа системы не нарушается.
Отказ - более серьезное проявление дефекта в системе, при котором вся система или ее часть выходят из строя, выходя при этом из работоспособного состояния, т.е. состояния, в котором все аспекты функционирования системы соответствуют требованиям. В случае отказа системы для ее возврата к нормальному функционированию требуется вмешательство оператора. Для программных систем причиной отказа может служить скрытый дефект, проявляющийся только с течением большого промежутка времени (переполнение внутреннего счетчика времени, переполнение данных и т.п.).
Авария - отказ системы, при котором система выходит из строя таким образом, что восстановление ее работоспособного состояния либо невозможно, либо занимает весьма значительное время. В случае программных систем можно избежать возникновения аварийных ситуаций при помощи полного дублирования системы как по выполняемому программному коду, так и по данным.
Сбои и отказы являются причиной отказных ситуаций, т.е. ситуаций, в которых работоспособное состояние системы нарушается временно. Аварии являются причиной аварийных ситуаций, т.е. ситуаций, в которых работоспособное состояние системы нарушается навсегда или на длительный срок.
Можно выделить следующие три вида сбоев, вызывающих отказные ситуации.
Для классификации сбоев по категориям выделим следующие параметры сбоя.
Точка возникновения сбоя - строка или оператор программного кода, вызвавший отказную ситуацию. Данный оператор может находиться в коде системных библиотек либо в коде приложения пользователя. Вовсе не обязательно, что сбой вызван именно этим оператором, но при помощи анализа окружения вызова и исходных текстов программ обычно удается обнаружить причину отказа.
Информационное окружение системы в момент сбоя - состояние системы в момент сбоя. К информационному окружению в данном случае относятся данные, которые могут помочь в анализе причины сбоя и его устранении - например, состояние стека, значение переменных окружения, пользовательской сессии и т.п. Данный набор параметров позволяет проследить ход выполнения программы, который привел к ее сбою, и оценить несоответствия в данных, которые могли привести к сбою.
Наличие и тип сообщения о сбое - сообщение о сбое может быть создано автоматическим модулем оповещения о сбоях и содержать вышеуказанную информацию, а может создаваться пользователем вручную. Если исходить из допущения, что автоматически создаваемые сообщения посылаются разработчику всегда в случае сбоев, не приводящих к полному краху системы и вызывающих нештатное поведение системы с точки зрения операционной среды либо времени выполнения, то эта информация также помогает оценить тип сбоя.
В табл. 25.1 приведена классификация типов сбоев по указанным выше признакам.
| Параметры сбоя | Тип сбоя | ||
|---|---|---|---|
| Сбой в системном ПО | Сбой в прикладном ПО | Сбой из-за неверной технологии | |
| Точка возникновения сбоя | Системные библиотеки или Приложение | Приложение | Неприменимо |
| Информационное окружение | Ненормальное | Ненормальное | Нормальное |
| Сообщение о сбое | Пользовательское или автоматическое | Автоматическое | Пользовательское |
Отказы вызывают длительное нарушение функционирования системы, или, по ГОСТ 27.002-89 [21], приводят ее в предельное состояние. Предельное состояние - это состояние, при котором дальнейшая эксплуатация системы недопустима или нецелесообразна либо восстановление ее работоспособного состояния невозможно или нецелесообразно. Тем самым в ГОСТ 27.002-89 не делается разницы между отказом и аварией. Будем называть отказом состояние системы, при котором восстановление ее работоспособного состояния возможно.
Отказы классифицируются согласно ГОСТ 27.002-89 следующим образом.
Внезапный отказ - отказ, вызванный резким скачкообразным изменением одного из параметров системы или обрабатываемых системой данных. Ситуации, вызывающие такие отказы, могут моделироваться при
Постепенный отказ - отказ, вызванный постепенным изменением одного из параметров системы или обрабатываемых системой данных. Такой отказ может возникать, например, при переполнении внутреннего буфера, хранящего информацию о состоянии системы в каждый момент времени. Если время работы системы больше размера буфера или не предусмотрена его очистка - рано или поздно возникнет переполнение.
Перемежающийся отказ - многократно возникающий самоустраняющийся сбой одного и того же характера. Поскольку в данном случае речь идет уже о систематически проявляющемся дефекте системы, то можно говорить именно об отказе, а не о серии сбоев.
Ресурсный отказ - отказ, в результате которого система достигает предельного состояния, т.е. такой отказ вызван, в первую очередь, нехваткой ресурсов (например, дискового пространства) для работы системы. Ситуации, вызывающие такие отказы, могут моделироваться при
Конструктивный отказ - отказ, вызванный нарушением процесса проектирования и разработки системы или неверным проектированием. Процесс верификации и тестирования, в первую очередь, направлен на обнаружение дефектов, вызывающих конструктивные отказы.
Производственный отказ - отказ, связанный с нарушением процесса производства или сопровождения системы. В применении к программным системам производственные отказы могут возникать в случае неверного выполнения профилактических работ при сопровождении системы. Например, в результате выполнения профилактических работ могут быть утеряны файлы настройки системы, в результате чего она переходит в режим работы по умолчанию, несовместимый с текущими настройками оборудования. Предупреждение таких отказов состоит, в первую очередь, в корректном составлении эксплуатационной документации и документации сопровождения, которая должна быть верифицирована.
Эксплуатационный отказ - отказ, связанный с нарушением правил эксплуатации. Причины, вызывающие данный вид отказов, связаны в первую очередь с человеческим фактором. Поэтому основные способы выявления таких отказов - проведение тестирования системы на удобство использования, верификация эксплуатационной документации, введение в систему защитных механизмов, блокирующих потенциальные ошибки оператора.
Явный отказ - отказ, который обнаруживается сразу после его возникновения штатными средствами контроля состояния системы.
Скрытый отказ - отказ, который не обнаруживается штатными средствами контроля состояния системы либо обнаруживается ими спустя некоторое время после возникновения отказа. Такой отказ может послужить причиной для одного или нескольких зависимых отказов.
Независимый отказ - отказ, возникновение которого не обусловлено другими отказами.
Зависимый отказ - отказ, возникновение которого вызвано другими отказами.
Процесс верификации не гарантирует отсутствия в системе всех дефектов, которые могут вызвать сбои, отказы или аварии - речь идет только об определенном уровне отсутствия этих дефектов. Поэтому когда речь идет о системах, к надежности которых предъявляются повышенные требования, для повышения их надежности кроме верификации используются различные методы разработки устойчивого кода.
При этом в результате верификации из системы устраняются дефекты, которые могут быть выявлены при анализе требований и/или кода, а методы разработки устойчивого кода дают дополнительную гарантию того, что система сохранит работоспособность в случаях, не предусмотренных требованиями. Однако, не следует расценивать эти методы как замену верификации или грамотного проектирования.
Как уже было сказано в первых разделах данного курса, верификация не может гарантировать того, что в программной системе отсутствуют абсолютно все ошибки. В лучшем случае мы можем сделать заключение о том, что система ведет себя в соответствии с требованиями, работая на заданном оборудовании. Чтобы нивелировать возможные негативные последствия от ошибок, не обнаруженных в процессе верификации, применяются методы разработки устойчивого программного кода или методы защитного программирования.
Защитное программирование - это метод организации программного кода таким образом, чтобы при работе системы последствия проявления дефектов в ней не приводили к сбоям, отказам и авариям. При этом защитное программирование, как правило, не дает нам никакой информации о том, где в системе находится дефект, поэтому его нельзя рассматривать как полную замену верификации - эти два аспекта промышленной разработки систем лишь дополняют друг друга.
Основной метод защитного программирования - внедрение в программный код системы различного рода проверок на допустимость обрабатываемых системой данных или допустимость состояния системы в заданный момент времени. Таким образом, подход защитного программирования можно сформулировать таким образом: "Прежде чем делать что-то - проверь, с корректными ли данными и в корректный ли момент времени ты начинаешь это делать". Если все данные для работы корректны - система функционирует в нормальном режиме. В случае, если данные неверны, запускается специально разработанная часть системы, предназначенная для восстановления правильности функционирования и предотвращения сбоя (либо при помощи приведения данных к корректному виду, либо при помощи извещения оператора).
В настоящее время существует два основных механизма защитного программирования - проверка допущений в критических точках и обработка исключительных ситуаций.
В любой программе есть участки, требующие предварительных проверок перед выполнением. Например, представим себе два массива, один из которых хранит имена и фамилии людей, а второй - номера их телефонов. В нормальной ситуации количество элементов в обоих массивах должно совпадать и, при поиске фамилии в первом массиве, полученный индекс может быть использован для получения номера телефона найденного человека:
string_vector surname;
string_vector phone;
…
int index = surname.find("Петров");
foundPhone = phone.at(index);
Однако, в случае рассинхронизации двух массивов, индекс может оказаться неверным, например, выходить за границы массива. Вообще, при использовании индекса мы делаем неявное допущение о его корректности. В большинстве современных языков программирования (C, C++, C#, Java, Eiffel) существуют средства для явного задания таких допущений.
Например, в C существует функция assert(), определенная в заголовочном файле <assert.h>. Аргументом этой функции может выступать любое булево выражение. В случае, если оно равно false, функция прерывает работу программы. Таким образом, при помощи булевых выражений могут быть описаны допущения в критических точках программы. Предыдущий пример при использовании функции assert() будет выглядеть как
#include <assert.h>
…
string_vector surname;
string_vector phone;
…
int index = surname.find("Петров");
assert( (index > 0) (index < phone.size()) );
foundPhone = phone.at(index);
Часто программисты определяют свою собственную функцию assert(), например, следующим образом:
#ifdef NODEBUG
#define assert(ignore) 0
#else
#define assert(ex) \
((ex) ? 1 : \
( printf("Assertion failed "), \
abort(), 0))
#endif // NODEBUG
Эта функция отличается от стандартной тем, что в финальной сборке системы с установленным макросом NODEBUG, выдача предупреждений функцией assert() отключается. Такая организация функции assert() связана с широко распространенным заблуждением касательно того, что частые вызовы функции assert() значительно замедляют выполнение программы. Поэтому многие программисты используют допущения только на стадии отладки, считая, что они не могут сработать в конечном продукте. Однако достаточно небольшой проигрыш в скорости окупается дополнительной гарантией надежности системы.
Другая причина того, что программисты предпочитают отключать допущения в финальной версии кода, заключается в том, что при срабатывании допущения выполнение программы прерывается. Однако, существует метод использования допущений совместно с обработкой исключений (см. следующий раздел), при котором возможно определить функции, исправляющие ошибочное состояние системы и продолжающие ее выполнение.
Существует три причины использовать допущения в критических точках:
В зависимости от того, в какой критической точке проверяется допущение, выделяют следующие их типы:
Применение допущений является основной для контрактного программирования, при котором в каждом классе явно определяются предусловия для использования методов этого класса. Таким образом, между объектами этого класса и другими объектами заключается своего рода "контракт" в котором четко прописан интерфейс взаимодействия не только по форматам вызова методов, но и по пересылаемым данным.
Основным источником информации для определения контрактов являются требования на систему - функциональные или архитектурные. Поэтому верификацию допущений необходимо проводить в два этапа: на первом этапе проверяется корректность условий каждого допущения по отношению к требованиям, и только затем на втором этапе моделируются ситуации, приводящие к нарушению допущения. Начинающие тестировщики часто забывают о первом этапе, переходя от
В C++, C# и Java механизм допущений был значительно расширен. При возникновении неверных данных в критической точке вызывается не единая общесистемная функция, прерывающая выполнение программы, а пользовательская функция, которая может либо предпринять попытку разрешить проблему с данными, либо прервать выполнение программы. Возникновение проблемы в критической точке получило название исключительной ситуации или исключения, а вызываемая функция пользователя - обработчик исключения.
Рассмотрим класс, реализующий тип данных "вектор". Для получения значения элемента вектора в нем перегружается оператор [], в котором делается проверка допустимости значения индекса элемента. В качестве второго параметра функции Assert указывается метод класса, обрабатывающего исключительную ситуацию в случае, если значение индекса элемента недопустимо.
class safeVector : public vector {
public:
class outOfRangeException {
int l;
public:
outOfRangeException (const char *,
const char *, int line)
: l (line) {}
int line (void) { return l; }
};
int safeVector::operator[] (int index) {
Assert ((index >= 0) (index < size),
safeVector::outOfRangeException);
...
};
int process(safeVector v, int index) {
int elem;
try {
elem = v[index];
}
catch (safeVector::outOfRangeException e) {
cerr << "Safe Vector range exception:\n";
exit (1);
}
return elem;
}
Для того, чтобы обработчик исключения сработал, обращение к элементу массива помещается внутрь структурного блока try { }, где содержатся команды, результат выполнения которых потенциально может вызвать исключительную ситуацию. Затем внутри синтаксического блока catch { } определяется реакция на возникшую исключительную ситуацию outOfRangeException. Подобным образом можно определить реакцию на любую исключительную ситуацию.
Все исключительные ситуации, для которых определяются пользовательские функции-обработчики, должны быть описаны в проектной документации и протестированы. Хорошей практикой является создание отдельной группы тестов, которая генерирует различные исключительные ситуации и проверяет реакцию системы на них. Однако следует учесть, что не все исключительные ситуации могут быть промоделированы при тестировании, особенно интеграционном или системном - некоторые обработчики пишутся "про запас", на случай изменения других модулей системы и в реальности никогда не вызываются.
Информация о сбоях и отказах - такой же источник данных для программистов, как и информация о неуспешно пройденных тестах. Поэтому, при возникновении сбоя, отказа или аварии рекомендуется составлять отчет о проблеме, который будет передан коллективу разработчиков.
Отчет о проблеме, содержащий информацию о сбое, отказе или аварии, будет несколько отличаться от отчета, созданного в ходе тестирования. Специфика такого отчета заключается в том, что он составляется либо пользователем системы, не имеющим доступ к проектной документации и исходным текстам системы, либо специалистом службы технической поддержки со слов пользователя. Из-за этого в отчете может отсутствовать информация, которая необходима для точной локализации вызвавшего проблему дефекта.
Для упрощения работы службы поддержки и программистов рекомендуется включать в отчет служебную информацию о состоянии и окружении системы в момент сбоя - переменных окружения, активных объектах, состоянии сеанса пользователя и т.п.
Поскольку напрямую пользователю эта информация недоступна, то ее сбор должен осуществляться обработчиками исключительных ситуаций. В результате их работы должен генерироваться выходной дамп состояния системы, который прикладывается к отчету, передаваемому разработчикам для анализа причин возникновения проблемы.
Данная лекция посвящена
Первое проявление дефекта - сбой в работе системы. Сбои имеют небольшую продолжительность во времени и могут быть устранены без длительных процедур восстановления. Как правило, сбой вызывает кратковременную порчу данных пользователя без прекращения работы всей системы в целом. Последствия сбоя могут быть существенными с точки зрения пользователя, особенно если данные являются критически важными, однако бесперебойная работа системы не нарушается.
Отказ - более серьезное проявление дефекта в системе, при котором вся система или ее часть выходят из строя, выходя при этом из работоспособного состояния, т.е. состояния, в котором все аспекты функционирования системы соответствуют требованиям. В случае отказа системы для ее возврата к нормальному функционированию требуется вмешательство оператора. Для программных систем причиной отказа может служить скрытый дефект, проявляющийся только с течением большого промежутка времени (переполнение внутреннего счетчика времени, переполнение данных и т.п.).
Авария - отказ системы, при котором система выходит из строя таким образом, что восстановление ее работоспособного состояния либо невозможно, либо занимает весьма значительное время. В случае программных систем можно избежать возникновения аварийных ситуаций при помощи полного дублирования системы как по выполняемому программному коду, так и по данным.
Сбои и отказы являются причиной отказных ситуаций, т.е. ситуаций, в которых работоспособное состояние системы нарушается временно. Аварии являются причиной аварийных ситуаций, т.е. ситуаций, в которых работоспособное состояние системы нарушается навсегда или на длительный срок.
Можно выделить следующие три вида сбоев, вызывающих отказные ситуации.
Для классификации сбоев по категориям выделим следующие параметры сбоя.
Точка возникновения сбоя - строка или оператор программного кода, вызвавший отказную ситуацию. Данный оператор может находиться в коде системных библиотек либо в коде приложения пользователя. Вовсе не обязательно, что сбой вызван именно этим оператором, но при помощи анализа окружения вызова и исходных текстов программ обычно удается обнаружить причину отказа.
Информационное окружение системы в момент сбоя - состояние системы в момент сбоя. К информационному окружению в данном случае относятся данные, которые могут помочь в анализе причины сбоя и его устранении - например, состояние стека, значение переменных окружения, пользовательской сессии и т.п. Данный набор параметров позволяет проследить ход выполнения программы, который привел к ее сбою, и оценить несоответствия в данных, которые могли привести к сбою.
Наличие и тип сообщения о сбое - сообщение о сбое может быть создано автоматическим модулем оповещения о сбоях и содержать вышеуказанную информацию, а может создаваться пользователем вручную. Если исходить из допущения, что автоматически создаваемые сообщения посылаются разработчику всегда в случае сбоев, не приводящих к полному краху системы и вызывающих нештатное поведение системы с точки зрения операционной среды либо времени выполнения, то эта информация также помогает оценить тип сбоя.
В табл. 25.1 приведена классификация типов сбоев по указанным выше признакам.
| Параметры сбоя | Тип сбоя | ||
|---|---|---|---|
| Сбой в системном ПО | Сбой в прикладном ПО | Сбой из-за неверной технологии | |
| Точка возникновения сбоя | Системные библиотеки или Приложение | Приложение | Неприменимо |
| Информационное окружение | Ненормальное | Ненормальное | Нормальное |
| Сообщение о сбое | Пользовательское или автоматическое | Автоматическое | Пользовательское |
Отказы вызывают длительное нарушение функционирования системы, или, по ГОСТ 27.002-89 [21], приводят ее в предельное состояние. Предельное состояние - это состояние, при котором дальнейшая эксплуатация системы недопустима или нецелесообразна либо восстановление ее работоспособного состояния невозможно или нецелесообразно. Тем самым в ГОСТ 27.002-89 не делается разницы между отказом и аварией. Будем называть отказом состояние системы, при котором восстановление ее работоспособного состояния возможно.
Отказы классифицируются согласно ГОСТ 27.002-89 следующим образом.
Внезапный отказ - отказ, вызванный резким скачкообразным изменением одного из параметров системы или обрабатываемых системой данных. Ситуации, вызывающие такие отказы, могут моделироваться при
Постепенный отказ - отказ, вызванный постепенным изменением одного из параметров системы или обрабатываемых системой данных. Такой отказ может возникать, например, при переполнении внутреннего буфера, хранящего информацию о состоянии системы в каждый момент времени. Если время работы системы больше размера буфера или не предусмотрена его очистка - рано или поздно возникнет переполнение.
Перемежающийся отказ - многократно возникающий самоустраняющийся сбой одного и того же характера. Поскольку в данном случае речь идет уже о систематически проявляющемся дефекте системы, то можно говорить именно об отказе, а не о серии сбоев.
Ресурсный отказ - отказ, в результате которого система достигает предельного состояния, т.е. такой отказ вызван, в первую очередь, нехваткой ресурсов (например, дискового пространства) для работы системы. Ситуации, вызывающие такие отказы, могут моделироваться при
Конструктивный отказ - отказ, вызванный нарушением процесса проектирования и разработки системы или неверным проектированием. Процесс верификации и тестирования, в первую очередь, направлен на обнаружение дефектов, вызывающих конструктивные отказы.
Производственный отказ - отказ, связанный с нарушением процесса производства или сопровождения системы. В применении к программным системам производственные отказы могут возникать в случае неверного выполнения профилактических работ при сопровождении системы. Например, в результате выполнения профилактических работ могут быть утеряны файлы настройки системы, в результате чего она переходит в режим работы по умолчанию, несовместимый с текущими настройками оборудования. Предупреждение таких отказов состоит, в первую очередь, в корректном составлении эксплуатационной документации и документации сопровождения, которая должна быть верифицирована.
Эксплуатационный отказ - отказ, связанный с нарушением правил эксплуатации. Причины, вызывающие данный вид отказов, связаны в первую очередь с человеческим фактором. Поэтому основные способы выявления таких отказов - проведение тестирования системы на удобство использования, верификация эксплуатационной документации, введение в систему защитных механизмов, блокирующих потенциальные ошибки оператора.
Явный отказ - отказ, который обнаруживается сразу после его возникновения штатными средствами контроля состояния системы.
Скрытый отказ - отказ, который не обнаруживается штатными средствами контроля состояния системы либо обнаруживается ими спустя некоторое время после возникновения отказа. Такой отказ может послужить причиной для одного или нескольких зависимых отказов.
Независимый отказ - отказ, возникновение которого не обусловлено другими отказами.
Зависимый отказ - отказ, возникновение которого вызвано другими отказами.
Процесс верификации не гарантирует отсутствия в системе всех дефектов, которые могут вызвать сбои, отказы или аварии - речь идет только об определенном уровне отсутствия этих дефектов. Поэтому когда речь идет о системах, к надежности которых предъявляются повышенные требования, для повышения их надежности кроме верификации используются различные методы разработки устойчивого кода.
При этом в результате верификации из системы устраняются дефекты, которые могут быть выявлены при анализе требований и/или кода, а методы разработки устойчивого кода дают дополнительную гарантию того, что система сохранит работоспособность в случаях, не предусмотренных требованиями. Однако, не следует расценивать эти методы как замену верификации или грамотного проектирования.
Как уже было сказано в первых разделах данного курса, верификация не может гарантировать того, что в программной системе отсутствуют абсолютно все ошибки. В лучшем случае мы можем сделать заключение о том, что система ведет себя в соответствии с требованиями, работая на заданном оборудовании. Чтобы нивелировать возможные негативные последствия от ошибок, не обнаруженных в процессе верификации, применяются методы разработки устойчивого программного кода или методы защитного программирования.
Защитное программирование - это метод организации программного кода таким образом, чтобы при работе системы последствия проявления дефектов в ней не приводили к сбоям, отказам и авариям. При этом защитное программирование, как правило, не дает нам никакой информации о том, где в системе находится дефект, поэтому его нельзя рассматривать как полную замену верификации - эти два аспекта промышленной разработки систем лишь дополняют друг друга.
Основной метод защитного программирования - внедрение в программный код системы различного рода проверок на допустимость обрабатываемых системой данных или допустимость состояния системы в заданный момент времени. Таким образом, подход защитного программирования можно сформулировать таким образом: "Прежде чем делать что-то - проверь, с корректными ли данными и в корректный ли момент времени ты начинаешь это делать". Если все данные для работы корректны - система функционирует в нормальном режиме. В случае, если данные неверны, запускается специально разработанная часть системы, предназначенная для восстановления правильности функционирования и предотвращения сбоя (либо при помощи приведения данных к корректному виду, либо при помощи извещения оператора).
В настоящее время существует два основных механизма защитного программирования - проверка допущений в критических точках и обработка исключительных ситуаций.
В любой программе есть участки, требующие предварительных проверок перед выполнением. Например, представим себе два массива, один из которых хранит имена и фамилии людей, а второй - номера их телефонов. В нормальной ситуации количество элементов в обоих массивах должно совпадать и, при поиске фамилии в первом массиве, полученный индекс может быть использован для получения номера телефона найденного человека:
string_vector surname;
string_vector phone;
…
int index = surname.find("Петров");
foundPhone = phone.at(index);
Однако, в случае рассинхронизации двух массивов, индекс может оказаться неверным, например, выходить за границы массива. Вообще, при использовании индекса мы делаем неявное допущение о его корректности. В большинстве современных языков программирования (C, C++, C#, Java, Eiffel) существуют средства для явного задания таких допущений.
Например, в C существует функция assert(), определенная в заголовочном файле <assert.h>. Аргументом этой функции может выступать любое булево выражение. В случае, если оно равно false, функция прерывает работу программы. Таким образом, при помощи булевых выражений могут быть описаны допущения в критических точках программы. Предыдущий пример при использовании функции assert() будет выглядеть как
#include <assert.h>
…
string_vector surname;
string_vector phone;
…
int index = surname.find("Петров");
assert( (index > 0) (index < phone.size()) );
foundPhone = phone.at(index);
Часто программисты определяют свою собственную функцию assert(), например, следующим образом:
#ifdef NODEBUG
#define assert(ignore) 0
#else
#define assert(ex) \
((ex) ? 1 : \
( printf("Assertion failed "), \
abort(), 0))
#endif // NODEBUG
Эта функция отличается от стандартной тем, что в финальной сборке системы с установленным макросом NODEBUG, выдача предупреждений функцией assert() отключается. Такая организация функции assert() связана с широко распространенным заблуждением касательно того, что частые вызовы функции assert() значительно замедляют выполнение программы. Поэтому многие программисты используют допущения только на стадии отладки, считая, что они не могут сработать в конечном продукте. Однако достаточно небольшой проигрыш в скорости окупается дополнительной гарантией надежности системы.
Другая причина того, что программисты предпочитают отключать допущения в финальной версии кода, заключается в том, что при срабатывании допущения выполнение программы прерывается. Однако, существует метод использования допущений совместно с обработкой исключений (см. следующий раздел), при котором возможно определить функции, исправляющие ошибочное состояние системы и продолжающие ее выполнение.
Существует три причины использовать допущения в критических точках:
В зависимости от того, в какой критической точке проверяется допущение, выделяют следующие их типы:
Применение допущений является основной для контрактного программирования, при котором в каждом классе явно определяются предусловия для использования методов этого класса. Таким образом, между объектами этого класса и другими объектами заключается своего рода "контракт" в котором четко прописан интерфейс взаимодействия не только по форматам вызова методов, но и по пересылаемым данным.
Основным источником информации для определения контрактов являются требования на систему - функциональные или архитектурные. Поэтому верификацию допущений необходимо проводить в два этапа: на первом этапе проверяется корректность условий каждого допущения по отношению к требованиям, и только затем на втором этапе моделируются ситуации, приводящие к нарушению допущения. Начинающие тестировщики часто забывают о первом этапе, переходя от
В C++, C# и Java механизм допущений был значительно расширен. При возникновении неверных данных в критической точке вызывается не единая общесистемная функция, прерывающая выполнение программы, а пользовательская функция, которая может либо предпринять попытку разрешить проблему с данными, либо прервать выполнение программы. Возникновение проблемы в критической точке получило название исключительной ситуации или исключения, а вызываемая функция пользователя - обработчик исключения.
Рассмотрим класс, реализующий тип данных "вектор". Для получения значения элемента вектора в нем перегружается оператор [], в котором делается проверка допустимости значения индекса элемента. В качестве второго параметра функции Assert указывается метод класса, обрабатывающего исключительную ситуацию в случае, если значение индекса элемента недопустимо.
class safeVector : public vector {
public:
class outOfRangeException {
int l;
public:
outOfRangeException (const char *,
const char *, int line)
: l (line) {}
int line (void) { return l; }
};
int safeVector::operator[] (int index) {
Assert ((index >= 0) (index < size),
safeVector::outOfRangeException);
...
};
int process(safeVector v, int index) {
int elem;
try {
elem = v[index];
}
catch (safeVector::outOfRangeException e) {
cerr << "Safe Vector range exception:\n";
exit (1);
}
return elem;
}
Для того, чтобы обработчик исключения сработал, обращение к элементу массива помещается внутрь структурного блока try { }, где содержатся команды, результат выполнения которых потенциально может вызвать исключительную ситуацию. Затем внутри синтаксического блока catch { } определяется реакция на возникшую исключительную ситуацию outOfRangeException. Подобным образом можно определить реакцию на любую исключительную ситуацию.
Все исключительные ситуации, для которых определяются пользовательские функции-обработчики, должны быть описаны в проектной документации и протестированы. Хорошей практикой является создание отдельной группы тестов, которая генерирует различные исключительные ситуации и проверяет реакцию системы на них. Однако следует учесть, что не все исключительные ситуации могут быть промоделированы при тестировании, особенно интеграционном или системном - некоторые обработчики пишутся "про запас", на случай изменения других модулей системы и в реальности никогда не вызываются.
Информация о сбоях и отказах - такой же источник данных для программистов, как и информация о неуспешно пройденных тестах. Поэтому, при возникновении сбоя, отказа или аварии рекомендуется составлять отчет о проблеме, который будет передан коллективу разработчиков.
Отчет о проблеме, содержащий информацию о сбое, отказе или аварии, будет несколько отличаться от отчета, созданного в ходе тестирования. Специфика такого отчета заключается в том, что он составляется либо пользователем системы, не имеющим доступ к проектной документации и исходным текстам системы, либо специалистом службы технической поддержки со слов пользователя. Из-за этого в отчете может отсутствовать информация, которая необходима для точной локализации вызвавшего проблему дефекта.
Для упрощения работы службы поддержки и программистов рекомендуется включать в отчет служебную информацию о состоянии и окружении системы в момент сбоя - переменных окружения, активных объектах, состоянии сеанса пользователя и т.п.
Поскольку напрямую пользователю эта информация недоступна, то ее сбор должен осуществляться обработчиками исключительных ситуаций. В результате их работы должен генерироваться выходной дамп состояния системы, который прикладывается к отчету, передаваемому разработчикам для анализа причин возникновения проблемы.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.