Programming

주장은 악한가?

procodes 2020. 5. 10. 11:50
반응형

주장은 악한가? [닫은]


Go언어 제작자는 쓰기 :

Go는 어설 션을 제공하지 않습니다. 그것들은 명백히 편리하지만, 프로그래머들은 적절한 오류 처리 및보고에 대한 생각을 피하기 위해 그것들을 목발로 사용한다는 경험이 있습니다. 적절한 오류 처리는 치명적이지 않은 오류 후에 서버가 충돌하지 않고 계속 작동 함을 의미합니다. 적절한 오류보고는 오류가 직접적이고 정확한 시점에 있음을 의미하므로 프로그래머는 큰 충돌 추적을 해석하지 않아도됩니다. 정확한 오류는 프로그래머가 오류를보고 코드에 익숙하지 않은 경우 특히 중요합니다.

이것에 대한 당신의 의견은 무엇입니까?


아니요, assert의도 한대로 사용하는 한 아무 문제가 없습니다 .

즉, 일반적인 오류 처리와는 달리 디버깅 중에 "발생할 수없는"경우를 포착하기위한 것입니다.

  • 어설 션 : 프로그램 논리 자체에 오류가 발생했습니다.
  • 오류 처리 : 프로그램의 버그로 인한 잘못된 입력 또는 시스템 상태입니다.

아니요, 악도 goto아닙니다 assert. 그러나 둘 다 오용 될 수 있습니다.

어설 션은 상태 점검을위한 것입니다. 올바르지 않은 경우 프로그램을 종료해야하는 것. 유효성 검사 또는 오류 처리를 대체하지 않습니다.


이 논리에 따르면 중단 점도 악합니다.

어설 션은 디버깅 보조 도구로 사용되어야합니다. "악"은 오류 처리 대신 사용하려고 할 때 입니다.

프로그래머는 존재하지 않아야하는 문제를 감지하고 수정하고 가정이 사실인지 확인하는 데 도움이됩니다.

오류 처리와는 아무런 관련이 없지만 불행히도 일부 프로그래머는 오류를 악용 한 다음 "악"이라고 선언합니다.


나는 assert를 많이 사용하고 싶다. 처음으로 응용 프로그램을 구축 할 때 (아마도 새로운 도메인) 매우 유용합니다. 매우 고급스러운 오류 검사 (조기 최적화를 고려할 것) 대신 빠르게 코딩하고 많은 주장을 추가합니다. 작동 방식에 대해 더 많이 알고 난 후에는 다시 작성하고 일부 어설트를 제거하고 더 나은 오류 처리를 위해 변경합니다.

주장으로 인해 코딩 / 디버깅 프로그램에 많은 시간을 소비하지 않습니다.

또한이 주장은 프로그램을 망칠 수있는 많은 것들을 생각하는 데 도움이된다는 것을 알게되었습니다.


프로그램에서 버그를 탐지하는 데 사용해야합니다. 나쁜 사용자 입력이 아닙니다.

올바르게 사용하면 아닙니다 .


추가 정보로서 go는 내장 기능을 제공합니다 panic. 대신에 사용할 수 있습니다 assert. 예 :

if x < 0 {
    panic("x is less than 0");
}

panic스택 추적을 인쇄하므로 어떤 식 으로든 목적이 assert있습니다.


이것은 많이 나오며 어설 션 방어를 혼란스럽게 만드는 한 가지 문제는 종종 인수 확인을 기반으로한다는 것입니다. 따라서 어설 션을 사용할 수있는 다음과 같은 다른 예를 고려하십시오.

build-sorted-list-from-user-input(input)

    throw-exception-if-bad-input(input)

    ...

    //build list using algorithm that you expect to give a sorted list

    ...

    assert(is-sorted(list))

end

때때로 입력이 잘못 될 수 있기 때문에 입력에 대해 예외를 사용합니다. 알고리즘에서 버그를 찾는 데 도움이되도록 목록이 정렬되어 있다고 주장합니다. 어설 션은 디버그 빌드에만 있으므로 검사 비용이 많이 들더라도 루틴을 호출 할 때마다 수행하지 않아도됩니다.

여전히 프로덕션 코드를 단위 테스트해야하지만, 코드가 올바른지 확인하는 다른 보완적인 방법입니다. 단위 테스트를 통해 일상적인 인터페이스를 유지할 수 있으며 단정은 구현이 예상 한대로 정확하게 수행되도록하는보다 세밀한 방법입니다.


주장은 악한 것이 아니지만 쉽게 오용 될 수 있습니다. 나는 "어설 션은 종종 적절한 오류 처리 및보고에 대한 생각을 피하기 위해 목발로 사용된다"는 진술에 동의합니다. 나는 이것을 아주 자주 보았다.

개인적으로 저는 어설 션을 사용하고 싶습니다. 코드를 작성하는 동안 만들었을 수도 있다는 가정을 문서화했기 때문입니다. 코드를 유지하면서 이러한 가정이 깨지면 테스트 중에 문제가 감지 될 수 있습니다. 그러나 프로덕션 빌드를 수행 할 때 (예 : #ifdefs 사용) 모든 코드에서 모든 주장을 제거해야합니다. 프로덕션 빌드에서 어설 션을 제거함으로써 누군가를 버팀목으로 잘못 사용할 위험을 제거합니다.

어설 션에 또 다른 문제가 있습니다. 어설 션은 런타임에만 확인됩니다. 그러나 종종 수행하려는 검사가 컴파일 타임에 수행되었을 수 있습니다. 컴파일 타임에 문제를 감지하는 것이 좋습니다. C ++ 프로그래머에게 boost는 BOOST_STATIC_ASSERT를 제공하여이를 수행 할 수 있습니다. C 프로그래머의 경우이 기사 ( 링크 텍스트 )는 컴파일시 어설 션을 수행하는 데 사용할 수있는 기술을 설명합니다.

요약하자면, 내가 따르는 경험 법칙은 다음과 같습니다. 프로덕션 빌드에서는 어설 션을 사용하지 말고 가능하면 컴파일 타임에 확인할 수없는 항목에 대해서만 어설 션을 사용하십시오 (즉, 런타임시 확인해야 함).


적절한 오류보고를 고려하지 않고 어설 션을 사용했음을 인정합니다. 그러나 올바르게 사용하면 도움이된다는 사실을 빼앗아 가지 않습니다.

They are especially useful for if you want to follow the "Crash Early" principle. For example suppose you're implementing a reference counting mechanism. At certain locations in your code you know that the refcount should be zero or one. And also suppose that if the refcount is wrong the program won't crash immediately but during the next message loop at which point it will be difficult to find out why things went wrong. An assert would have been helpful in detecting the error closer to its origin.


I prefer avoiding code that does different things in debug and release.

Breaking in the debugger on a condition and having all file/line info is useful though, also the exact expression and the exact value.

Having an assert that would "evaluate the condition only in debug" may be a performance optimization, and as such, useful only in 0.0001% of programs - where people know what they are doing. In all other cases this is harmful, as the expression may actually change program's state:

assert(2 == ShroedingersCat.GetNumEars()); would make the program do different things in debug and release.

We have developed a set of assert macros which would throw an exception, and do it in both debug and release version. For instance, THROW_UNLESS_EQ(a, 20); would throw an exception with what() message having both file, line and the actual values of a, and so on. Only a macro would have the power for this. The debugger may be configured to break at 'throw' of the specific exception type.


I dislike asserts intensely. I would not go as far as saying they are evil though.

Basically an assert will do the same thing as an unchecked exception would, the only exception is that the assert (normally) should not be kept for the final product.

If you build a safety net for yourself while debugging and building the system why would you deny this safety net for your customer, or your support help desk, or anyone that will get to use the software that you are currently building. Use exceptions exclusively for both asserts and exceptional situations. By creating an appropriate exception hierarchy you will be able to discern very quickly one from the other. Except this time the assert remains in place and can provide valuable information in case of failure that would otherwise be lost.

So I fully understand the creators of Go by removing asserts altogether and forcing programmers to use exceptions to handle the situation. There is a simple explanation for this, exception are just a better mechanism for the job why stick with the archaic asserts?


Short answer: No, I believe assertions can be useful


I've recently started adding some asserts to my code, and this is how I've been doing it:

I mentally divide my code into boundary code and internal code. Boundary code is code that handles user input, reads files, and gets data from the network. In this code, I request input in a loop that only exits when input is valid (in the case of interactive user input), or throw exceptions in the case of unrecoverable file / network corrupt data.

Internal code is everything else. For instance, a function that sets a variable in my class might be defined as

void Class::f (int value) {
    assert (value < end);
    member = value;
}

and a function that gets input from a network might read as such:

void Class::g (InMessage & msg) {
    int const value = msg.read_int();
    if (value >= end)
        throw InvalidServerData();
    f (value);
}

This gives me two layers of checks. Anything where the data is determined at run-time always gets an exception or immediate error handling. However, that extra check in Class::f with the assert statement means that if some internal code ever calls Class::f, I still have a sanity check. My internal code might not pass a valid argument (because I may have calculated value from some complex series of functions), so I like having the assertion in the setting function to document that regardless of who is calling the function, value must not be greater than or equal to end.

This seems to fit into what I'm reading in a few places, that assertions should be impossible to violate in a well-functioning program, while exceptions should be for exceptional and erroneous cases that are still possible. Because in theory I'm validating all input, it should not be possible for my assertion to be triggered. If it is, my program is wrong.


assert is very useful and can save you a lot of backtracking when unexpected errors occur by halting the program at the very first signs of trouble.

On the other hand, it is very easy to abuse assert.

int quotient(int a, int b){
    assert(b != 0);
    return a / b;
}

The proper, correct version would be something like:

bool quotient(int a, int b, int &result){
    if(b == 0)
        return false;

    result = a / b;
    return true;
}

So... in the long run... in the big picture... I must agree that assert can be abused. I do it all the time.


assert is being abused for error handling because it is less typing.

So as language designers, they should rather see that proper error handling can be done with even lesser typing. Excluding assert because your exception mechanism is verbose is not the solution. Oh wait, Go doesn't have exceptions either. Too bad :)


I felt like kicking the author in the head when I saw that.

I use asserts all the time in code and eventually replace them all when I write more code. I use them when I haven't written the logic required and want to be alerted when I run into the code instead of writing an exception which will be deleted as the project gets closer to completion.

Exceptions also blend in with production code more easily which I dislike. An assert is easier to notice than throw new Exception("Some generic msg or 'pretend i am an assert'");


My problem with these answers defending assert is no one clearly specifies what makes it different from a regular fatal error, and why an assert can't be a subset of an exception. Now, with this said, what if the exception is never caught? Does that make it an assertion by nomenclature? And, why would you ever want to impose a restriction in the language that an exception can be raised that /nothing/ can handle?


Yes, asserts are evil.

Often they get used in places where proper error handling should be used. Get used to writing proper production quality error handling from the start!

Usually they get in the way of writing unit tests (unless you write a custom assert that interacts with your test harness). This is often because they are used where proper error handling should be used.

Mostly they get compiled out of release builds which means that none of their "testing" is available when you're running the code that you actually release; given that in multi-threaded situations the worst problems often only show up in release code this can be bad.

Sometimes they're a crutch for otherwise broken designs; i.e. the design of the code allows a user to call it in a way that it shouldn't be called and the assert "prevents" this. Fix the design!

I wrote about this more on my blog back in 2005 here: http://www.lenholgate.com/blog/2005/09/assert-is-evil.html


If the asserts you're talking about mean that the program vomits and then exists, assertions can be very bad. This is not to say that they are always the wrong thing to use, they are a construct that is very easily misused. They also have many better alternatives. Things like that are good candidates for being called evil.

For example, a 3rd party module (or any module really) should almost never exit the calling program. This doesn't give the calling programmer any control over what risk the program should take at that moment. In many cases, data is so important that even saving corrupted data is better than losing that data. Asserts can force you to lose data.

Some alternatives to asserts:

  • Using a debugger,
  • Console/database/other logging
  • Exceptions
  • Other types of error handling

Some references:

Even people that advocate for assert think they should only be used in development and not in production:

This person says that asserts should be used when the module has potentially corrupted data that persists after an exception is thrown: http://www.advogato.org/article/949.html . This is certainly a reasonable point, however, an external module should never prescribe how important corrupted data is to the calling program (by exiting "for" them). The proper way to handle this is by throwing an exception that makes it clear that the program may now be in an inconsistent state. And since good programs mostly consist of modules (with a little glue code in the main executable), asserts are almost always the wrong thing to do.


Not so much evil as generally counterproductive. There's a separation between permanent error checking and debugging. Assert makes people think all debugging should be permanent and causes massive readability problems when used much. Permanent error handling ought to be better than that where needed, and since assert causes its own errors it's a pretty questionable practice.


i never use assert(), examples usually show something like this:

int* ptr = new int[10];
assert(ptr);

This is bad, i never do this, what if my game is allocating a bunch of monsters? why should i crash the game, instead you should handle the errors gracefully, so do something like:

CMonster* ptrMonsters = new CMonster[10];
if(ptrMonsters == NULL) // or u could just write if(!ptrMonsters)
{
    // we failed allocating monsters. log the error e.g. "Failed spawning 10 monsters".
}
else
{
    // initialize monsters.
}

참고URL : https://stackoverflow.com/questions/1854302/is-assert-evil

반응형