Файл: Освой самостоятельно программирование для MS Access 2002 за 24 часа [П.Киммел].pdf

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 21.10.2020

Просмотров: 7949

Скачиваний: 25

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
background image

Не используйте конструкции, подобные If

 > 0)

Then, непосредственно. Заключите эту строку в тело функции и дайте
последней четкое название, скажем, Function FileExists

 File-

Name As String) As Boolean. В этом случае код приобретет ясность и
будет удобным для чтения.

Во время отладки вместо задания точки останова в строке If

 Then достаточ-

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

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

чены рамками редактора VBA. А верификаторы — это неотъемлемая и самодостаточ-
ная часть кода. Впрочем, ищите "золотую" середину.

Использование соглашений

ЕСЛИ над проектом трудится целая команда специалистов, зачастую применяется

стиль программирования, основанный на использовании соглашений.

 Соглашение

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

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

ваться этой функцией, обязан сам позаботиться о существовании файла, поскольку
соответствующая проверка вами не предусмотрена.

Теперь вы можете сосредоточить внимание непосредственно на проблеме

(пополнения файла данными) и значительно уменьшить объем кода за счет исключения

дополнительных проверок. Да, но как обеспечить выполнение соглашения? Можно, ко-

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

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

Соглашения — это неплохо, но лучше, если они будут подкреплены верификаторами

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

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

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

Повторное использование кода отладки

Вспомогательный код (как и любой другой код) нуждается в отладке. Однако, при-

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

 Trace, Trap

 и

 Assert.

 Напишите подобные функции один раз, отладьте их,

экспортируйте модуль в файл (скажем,

 а затем импортируйте по мере не-

обходимости в каждый новый проект.

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

эффективно.

17-й час. Отладка кода 305


background image

Использование директив компилятора

Ни в коем случае не следует избавляться от отладочного кода после завершения проце-

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

 написанный и распро-

страненный, начинает жить своей собственной жизнью. Не исключено, что со временем

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

Если вы написали множество замечательных отладочных процедур, а затем, нака-

нуне передачи приложения в эксплуатацию, решили их удалить (как казалось, за не-

надобностью), в дальнейшем, при необходимости внесения изменений, придется все

это восстанавливать. Как же быть? На помощь приходят директивы компилятора.

Директивам компилятора в тексте программы предшествует символ фунта (#).

 Ди-

рективы компилятора —

 это инструкции, указывающие, что делать с тем или иным

блоком кода во время его компиляции. Наиболее частое применение в них находят

константы и условные управляющие структуры. Обычно с помощью служебного слова

#Const задается именованная константа, а затем строится управляющая структура ви-

да

 If, охватывающая блок кода и проверяющая с помощью значения

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

Конструкция If

 End If — это вовсе не то же самое, что

#End If. Первая представляет собой полноправную часть кода, а вторая

действует лишь во время его компиляции.

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

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

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

единственной константы. Листинг 17.3 демонстрирует приемы использования кон-

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

файл отладочную конструкцию или нет.

Листинг 17.3. Пример использования условной директивы компилятора

 Sub Test ( )

2:

 DebuggingOn = True

3: #If DebuggingOn Then
4:

 SomeBooleanValue

5: iEnd If
6 : End Sub

I Листинг 17.3 содержит пример верного с формальной точки зрения ис-

I пользования директив компилятора. Поскольку значение константы De-

buggingOn равно True, код строки 4 будет включен в откомпилирован-

ную версию программы.

 изменить значение константы Debuggin-

gOn на

 при следующей компиляции строка 4 не будет включаться

в исполняемый код. В любом случае (независимо от значения константы)

строк 2, 3 и 5 в откомпилированном коде не будет.

Текст процедуры Test технически правильный, но он достаточно скромный в

практическом отношении. Дело в следующем. Если вы будете действовать таким обра-

зом и далее, придется обрамлять конструкциями

 f буквально каждый

вызов метода Assert и других отладочных функций. Поэтому более целесообразно

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

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

ректив компилятора.

306

Часть VI. Работа над ошибками


background image

Листинг 17.4. Пример процедуры верификации с условной директивой компилятора

 DebuggingOn = True

 False

Sub

 Test As Boolean,

 FileName As String, ByVal

 As Long)

ttlf DebuggingOn Then

 Test

 If

End Sub

Недостаток — впрочем, единственный — этого метода заключается в том,

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

Процедуры верификации хорошо развиты в языках С и C++, поскольку

конструкция Assert реализована в них в виде макроса. Ее код
автоматически включается компилятором в те места текста программы,
в которых выполняется обращение к Assert. VBA такой возможностью
не обладает. (В данном случае речь не идет об обычных макросах
Access — говорится о макросах как о механизме развития директив
компилятора.)

Чтобы увидеть содержимое стека вызовов (напомним, что программа в случае не-

удачной верификации приостанавливает свое выполнение в строке, содержащей De-
bug. Assert), обратитесь к команде меню

 Stack окна редактора VBA. Вто-

рой сверху элемент списка, отображаемого в диалоговом окне Call Stack, указывает на
строку кода, вызвавшую приостановку в момент верификации. Рис.

 соответствует

ситуации, когда процедура Assert вызывается из некоторой процедуры SomeCode-
ToTest при условии, что в качестве аргумента Test передавалось значение False.

Рис.

 Диалоговое окно Call Stack позволя-

ет увидеть содержимое стека вызовов и бы-
стро перейти к строке кода, содержащей об-

ращение к процедуре или функции

Главная особенность структуры данных, называемой

 стеком,

 состоит в том, что

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

"вошедший" элемент первым же и "выйдет". Информация о последовательности об-
ращений к функциям и процедурам сохраняется в так называемом

 стеке вызовов.

Всякий раз, когда одна функция или подпрограмма вызывает другую, стек пополняет-

ся, а при завершении последней вызванной функции (процедуры) элемент, располо-

17-й час. Отладка кода

307


background image

 на вершине стека, удаляется из него. Если щелкнуть на элементе списка, ил-

люстрирующего стек вызовов, а затем на кнопке Show диалогового окна Call Stack

(см. рис.

 текстовый курсор в окне редактора перейдет на строку, содержащую

вызов. Так, например, щелчок на элементе

 .SomeCodeToTest в представлен-

ном на рисунке примере приведет к переходу курсора на строку, в которой содержит-
ся обращение к процедуре Assert.

Теперь, умея обращаться с условными директивами компиляции, вы можете не

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

 в покое. Возложите обязанности по его сохранению или изъятию на

компилятор. Для этого достаточно изменить значение единственной константы и пе-
рекомпилировать приложение.

Не нужно "обрамлять" условными директивами компиляции каждый вызов отла-

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

(функции). Другое немаловажное преимущество подобного подхода заключается в

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

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

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

 содержащего полный набор отла-

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

Листинг 17.5.

 — набор отладочных процедур

Option Compare Database
Option Explicit
iConst DebuggingOn = True
Private Sub DoTrap(ByVal

 As String,

 As Long)

 "Ловушка:

 & FileName &

 & TrapNumber &

Stop

End Sub

Sub

 FileName As String, ByVal TrapNumber As Long)

9 #If DebuggingOn Then
10: Call

 FileName, TrapNumber )

11:

 If

 Sub

 Sub

 ByVal FileName As

14: ByVal

 As Long, ByVal TraceMessage As Variant)

15: Dim Output As String
16: Output =

 & FileName &

 &

 TraceNumber &

 в

 & Now & vbCrLf &

18: TraceMessage & vbCrLf
19:

 Output

 Sub

 ByVal FileName As String,

ByVal TraceMessage As String, ByVal TraceNumber As Long)

22: #If DebuggingOn Then
23: Call

 TraceMessage, TraceNumber)

24:

 If

 Sub

 Sub

 Test As Boolean,

ByVal FileName As String, ByVal

 As Long)

27:

 Test

 Sub

308

Часть VI. Работа над ошибками


background image

 Test As Boolean,

 FileName As String, ByVal

 As Long)

30: ttlf DebuggingOn Then

31: Call

 FileName, AssertNumber)

32:

 If

 Sub

Как уже неоднократно отмечалось, предпочтительно писать короткие
процедуры и функции. Просмотрев листинг 17.5, вы не увидите
процедур длиннее трех-пяти строк. Функциональная часть (скажем,

DoAssert) отделена от "условно-директивной" (Assert).
Встречаются программисты, которые буквально в штыки принимают

подобный стиль работы. Я же мотивирую свои действия удобством и

универсальностью подхода

 • - мы уже говорили о

нем: дели проблему на мелкие обозримые части, и ее решение упростится.

В листинге

 функциональная часть кода отладочных процедур отде-

I лена от условных конструкций компилятора. В этом случае можно вос-

пользоваться процедурами тестирования даже тогда, когда отладочный
режим отключен (т.е. константа DebuggingOn равна False). Эти проце-

дуры, в названия которых введен префикс

 Do,

 объявлены посредством

служебного

 Private, предотвращающего возмож-

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

(Подробнее о применении подобных средств см. главу "21-й час. Основы
программирования

Отладочный код — только для чтения

Отладочный код — это код только для чтения. Другими словами, наличие отладоч-

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

"срабатывают" условные директивы компилятора или нет. Программа должна рабо-

тать одинаково в обоих случаях — с отладочным кодом и без такового.

Различные типы кода обработки ошибок

Конструкции, обрабатывающие ошибки периода разработки программы, дают вам,

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

должен гарантировать, что программа будет работать с различными наборами исход-

ных данных и в любых ситуациях.

Чаще всего целесообразно наряду с отладочными выражениями использовать и

конструкции обработки ошибок, служащие неотъемлемой частью кода приложения.

Например, если файл должен существовать (это условие гарантирует возможность его

дальнейшего открытия), можно применить верификатор, позволяющий протестиро-

вать код во время разработки, а также включить в текст постоянную конструкцию,
проверяющую факт существования файла:
Call

 FileName

 1 )

If

 FileName

 Какой-то код

17-й час. Отладка кода

309