пятница, 23 марта 2012 г.

Урок 38. Обработчик ошибок

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

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

Первый вопрос, который я предвижу от слабо посвященных: "А зачем?"
Действительно, пишешь задачу, как "честная кнопка", пытаешься ничего не упустить, все предусмотреть, собственное творчество, как правило, себе нравится, и не вызывает сомнений правильность его алгоритма... И все же! Если задачка небольшая - все просто и прозрачно. Но, если алгоритм сложен... как говорят "глаз замыливается", перестает находить узкие места. К тому же накладывается человеческий фактор: откуда Вам было знать, что пользователь не введет значение в поле и нажмет "Enter"?.. В этот момент Ваша программа напугает его каким-нибудь англоязычным сообщением да еще и с пиктограммой "Error"... А, если Вы помните, я с самого начала просил Вас уважать пользователя и заказчика. Стоит ли доводить ситуацию до общения с плохо вменяемым пиплом?! Если Вы не хотите общаться с человеком, у которого от испуга вытаращены глаза и трясутся руки, нужно научиться предугадывать (перехватывать) ошибки и выдавать на экран сообщения на родном для пользователя языке, желательно с номером Вашего телефона... Это и есть часть понятия "дружественный интерфейс".

Следующий вопрос, к которому я хочу приблизить тебя, дорогой читатель, это вопрос:

где и когда нужен обработчик ошибок?

Стоит ли, на эту тему рыться в учебниках? И "да", и "нет". Почему? Программа, о которой в настоящий момент идет речь ("Расходы"), работает с базой данных, а найти в книжках этот материал - ой как не просто, поскольку большую часть книжного пространства авторы отводят, как правило, обучению работе с базой данных (создание, подключение, запросы и т.п.). Можно долго и упорно рыться в интернете, гуглить яндекс и задавать вопросы на форумах - в конце концов, Вы соберете нужную инфу, но упустите время...

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

Чем большим количеством подобных вопросов Вы себя озадачите, тем меньше вероятность того, что Ваша программа в руках незадачливого пользователя перейдет в состояние "Не отвечает".

Наиболее общая схема обработчика ошибок выглядит примерно так:

  • Объявление необходимых переменных и присвоение им стартовых значений.
  • Выполнение основного алгоритма, в процессе которого проверяются возможные условия возникновения ошибок
  • Обработка ошибок
  • Выдача сообщения оператору
Я предлагаю вернуться к предыдущему уроку и на примере описанных в нем процедур "сочинить" несложный обработчик ошибок.

Добавьте в объявление переменных в процедуре SetLang() еще парочку:

Var
  ini: TIniFile;
  ErrKod: integer;
  ErrMsg: String;

а так же - объявление метки:

Label
  ErrLabel;

и стартовые значения:


begin

  ErrKod:=0;                                    // Это значение при отсутствии ошибок
  ErrMsg:= 'Операция завершена успешно';

Настройте заранее (в начале процедуры) компонент, выдающий сообщения:


  MyMessenger.TitleString:='Ошибка...';
  MyMessenger.MessageType:=mtError;
  MyMessenger.Buttons:=[mbOK];


Затем - напишите проверку наличия файла языковой поддержки:


  If Not FileExists(GetCurrentDir + '\'+Lang)
  then
  begin
    ErrKod:=1;
    ErrMsg:='При попытке открытия файла языковой настройки произошла ошибка';
  end;


Почему именно здесь нужно предусмотреть какие-то действия? А вдруг в файле настроек указан несуществующий файл? Или его кто-то с диска того... нечаянно стер...

Следом должна идти проверка на наличие ошибок:


  if ErrKod>0
  then
    Goto ErrLabel;


...


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


...


ErrLabel:


    MyMessenger.MessageString:=ErrMsg;
    MyMessenger.ShowMessage;


end;        // Процедуры


Давайте нашалим: переименуем файл Rus.lng, например в Rus1.lng, чтоб программа его уж точно не нашла.

Тогда при старте Rashod.exe будет произведена попытка настроить интерфейс приложения с помощью указанного в файле настроек Rashod.ini, в секции [Constants], в переменной LangFileName файла Rus.lng, которого в рабочем каталоге нет. Сработает обработчик ошибки, и на экране будет выведено придуманное нами сообщение:


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

Верните переименованному файлу его законное название и запустите программу еще раз.
Вы получите еще одно сообщение:


не корректное по оформлению и неуместное по сути (если ошибок нет, нужно ли в данном случае вообще выводить какое-то сообщение?!).

Давайте поправим ситуацию:

ErrLabel:

  Case ErrKod of
    0:                               // Ошибок нет
    else
    begin
      MyMessenger.MessageString:=ErrMsg;
      MyMessenger.ShowMessage;
    end;

  End;

end;        // Процедуры


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

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





2 комментария:

  1. Анонимный23/3/12 18:44

    На сайте много полезной информации, которую не скоро найдешь в учебниках. Материал преподносится доступным языком. Но у меня есть одно замечание по оформлению сайта. Плохо читается текст, особенно зеленый на черном. Зачем такой мрачный фон? На более светлом фоне темный (контрастный) шрифт будет читать намного легче и приятнее.

    ОтветитьУдалить
    Ответы
    1. Спасибо.

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

      Я обязательно учту Ваше предложение при подготовке следующих постов.

      Удалить