А теперь рассмотрим другой случай. Предположим, что мы разрабатываем функцию, которая должна разворачивать данные из файла, например, из архива. Формат сжатого файла достаточно сложен, по крайней мере, он считается простой последовательностью битов, и все последовательности выглядят примерно одинаково. Если в последовательности битов функция разархивирования встретит ошибку (например, последовательность исчерпана, но логически она не закончилась), будет это утверждением или же исключением? По мнению автора, это должно быть простым исключением. Вполне вероятно, что функции в качестве входных данных будут переданы поврежденные файлы или файлы, которые не являются архивами в требуемом формате. Очевидно, что это ошибка не программиста. Она полностью вызвана внешними условиями.
Таким образом, утверждения служат для проверки качества работы программиста и предупреждают о наличии его собственных ошибок в коде, а исключения возникают в ситуациях, когда программа используется в условиях, для которых она не предназначена.
Это правило выглядит достаточно просто:
----
Правило № 3. Помещайте в код комментарии. Объясняйте ваши допущения (более того, проверяйте их с помощью утверждений). Описывайте сложные блоки кода. При изменении кода изменяйте и соответствующие комментарии. Не допускайте, чтобы комментарии устаревали.
----
Рассмотрим еще одно средство из арсенала защитного программирования -протоколирование (logging). Под протоколированием здесь понимается вставка дополнительного кода, закрытого директивами компилятора, который записывает в файл состояние или значения основных переменных.
Этот метод уходит корнями в те времена программирования на языке Pascal, когда программисты при любом удобном случае вставляли оператор writeln и надеялись, что он поможет обнаружить ошибку. В наши дни ценность этого метода существенно снизилась. Автор книги зачастую для протоколирования состояния классов пишет методы DumpToFile. Их можно помещать в условные блоки компилятора, вызывать несколько раз в стратегически важных точках и получать описание всего жизненного цикла определенного объекта.
----
Правило № 4. Пишите код протоколирования и защищайте его директивами компилятора. Однажды протокол может пригодиться, и вполне вероятно, что такой день таки наступит.
----
В кодах, приведенных в книге, будут приведены примеры использования этого метода.
В прошлом трассировка была тесно связана с протоколированием. Трассировка (tracing) представляла собой метод вставки операторов writeln в начале и в конце функций. Операторы применялись для вывода на экран или в файл таких простых сообщений, как "Вход в функцию X" или "Выход из функции X". Запись сообщений в файл помогала восстановить ход выполнения приложения и порядок вызова функций. В настоящее время существуют специальные программы, которые делают все это сами, без участия программиста. Приложение запускается внутри такой программы, а она автоматически идентифицирует все функции и подпрограммы, их начало и завершение, и формирует журнал трассировки приложения. Никаких изменений вносить в код не потребуется.
В последнее время большинство программистов не пользуются трассировкой. Намного проще запустить отладчик и при возникновении ошибки просмотреть стек вызовов.
Это современный метод и для его использования вам понадобится специальное программное обеспечение. Анализ покрытия (coverage analysis) представляет собой запись в журнал того, какие операторы приложения были "покрыты", т.е. выполнены. Если при тестировании отдельная строка или блок кода не выполняются, в этой строке или блоке может содержаться ошибка. Такую ошибку можно будет выявить только с помощью теста, при выполнении которого выполняется код с ошибкой.
----
Правило № 5. При тестировании пользуйтесь анализатором покрытия. Убедитесь, что во время тестирования выполняются все строки кода.
----
Тестирование модулей (unit testing) представляет собой процесс тестирования отдельных частей независимо от самой программы.
Одним из новых методов разработки программного обеспечения, который появился уже при написании этой книги, является экстремальное программирование (extreme programming)[3]. Этот метод состоит в целом наборе рекомендаций. Некоторые рекомендации достаточно спорны, но, по крайней мере, одна из них имеет смысл: пишите тест тогда, когда вы пишете метод класса. Если метод требует не одного теста, разработайте несколько тестов. Такой порядок обладает двумя преимуществами: во-первых, код вам знаком - вы только что его написали, и, во-вторых, в дальнейшем разработанный тест может быть включен в тестовый набор и применяться для тестирования приложения после внесения в него изменений. Таким образом, вы можете быть уверены, что изменения не повлекли за собой возникновение ошибок.
Читать дальше