« Поставить закладку » « Сделать стартовой »

« Форумы » « Блоги » « Статьи » « Новости » « Файлы » « Realcoding IRC » « Site map » « Поиск »


Главная Главная
Анонсы Анонсы
Форумы Форумы
Каталог Каталог
Поиск Поиск
Опросы Опросы
Книжный магазин Книжный магазин
Реклама на сайте
Публикации Публикации
Партнеры Партнеры
Карта Карта сайта
Рассылки Рассылки
RSS экспорт
Настройки Настройки
О нас пишут О нас пишут
Контакты Контакты
Гостевая книга Гостевая книга


ПнВтСрЧтПтСбВс
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  
    Популярное
Глава 1 Введение

Описание функций C (Си) / C++ - ecvt

Динамическое создание псевдонимов

Оптимизация приложений С++Builder в архитектуре клиент/сервер

Разработка технического задания

Функция GetWindowsDirectory

Установка Ruby on Rails для чайников

Компоновщик. Composite.

Функция AccessResource

Маршрутизатор многосетевого доступа




    Архив файлов



    Сообщества

    Документация

    Кто на сайте
Вы не зарегистрированы.
Имя:

Пароль:

Запомнить

Регистрация позволит Вам пользоваться дополнительными сервисами.
Сейчас на сайте:
Гостей: 173
Пользователей: 0

Статьи:: Delphi :: Разные статьи :: Delphi. Работа над ошибками



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

Delphi. Работа над ошибками



Новая страница 1

Источник - Королевство Делфи http://www.delphikingdom.com

Delphi. Работа над ошибками

Вступление

 

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

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

Выработанные правила направлены на:

  • Повышение надежности работы программы, т.е. уменьшение вероятности возникновения ошибки. Вероятность возникновения ошибки существует всегда, никто не безгрешен (включая операционную систему). Задача программиста - свести эту вероятность к минимуму.
  • Увеличение устойчивости программы - свойства, при котором она возвращается в стабильное состояние после возникновения возмущения (ошибки) (а не зависает, исчезает или уваливает операционную систему).
  • Написание единообразного и легко поддерживаемого кода.

 

Warnings and Hints

 

Компилятор Delphi снабжен "анализатором" качества кода. Он может предупреждать о потенциально опасных или бессмысленных ситуациях. Не пренебрегайте его услугами.

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

 

 

Использование констант

 

Используйте именованные константы. Это увеличивает "настраиваемость" исходного кода. А также избавляет от проблем связанных с изменением значения константы в случае ее множественного вхождения.

 

Range Check и Integer Overflow Check

 

К сожалению, эти опции компилятора по умолчанию отключены в Delphi, и многие разработчики не пользуются их услугами, а зря. Появления этих ошибок говорит о наличии в программе семантических ошибок, таких как неправильная индексация массива или использование несоответствующего целочисленного типа. Последствия этих ошибок могут быть весьма коварны. Я советую оставлять эти флаги всегда включенными, независимо от того - это отладочная или "финальная" версия программы. Лучше иметь неработающую программу (или ее часть), чем программу работающую неправильно (IMHO).

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

 

Будьте недоверчивы

 

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

  • Проверяйте значения переменных на допустимость. Особенно это касается переменных типа указатель, процедурных переменных и объектов.
  • Защищайте пары выделение-освобождение ресурсов блоками try/finally. Предполагайте, что исключение может произойти в любом операторе.
  • Используйте процедуру Assert для проверки условий, которые всегда должны быть истинными.

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

 

Значения по умолчанию и "неопределенные" значения

 

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

Правило №1:
 

  • Для указателей и объектов пустым значением должно являться значение nil.
  • Для числовых типов лучше всего резервировать значение ноль.
  • Для строковых переменных - пустая строка
  • Для перечислимых типов необходимо предусмотреть специальное значение.

Пример:
TDayOfWeek = (dwNone,dwSun,dwMon,dwTue,dwWen,dwThu,dwFri,dwSat);

 

Правило №2:
"Неопределенными" значениями лучше всего выбирать такие, чье двоичное представление соответствует нулю (нулям). Это увеличивает устойчивость, когда не выполнена начальная инициализация переменной, но произведена инициализация блока памяти, в котором она размещается.

 

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

 

Инициализация переменных и полей

 

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

Правило:
 

  • Для глобальных переменных: использовать типизированные константы, инициализированные переменные или присваивать начальные значения переменным в секции инициализации модуля.
  • Для локальных переменных: присваивать начальные значения в первых строках процедуры или функции.
  • Для полей объектов: присваивать начальные значения полям в конструкторе и не полагаться на то, что память, выделенная под объект, инициализируется нулями.
  • Массивы, записи и выделенные блоки памяти очень удобно инициализировать при помощи функции FillChar. Но, с появлением в Delphi "управляемых" (manageable) типов (длинные строки, динамические массивы, варианты и интерфейсы), пользоваться ей необходимо с четким пониманием.

 

Пример
 

 

type
  TStrArray = array[1..10] of string;
var
  A : TStrArray;
...
  FillChar(A, SizeOf(A), 0); 

 

В данном примере вызов процедуры FillChar проинициализирует строки пустыми значениями, такой подход был нормальным в ранних версиях Delphi и Borland Pascal, но недопустим в последних версиях, в которых тип string по умолчанию соответствует типу LongString и суть указатель. Если значения строк перед инициализацией были не пусты, то мы получим утечку памяти.

 

Передача параметров

 

В Delphi параметры функций и процедур по умолчанию передаются по значению. Т.е. для них выделяется область памяти в стеке или куче, куда копируются оригинальные значения. При передаче параметров сложных типов (запись, массив, строка, вариант) это сопряжено со значительными расходами ресурсов, поэтому параметры этих типов желательно передавать по ссылке, т.е. с использованием ключевых слов var или const. Замечено, что наиболее типична эта ошибка при передаче параметра типа string.

Пример
 

 

procedure Proc(s : string); //Не очень хорошо :(
procedure Proc(const s : string); //Гораздо лучше :)

 

 

Функции, процедуры и состояния

 

Для начала словарь терминов:

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

Просьба не путать эти определения с ключевыми словами function и procedure.

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

 

 

Контроль достижения предела

 

Довольно часто встречаются случаи, когда контроль достижения предела цикла осуществляется условием равенства.
Пример

	Repeat
...
	  Inc(I);
	Until I = Limit;

Что произойдет, если в результате ошибки (или просто модификации алгоритма) переменная I перескочит через значение Limit? Правильно - ничего хорошего. Более устойчивой будет конструкция с использованием условия отсечения диапазона, т.е. I >= Limit.

 

Частота выделения-освобождения ресурсов

 

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

Пример:
Допустим, в объекте есть метод DoSomething. В процессе работы он выделяет и освобождает память, которая нужна только ему. С точки зрения "выделения ресурсов по месту их использования" - все корректно, но при многократном обращении к этому методу и в случае наличия ошибки при освобождении памяти вы можете получить достаточно интенсивную утечку памяти. В данной ситуации имеет смысл рассмотреть одноразовое выделение памяти при создании объекта и освобождении при его разрушении. В данной ситуации при наличии ошибки скорость утечки будет гораздо меньше. Естественно, что данное решение необходимо рассматривать в комплексе с другими задачами (производительность, минимизация расхода ресурсов и т.д.)

 

 

Область использования переменных

 

Много сказано и написано на эту тему. Но еще раз повторюсь:

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

 

Интерфейсы объектов

 

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

 

"Просачивание" исключений в библиотеках

 

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

Пример

 

try
...
{Я столкнулся с подобным кодом в библиотеке ODBCExpress в 
 процессе написания NT сервиса J.}
exception
  //Очень нехорошо
  on Exception do 
    ShowMessage('Something wrong's happened :-('); 
end; 

 

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

 

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

 

Любой модуль можно логически разделить на две части:

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

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

 

Пример

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

Я столкнулся с описанной проблемой при написании серверного приложения без GUI, которое взаимодействует с базой данных. Где-то в недрах DBxxx компонент есть ссылка на модуль Forms. Эта "особенность" была замечена в Delphi 5, скорее всего эта проблема имела место и в предыдущих версиях. Справедливости ради надо отметить, что в Delphi 7 эта особенность устранена.

 

Циклические ссылки модулей и "осведомленность" сущностей

 

Технически, Object Pascal позволят создать циклические ссылки между модулями. Их наличие в программе или библиотеке свидетельствует о не очень удачной декомпозиции (IMHO). Негативными последствиями их использования есть:

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

Правило:
Избегайте использования циклических ссылок модулей. Старайтесь организовать "осведомленность" сущностей древовидной (сущности верхнего уровня знают о существовании сущностей нижнего уровня, но не наоборот). Обратное взаимодействие можно реализовывать посредством механизма событий (процедурных переменных) или при помощи сущностей "посредников".

 

Пример

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

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

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

 

Исключения в обработчике события OnTimer

 

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

Решить данную проблему можно несколькими способами:

  • Обрабатывать исключения непосредственно в обработчике события
    try
    except
      on E: Exception do Application.ShowException(E);
    end;		
  • Использовать централизованный обработчик исключений, который фиксирует их в протоколе или журнале, но не выдает никаких сообщений об ошибке.
    Application.OnException := MyExceptionHandler;

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

 

Заключение

 

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

С уважением,
Андрей Банин




Рубрика: Разные статьи




HTML 5: пять вещей вызывающих особый интер....

Html

HTML 5 — это грядущее обновление гипертекстового языка разметки, основного способа создания контента для размещения его во всемирной паутине. Разработка HTML остановилась в 1999 году, на версии HTML 4.01 и с тех пор web-содержимое изменилось так, что текущие спецификации HTML перестали соответствовать сегодняшним требованиям. HTML 5 нацелен на то, чтобы увеличить функциональную совместимость HTML и соответствовать растущим требованиям разнообразного и смешанного web-контента. HTML 5 так же нацелен на устранение недостатков четвертой версии. В этой статье мы взглянем на 5 новых интересных вещей в HTML 5.


Подробнее... | Рубрика: Html | Добавлено: 22.12.2008

asp.net: ListView с разных сторон.

.NET компоненты

Элемент управления ListView был представлен в .Net Framework 3.5 как замена устаревшему GridView. Новый элемент имеет более расширенный функционал, чем его предшественник, но в тоже время лишен некоторых внутренних механизмов, что впрочем целиком следствие из расширенной универсальности ListView. Среди отличий ListView и GridView можно назвать и гибкую настройку разметки, что позволяет выводить данные не только в табличном виде, но и вообще в любом каком пожелает программист. Благодаря шаблонам ItemTemplate, EditItemTemplate, InsertItemTeplate можно настроить внешний вид при любом из состояний ListView: редактировании или выборе элемента.


Подробнее... | Рубрика: .NET компоненты | Добавлено: 22.12.2008

Создание кросс-таб отчета в Stimulsoft Rep....

.NET компоненты

Компания Стимулсофт предоставляет для разработчиков мощный набор инструментов для создания отчетов для Microsoft Visual Studio .Net 2005 и 2008; эти инструменты доступны как для Windows Forms, так и для Web Forms. Это генератор отчетов Stimulsoft Reports.Net. Генератор отчетов Stimulsoft Reports.Net имеет ряд особенностей: простая работа с дизайнером отчетов, полная поддержка экспорта в PDF, Word, Excel и многие другие форматы. Crystal Report и Microsoft Reporting Service – очень хорошие программные продукты для повседневной работы, но, если Вам необходимо создать отчеты с поддержкой кросс-табов, drill down, Ajax, штрих-кодов и возможностью подключения одновременно более одного источника данных, то Stimulsoft Reports.Net поможет Вам сэкономить массу времени. Также, данный генератор отчетов позволяет пользователям создавать свои собственные отчеты любой сложности. И все эти особенности делают Stimulsoft Reports.Net хорошим выбором в сфере программных продуктов для Business Intelligence.


Подробнее... | Рубрика: .NET компоненты | Добавлено: 22.12.2008

Остальные статьи:

VivaMP - инструмент для OpenMP
Создаем контекстно-зависимое WPF-приложени...
Windows Vista SP2: что внутри и что важно?
Вышел MySQL 5.1.30, первый стабильный рели...
Тестирование параллельных программ
Архитектура AMD64 (EM64T)
Платформа 2009. Определяя будущее
Windows Vista Bridge Sample Library - упра...
Оптимизация 64-битных программ
Подгрузка через AJAX HTML-кода, содержащег...
Обзор нового релиза самой мощной Ajax библ...
Firebug 1.3 и 1.4 alpha — что нового и инт...
Релиз Microsoft Silverlight 2.0. Что новог...
XML документация в C#
Курсоры в MySQL 5
Microsoft опубликовала подробности о сесси...
Microsoft делится подробностями о том, что...
Тестируем новый javascript от нового брауз...
MySQL Query Cache
Использование провайдеров компиляции в As...


Цитата дня (все,добавить):

Портал фрилансеров

работа на дому


    Рубрикатор

Программирование

C/С++
Обучение
Windows API
XAML
Моделирование
Паттерны
Visual Basic 7 .NET
WxWidgets
Функции WinApi
Функции С++
Разработка под Mac OS
Eiffel
Visual Studio 2008
UI дизайн
Алгоритмы
Конкурсные статьи
Turbo Pascal
Visual Studio
CASE-средства
Visual Studio 2005
Без VCL
Delphi
Тех. документация
Тестирование
Software Testing
ООП
TCP/IP
Google Android
Windows Installer
.NET Framework
Драйвера
C# C Sharp
Справка
Проектирование
Информ. системы
Visual Basic
Assembler
Оптимизация кода
Gtk+
Компоненты
Реинжиниринг
Управление проектами
Extreeme programming
Lotus Notes
Алгебраическое проектирование


Интернет технологии

PHP
Perl
ASP
WAP
Cookies
SSI
CGI
Web Servers
VB Script
DNS
CSS
XML
Html
Java Script
Java2ME
Firewall
Flash
.htaccess
Apache
VRML
Протоколы
Поисковые системы
Технология JAVA
Учебник по PHP
Учебник по JavaScript
Учебник по XML
Java Q&A
AJAX
DHTML
XHTML
Dreamweaver
Web 2.0
Python
Вебмастеру
Cisco
Ruby on Rails
Silverlight

Базы данных

Access
InterBase
MySQL
Oracle
ADO .NET
Основы SQL
Учебник по Access 2002
MS
Microsoft FoxPro
Доступ к данным
XML в MS SQL Server 2000
ODBC и MyODBC
Обучение
Caché
DB2
PostgresSQL
Sybase
Теория
Хранилища данных
Безопасность
Реляционные данные
MySQL и mSQL

Остальное:

Разное
Обзоры книг
Безопасность
Графика и дизайн
Юмор
Linux
Фракталы
Microsoft Axapta
Многоядерность
Сети
Microsoft Office
Работа
MS-DOS
Криптография
Графика и игроделание
Новости SDK
Системы защиты
Учебник по AutoCad
CVS
Windows XP
Windows Server 2003
Windows Vista
Windows 7
Мероприятия