내 라이브러리에 구현할 '좋은 수'의 예외는 무엇입니까?


20

나는 항상 내 소프트웨어의 다양한 부분에 대해 구현하고 던져야 할 예외 클래스가 얼마나 많은지 궁금했습니다. 내 특정 개발은 일반적으로 C ++ / C # / Java와 관련이 있지만 이것이 모든 언어에 대한 질문이라고 생각합니다.

다양한 예외가 발생하는 것과 개발자 커뮤니티가 좋은 라이브러리에 기대하는 것을 이해하고 싶습니다.

내가 보는 단점은 다음과 같습니다.

  • 더 많은 예외 클래스는 API 사용자에 대해 매우 세밀한 수준의 오류 처리를 허용 할 수 있습니다 (사용자 구성 또는 데이터 오류가 발생하거나 파일을 찾을 수 없음)
  • 더 많은 예외 클래스를 사용하면 문자열 메시지 나 오류 코드가 아니라 오류 관련 정보를 예외에 포함시킬 수 있습니다.
  • 더 많은 예외 클래스는 더 많은 코드 유지 관리를 의미 할 수 있습니다.
  • 더 많은 예외 클래스는 사용자가 API에 접근하기가 쉽지 않음을 의미 할 수 있습니다.

예외 사용법을 이해하려는 시나리오는 다음과 같습니다.

  • '설정'단계에서 파일로드 또는 매개 변수 설정이 포함될 수 있습니다.
  • 라이브러리가 작업을 실행 중이거나 다른 스레드에서 일부 작업을 수행 할 수있는 '작업'유형 단계 중

예외를 사용하지 않거나 예외를 적게 사용하는 다른 패턴의 오류보고에는 다음이 포함될 수 있습니다.

  • 예외는 적지 만 조회로 사용할 수있는 오류 코드 포함
  • 함수에서 직접 오류 코드 및 플래그 반환 (때로는 스레드에서 불가능)
  • 오류 발생시 이벤트 또는 콜백 시스템 구현 (스택 풀기 방지)

개발자로서 무엇을보고 싶습니까?

많은 예외가 있다면 어쨌든 개별적으로 오류 처리를 방해합니까?

작업 단계에 따라 오류 처리 유형을 선호합니까?



5
"API는 사용자에게 접근하기가 쉽지 않습니다"-API의 공통 기본 클래스에서 모두 상속되는 몇 가지 예외 클래스를 사용하여 처리 할 수 ​​있습니다. 그런 다음 시작하면서 모든 세부 정보에 대해 걱정할 필요없이 예외가 발생한 API를 확인할 수 있습니다. API를 사용하여 첫 번째 프로그램을 완료 할 때까지 오류에 대한 자세한 정보가 필요하면 다른 예외가 실제로 무엇을 의미하는지 살펴보기 시작합니다. 물론 사용중인 언어의 표준 예외 계층 구조와 동시에 훌륭하게 플레이해야합니다.
Steve Jessop

관련 포인트 Steve
Fuzz

답변:


18

간단하게 유지합니다.

라이브러리에는 std ::: runtime_error에서 확장 된 기본 예외 유형이 있습니다 (C ++에서 다른 언어에 적절하게 적용됨). 이 예외는 메시지 문자열을 가져 오므로 기록 할 수 있습니다. 모든 던지기 지점에는 고유 한 메시지가 있습니다 (보통 고유 한 ID).

그게 다야.

참고 1 : 누군가 예외를 잡는 상황에서는 예외를 수정하고 조치를 다시 시작할 수 있습니다. 원격 위치에서 고유하게 수정 될 수있는 항목에 대해서는 파생 예외를 추가합니다. 그러나 이것은 매우 드문 일입니다. 포수가 던지기 지점에 가까워 질 가능성이 적으므로 문제를 해결하는 것이 어려울 것입니다 (그러나 모든 것이 상황에 달려 있음).

참고 2 : 때로는 라이브러리가 너무 단순하여 자체 예외를 제공 할 가치가 없으며 std :: runtime_error가 수행합니다. std :: runtime_error와 구별 할 수있는 기능으로 사용자에게 무언가를 할 수있는 충분한 정보를 제공 할 수있는 경우에만 예외를 갖는 것이 중요합니다.

참고 3 : 클래스 내에서 일반적으로 오류 코드를 선호합니다 (그러나 클래스의 공용 API에서 절대로 벗어날 수는 없습니다).

장단점을 보면 :

내가 보는 단점은 다음과 같습니다.

더 많은 예외 클래스는 API 사용자에 대해 매우 세밀한 수준의 오류 처리를 허용 할 수 있습니다 (사용자 구성 또는 데이터 오류가 발생하거나 파일을 찾을 수 없음)

더 많은 예외가 실제로 더 미세한 입자 제어를 제공합니까? 문제는 catch 코드가 실제로 예외를 기반으로 오류를 해결할 수 있습니까? 나는 그런 상황이 있다고 확신하며,이 경우 다른 예외가 있어야합니다. 그러나 위에 나열된 유일한 예외 사항은 큰 경고를 생성하고 응용 프로그램을 중지하는 것입니다.

더 많은 예외 클래스를 사용하면 문자열 메시지 나 오류 코드가 아니라 오류 관련 정보를 예외에 포함시킬 수 있습니다.

이것이 예외를 사용하는 큰 이유입니다. 그러나 정보는 캐싱하는 사람에게 유용해야합니다. 정보를 사용하여 일부 수정 작업을 수행 할 수 있습니까? 객체가 라이브러리 내부에 있고 API에 영향을주는 데 사용할 수없는 경우 정보가 쓸모가 없습니다. 던져진 정보는 그것을 잡을 수있는 사람에게 유용한 가치를 지니고 있어야합니다. 정보를받는 사람은 일반적으로 공개 API 외부에 있으므로 공개 API의 정보와 함께 사용할 수 있도록 정보를 조정하십시오.

그들이 할 수있는 모든 것이 예외를 기록하는 것이라면 많은 양의 데이터보다는 에러 메시지를 던지는 것이 가장 좋습니다. 포수가 일반적으로 데이터와 함께 오류 메시지를 작성합니다. 오류 메시지를 작성하면 모든 포수에서 일관성이 유지됩니다. 캐처가 오류 메시지를 작성하도록 허용하면 전화를 걸고 잡는 사람에 따라 동일한 오류가 다르게보고 될 수 있습니다.

예외는 적지 만 조회로 사용할 수있는 오류 코드 포함

오류 코드를 의미있게 사용할 수있는 날씨를 결정해야합니다. 가능한 경우 자체 예외가 있어야합니다. 그렇지 않으면 사용자는 이제 catch 내부에서 switch 문을 구현해야합니다 (catch가 자동으로 물건을 처리하는 전체 요점을 무너뜨림).

그렇다면 예외에서 오류 메시지를 사용하지 않는 이유는 무엇입니까?

함수에서 직접 오류 코드 및 플래그 반환 (때로는 스레드에서 불가능)

내부적으로 오류 코드를 반환하는 것이 좋습니다. 버그를 수정 한 다음 모든 오류 코드를 수정하고이를 확인해야합니다. 그러나 공개 API에서 유출하는 것은 나쁜 생각입니다. 문제는 프로그래머가 종종 오류 상태를 확인하는 것을 잊어 버린다는 것입니다. (적어도 예외로 확인하지 않은 오류는 응용 프로그램에서 처리되지 않은 오류를 강제로 종료하면 일반적으로 모든 데이터가 손상됩니다).

오류 발생시 이벤트 또는 콜백 시스템 구현 (스택 풀기 방지)

이 방법은 종종 다른 오류 처리 메커니즘과 함께 사용됩니다 (대안이 아님). Windows 프로그램을 생각해보십시오. 사용자는 메뉴 항목을 선택하여 작업을 시작합니다. 이벤트 큐에서 조치를 생성합니다. 이벤트 큐는 결국 조치를 처리 할 스레드를 지정합니다. 스레드는 조치를 처리하고 결국 스레드 풀로 돌아가서 다른 태스크를 기다립니다. 여기서 작업을 수행하는 스레드가 기본에서 예외를 포착해야합니다. 예외를 포착 한 결과 일반적으로 기본 루프에 대해 이벤트가 생성되어 결국 사용자에게 오류 메시지가 표시됩니다.

그러나 예외에 직면 할 수 없다면 스택이 풀릴 것입니다 (적어도 스레드의 경우).


+1; "그렇지 않으면 사용자는 이제 catch 내부에 switch 문을 구현해야합니다 (catch가 자동으로 물건을 처리한다는 전체 요점을 무너뜨림). -콜 스택 해제 (아직 사용할 수있는 경우) 및 강제 오류 처리는 여전히 큰 이점입니다. 그러나 중간에 잡아서 다시 던져야 할 때 호출 스택 해제 기능을 사용하지 못하게됩니다.
멀린 모건-그레이엄

9

나는 보통 다음과 같이 시작합니다.

  1. 인수 버그 의 예외 클래스입니다 . 예를 들어 "인수가 널이 될 수 없음", "인수가 양수 여야합니다"등입니다. Java 및 C #에는 이러한 클래스가 사전 정의되어 있습니다. C ++에서는 보통 std :: exception에서 파생 된 하나의 클래스 만 만듭니다.
  2. 전제 조건 버그에 대한 예외 클래스 . "색인은 크기보다 작아야합니다"와 같이보다 복잡한 테스트를위한 것입니다.
  3. 어설 션 버그에 대한 예외 클래스 . 그것들은 일관성 중간 방법의 상태를 확인하기위한 것입니다. 예를 들어 음수, 0 또는 양수의 요소를 계산하기 위해 목록을 반복 할 때 결국 세 가지 크기가 더해집니다.
  4. 라이브러리 자체에 대한 하나의 기본 예외 클래스 . 처음에는이 수업을 던져라. 필요한 경우에만 하위 클래스 추가를 시작하십시오.
  5. 나는 예외를 포장하는 것을 선호하지 않지만,이 시점에서 의견이 다르다는 것을 알고 있습니다. 줄 바꿈을 하려면 추가 줄 바꿈 예외 클래스 가 필요합니다 .

처음 3 가지 경우에 대한 클래스는 디버깅 보조 도구이므로 코드에서 처리하도록 설계되지 않았습니다. 대신, 정보를 표시하는 최상위 레벨 처리기에서만 사용자가 정보를 복사하여 개발자에게 붙여 넣을 수 있습니다 (또는 "보고서 보내기"단추를 누르십시오). 따라서 개발자에게 유용한 정보, 파일, 함수, 줄 번호 및 실패한 검사를 명확하게 식별하는 메시지를 포함하십시오.

처음 세 가지 경우는 각 프로젝트마다 동일하기 때문에 C ++에서는 보통 이전 프로젝트에서 복사합니다. 많은 사람들이 정확히 같은 작업을 수행하기 때문에 C # 및 Java 디자이너는 해당 사례에 대한 표준 클래스를 표준 라이브러리에 추가했습니다. [업데이트 :] 게으른 프로그래머 : 클래스 하나면 충분하고 운이 좋으면 표준 라이브러리에 이미 적합한 예외 클래스가 있습니다. C ++의 기본 클래스가 제공하지 않는 파일 이름 및 줄 번호와 같은 정보를 추가하는 것을 선호합니다. [최종 업데이트]

라이브러리에 따라 네 번째 사례는 하나의 클래스 만 가질 수도 있고 소수의 클래스가 될 수도 있습니다. 나는 민첩한 aproach가 간단하게 시작하여 필요할 때 서브 클래스를 추가하는 것을 선호합니다.

네 번째 사례에 대한 자세한 주장은 Loki Astari 's answer을 참조하십시오 . 나는 그의 자세한 답변에 전적으로 동의합니다.


+1; 프레임 워크에서 쓰기 예외를 작성하는 방법과 응용 프로그램에서 예외를 작성하는 방법에 대한 명확한 차이가 있습니다. 차이점은 약간 모호하지만 언급 할 수 있습니다 (도서관의 경우 Loki를 연기 함).
멀린 모건-그레이엄
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.