맹렬한 예외를 피하는 방법?


21

예외대한 Eric Lippert의 기사를 읽으면 생산자와 소비자 모두 예외에 어떻게 접근해야하는지 분명히 알 수있었습니다. 그러나 나는 여전히 예외를 던지는 것을 피하는 방법에 관한 지침을 정의하기 위해 고심하고 있습니다.

구체적으로 :

  • a) 다른 사람이 레코드를 수정하기 전에 또는 b) 만들려는 값이 이미 존재 하기 때문에 실패 할 수있는 Save 메서드가 있다고 가정 합니다 . 이러한 조건은 예상되고 예외적이지 않으므로 예외를 발생시키는 대신 Try 버전의 Try 버전을 작성하여 저장 성공 여부를 나타내는 부울을 리턴하도록 결정합니다. 그러나 그것이 실패하면, 소비자는 어떻게 문제가 무엇인지 알 수 있습니까? 아니면 결과, Ok / RecordAlreadyModified / ValueAlreadyExists의 종류를 나타내는 열거 형을 반환하는 것이 가장 좋습니까? integer.TryParse를 사용하면 메소드가 실패 할 수있는 이유가 하나뿐 이므로이 문제는 존재하지 않습니다.
  • 이전 예제는 정말 까다로운 상황입니까? 아니면이 경우 예외를 던지는 것이 선호되는 방법입니까? Entity 프레임 워크를 포함하여 대부분의 라이브러리 및 프레임 워크에서 수행되는 방식입니다.
  • 메소드의 시험 버전을 작성하는시기와 메소드가 작동하는지 사전에 테스트 할 방법을 제공하는 시점을 어떻게 결정합니까? 현재 다음 지침을 따르고 있습니다.
    • 경쟁 조건이 발생할 경우 체험판을 만듭니다. 이것은 소비자가 외인성 예외를 잡을 필요를 방지한다. 예를 들어, 앞에서 설명한 저장 방법에서.
    • 조건을 테스트하는 메소드가 원래 메소드가 수행하는 모든 작업을 수행하는 경우 Try 버전을 작성하십시오. 예를 들어 integer.TryParse ()입니다.
    • 다른 경우에는 조건을 테스트하는 메소드를 작성하십시오.

1
실패 할 수있는 저장의 예는 실제로 끔찍한 예외가 아닙니다. 그것은 아주 보통의 아마 한다 단순히 예외.
S.Lott

@ S.Lott : 평범한 게 무슨 뜻입니까? 상황 자체 또는이 상황에서 예외가 발생합니까? 어쨌든, 이것이 실제로 상황에 처한지는 분명하지 않다는 것에 동의합니다. 질문을 업데이트하겠습니다.
Mike

"상황 자체 또는이 상황에서 예외 발생"둘 다.
S.Lott

답변:


24

a) 누군가 다른 사람이 전에 레코드를 수정했거나 b) 만들려고하는 값이 이미 있기 때문에 실패 할 수있는 Save 메서드가 있다고 가정합니다. 이러한 조건은 예상되고 예외적이지 않으므로 예외를 발생시키는 대신 Try 버전의 Try 버전을 작성하여 저장 성공 여부를 나타내는 부울을 리턴하도록 결정합니다. 그러나 그것이 실패하면, 소비자는 어떻게 문제가 무엇인지 알 수 있습니까?

좋은 질문.

내 마음에 오는 첫 번째 질문은 : 데이터가 이미 있다면 어떤 의미에서 저장이 실패 했습니까? 그것은 나에게 성공한 것처럼 들린다. 그러나 작업이 실패 할 수있는 여러 가지 이유가 실제로 있다고 주장하기 위해 가정 해 봅시다.

내 마음에 오는 두 번째 질문은 다음과 같습니다. 실행 가능한 사용자에게 반환하려는 정보는 무엇입니까? 즉, 그들은 그 정보를 바탕으로 어떤 결정을 내릴 것입니까?

"엔진 점검"표시등이 켜지면 후드를 열고 내 차에 불이없는 엔진이 있는지 확인한 후 차고로 가져갑니다. 물론 차고에는 검사 엔진 표시등이 왜 켜져 있는지 알려주는 모든 종류의 특수 목적 진단 장비가 있지만 관점에서 경고 시스템은 잘 설계되었습니다. 산소 센서가 연소실에서 비정상적인 수준의 산소를 기록하고 있는지 또는 유휴 속도 감지기의 플러그가 뽑혀 있는지 또는 기타 무엇인지 문제가되지 않습니다. 나는 같은 행동을 취할 것입니다. 즉, 다른 사람이 이것을 알아 보도록하십시오 .

발신자가 저장이 실패한 이유를 걱정합니까? 포기하거나 다시 시도하는 것 외에 다른 일을 할 것입니까?

호출자가 실제로 작업이 실패한 이유에 따라 다른 조치를 취할 것이라고 주장하기 위해 가정 해 봅시다.

염두에 두어야 할 세 번째 질문 은 실패 모드가 예외적 입니까? 나는 당신이 혼란 될 수 있다고 생각 할 수 와 함께 예외가 아닌 . 두 명의 사용자가 동시에 동일한 레코드를 수정하려고 시도하는 것은 일반적인 상황이 아니라 예외적이지만 가능한 상황입니다.

논쟁의 여지가 없다는 점을 가정 해 봅시다.

네 번째로 떠오른 질문 은 나쁜 상황을 미리 감지 할 수있는 방법이 있습니까?

나쁜 상황이 "외인성"버킷에 있다면, 아닙니다. "다른 사용자가이 레코드를 수정 했습니까?"라고 확실하게 말할 수있는 방법이 없습니다. 그들은 당신이 질문을 한 후에 그것을 수정할 수 있기 때문에 . 대답은 오래된 즉시 생산되고있다.

염두에 두어야 할 다섯 번째 질문은 다음과 같습니다. 나쁜 상황을 방지 할 수 있도록 API를 설계하는 방법이 있습니까?

예를 들어 "저장"작업에 두 단계가 필요합니다. 1 단계 : 수정중인 레코드에 대한 잠금을 확보하십시오. 이 작업은 성공하거나 실패하므로 부울을 반환 할 수 있습니다. 그러면 호출자는 실패를 처리하는 방법에 대한 정책을 가질 수 있습니다. 잠시 기다렸다가 다시 시도하고 포기하십시오. 2 단계 : 잠금이 확보되면 저장을 수행하고 잠금을 해제하십시오. 이제 저장은 항상 성공 하므로 모든 종류의 오류 처리에 대해 걱정할 필요가 없습니다. 저장이 실패하면 정말 예외입니다.


감사합니다. 다음은 아마도 내 게시물을 요약하는 수사적 질문입니다. File.Open ()을 다시 디자인하려면 File.TryOpen ()을 대신 작성 하시겠습니까? 실패 이유를 소비자에게 어떻게 알리겠습니까? 아니면 외생적인 예외를 던지는 것이 여기서 가장 좋은 타협입니까?
Mike

10
@Mike : 파일 시스템은 외인성 예외를 사용하는 좋은 예입니다. 그들은 거의 실패하지 않으므로 실패는 예외적입니다. 그들은 예측할 수없고 실패하기 때문에 호출자의 통제 범위를 완전히 벗어난 이유로 (이더넷 케이블을 연결 한 상태에서 "잠금"이 없어야 함) 실패는 다양하고 실행 가능합니다 (즉, 파일이 찾을 수 없음 대 파일을 찾을 수 있지만 쓰기 액세스 권한이없는 경우 모두 다른 방식으로 조치 할 수 있습니다.) 이러한 모든 것은 실패를 예외로 표시하는 이유입니다.
Eric Lippert

나는 지금 질문에 답할 것이라 생각하지만, 나는 단지 궁금하다.;) 만약 그 방법이 2 가지 또는 그 이상의 이유로 실패 할 수 있다면, 실패는 실행 가능하고, 실패는 예외적이지 않으며 실패는 미리 발견되거나 예방 될 수 없다. 당신은 무엇을 하시겠습니까?
Mike

@ Mike와 대화 할 수는 없지만 오류 코드가 좋은 곳인 것 같습니다. 아마도 열거 형 멤버를 반환합니다.
Matthew 읽기

1

ValueAlreadyExists 상황을 쉽게 확인할 수 있습니다 경우의 예에서, 그것은 해야 확인 및 예외가 저장을 시도하기 전에 제기 될 수있다, 나는 시도는이 상황에서 필요한다고 생각하지 않습니다. 경쟁 조건은 미리 확인하기가 어려우므로이 경우 시험 사용시 저장을 포장하는 것이 좋습니다.

일반적으로 (NoDataReturned, DivideByZero 등과 같은) 가능성이 매우 높거나 확인이 쉬운 조건 (빈 컬렉션 또는 NULL 값)이있는 경우 확인하려고합니다. 미리 예외를 잡아야 할 시점에 도달하기 전에 미리 처리하고 처리하십시오. 이러한 조건을 미리 미리 알기는 쉽지 않다는 것을 인정합니다. 때로는 코드가 엄격한 테스트를 받고있을 때만 나타납니다.


0

save()메소드는 예외를 throw해야합니다.

최상위 계층은 명령 행 프로그램과 같은 Unix와 같은 경우가 아니라면 프로그램을 종료하지 않고 사용자를 잡아서 알려야합니다 .이 경우 종료해도됩니다.

반환 값은 예외를 관리하는 좋은 방법이 아닙니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.