http://programmingmindstream.blogspot.ru/2014/02/assert-vs-exception.html?showComment=1392358212790#c3301455318549552072
Цитирую:
«Побоюсь показаться БАНАЛЬНЫМ, но я много видел в коде примерно следующее:
Assert(Supports(SomeClass, SomeInterface, Instance));
Instance.DoSomeMethod;
Понятно, что ПРАВИЛЬНО было написать так:
if Supports(SomeClass, SomeInterface, Instance)) then
Instance.DoSomeMethod
else
Assert( false );»
-- Не понятно - поясните.
Первый вариант нахожу всем лучше второго, за исключением особенности Assert, состоящей в том, что при сборке версии для пользователя (без отладки) Assert-ы удаляются компилятором.
Ввиду этой особенности, Assert не используется вообще, вместо него применяется своя процедура Contract:
«resourcestring
SEContractViolation = 'Произошла внутренняя ошибка программы. Обратитесь к разработчику.';
SEViolationDetails = 'Служебная информация: модуль %s, строка %d';
procedure Contract(ACondition: Boolean; const AMessage: String = '');
var
ExceptAddr: Pointer;
location: TLocation;
message: String;
begin
if ACondition then Exit;
// получаем адрес места, откуда вызвали Contract
asm
mov EAX, [EBP+$04]
mov ExceptAddr, EAX
end;
if Assigned(GetLocationProc) then
location := GetLocationProc(ExceptAddr);
if AMessage = '' then
message := SEContractViolation
else
message := AMessage;
raise ESContract.CreateFmt(message + ^M^J + SEViolationDetails, [location.SourceName, location.LineNumber]) at ExceptAddr
end;»
которая и применяется в версии для пользователя.
Конец цитаты.
Скажу коротко.
Assert и Contract это РАЗНЫЕ инструменты. Два разных инструмента.
Assert это ИНВАРИАНТ, это то, что у пользователя НЕ СЛУЧАЕТСЯ в принципе.
Контракт это НЕ ИНВАРИАНТ, а защита, от того, что "а вдруг чего случится" или "а вдруг недодумали".
И я ПРАКТИЧЕСКИ УВЕРЕН, что NameRec это понимает.
И ОСОЗНАННО применяет только ОДИН из них.
Ну что же. Каждый имеет право на выбор.
И выбор - осознанный.
Я же применяю ОБЕ техники. Мне лично - это ближе.
Никому ничего не навязываю.
P.S. Да! И СПАСИБО NameRec'у за ХОРОШИЙ вопрос. Тему на самом деле можно развивать и дальше.
Цитирую:
«Побоюсь показаться БАНАЛЬНЫМ, но я много видел в коде примерно следующее:
Assert(Supports(SomeClass, SomeInterface, Instance));
Instance.DoSomeMethod;
Понятно, что ПРАВИЛЬНО было написать так:
if Supports(SomeClass, SomeInterface, Instance)) then
Instance.DoSomeMethod
else
Assert( false );»
-- Не понятно - поясните.
Первый вариант нахожу всем лучше второго, за исключением особенности Assert, состоящей в том, что при сборке версии для пользователя (без отладки) Assert-ы удаляются компилятором.
Ввиду этой особенности, Assert не используется вообще, вместо него применяется своя процедура Contract:
«resourcestring
SEContractViolation = 'Произошла внутренняя ошибка программы. Обратитесь к разработчику.';
SEViolationDetails = 'Служебная информация: модуль %s, строка %d';
procedure Contract(ACondition: Boolean; const AMessage: String = '');
var
ExceptAddr: Pointer;
location: TLocation;
message: String;
begin
if ACondition then Exit;
// получаем адрес места, откуда вызвали Contract
asm
mov EAX, [EBP+$04]
mov ExceptAddr, EAX
end;
if Assigned(GetLocationProc) then
location := GetLocationProc(ExceptAddr);
if AMessage = '' then
message := SEContractViolation
else
message := AMessage;
raise ESContract.CreateFmt(message + ^M^J + SEViolationDetails, [location.SourceName, location.LineNumber]) at ExceptAddr
end;»
которая и применяется в версии для пользователя.
Конец цитаты.
Скажу коротко.
Assert и Contract это РАЗНЫЕ инструменты. Два разных инструмента.
Assert это ИНВАРИАНТ, это то, что у пользователя НЕ СЛУЧАЕТСЯ в принципе.
Контракт это НЕ ИНВАРИАНТ, а защита, от того, что "а вдруг чего случится" или "а вдруг недодумали".
И я ПРАКТИЧЕСКИ УВЕРЕН, что NameRec это понимает.
И ОСОЗНАННО применяет только ОДИН из них.
Ну что же. Каждый имеет право на выбор.
И выбор - осознанный.
Я же применяю ОБЕ техники. Мне лично - это ближе.
Никому ничего не навязываю.
P.S. Да! И СПАСИБО NameRec'у за ХОРОШИЙ вопрос. Тему на самом деле можно развивать и дальше.
Действительно, есть достаточно большой положительный опыт применения именно контрактов, которые контролируются при выполнении приложения у пользователя. Протестировать всё на 100% нереально, но нарушение контракта приводит к исключениям, попадающим в лог вместе со стеком вызовов, что часто помогает выявлению причин и исправлению проблемы.
ОтветитьУдалитьЯ тоже никому ничего не пытаюсь навязать, но с давних пор меня смущала ограниченность Assert.
Им можно воспользоваться только при "белом тестировании", которое может выполнять только программист, на настоящее тестирование (по крайней мере у нас) такая версия никогда не передаётся, поскольку тестированию должно подвергаться приложение, которое уйдёт пользователю, а не какая-то специальная версия с отладочной информацией.
"Белое" же тестирование у нас практически не востребовано. Понятно, если ищем ошибку - включается всё, и отладка и FullDebugMode у FastMM... Тут могли бы работать и Assert, но толку от них... Они будут только уводить от проблемы, которая возникает на реальной версии (без отладки), и вообще, какой смысл искать ошибки в версии программы, отличной от того, что будет передано пользователю...
А раз так, то Assert для нас совершенно бесполезен.
Ну, разве что, при автоматизированном тестировании. Но в тестах всё равно, что использовать: Assert или Contract.
Contract для нас привычнее и больше соответствует принципу наименьшего удивления. Кроме того, а если код из тестов мигрирует в приложение? Там-то Assert нежелателен...
Ну и, разумеется, было бы интересно узнать, как и где применяют Assert люди, находящие его полезным...
Идея понятна. Я сам этим пользуюсь. Assert же я применяю, как вы правильно заметили в "белом тестировании".
УдалитьВдогонку... Мы могли бы продолжить "спорить", но разве что только для "углубления темы".
ОтветитьУдалить