문제

어제 나는 선호하는 오류 보고 방법이 무엇인지에 관해 동료와 열띤 토론을 벌였습니다.주로 애플리케이션 계층이나 모듈 간의 오류를 보고하기 위한 예외나 오류 코드의 사용에 대해 논의했습니다.

오류 보고를 위해 예외를 발생시키거나 오류 코드를 반환할지 결정하기 위해 어떤 규칙을 사용합니까?

도움이 되었습니까?

해결책 2

나는 일반적으로 예외를 선호합니다. 상황에 더 많은 정보가 있고 명확한 방식으로 프로그래머에게 오류를 전달할 수 있기 때문입니다.

반면에, 오류 코드는 예외보다 가볍지 만 유지하기가 어렵습니다. 오류 검사는 실수로 생략 할 수 있습니다. 모든 오류 코드가있는 카탈로그를 유지 한 다음 결과를 켜서 어떤 오류가 발생했는지 확인해야하기 때문에 오류 코드는 유지하기가 더 어렵습니다. 오류 범위는 여기에서 도움이 될 수 있습니다. 우리가 관심있는 유일한 것이 오류가 있거나없는 경우 확인하는 것이 더 간단하기 때문에 (예 : 0과 같은 HRESULT 오류 코드는 성공 및 동일합니다. 0보다 적은 것은 고장입니다). 개발자가 오류 코드를 점검 할 것이라는 프로그래밍 방식이 없기 때문에 실수로 생략 할 수 있습니다. 반면에, 당신은 예외를 무시할 수 없습니다.

요약하면 거의 모든 상황에서 오류 코드보다 예외를 선호합니다.

다른 팁

높은 수준의 물건에서 예외; 저수준에서 오류 코드.

예외의 기본 동작은 스택을 풀고 프로그램을 중지하는 것입니다. 스크립트를 작성하고 사전에 있지 않은 열쇠를 찾으면 아마도 오류 일 것입니다. 프로그램이 중단되어 저를 보내 주시기를 원합니다. 그것에 대해 모두 알고 있습니다.

그러나 만약 내가 코드를 작성한다면 알아야 해 가능한 모든 상황에서의 동작은 오류 코드를 원합니다. 그렇지 않으면 내 기능의 모든 줄에서 던질 수있는 모든 예외를 알아야합니다. 항공사를 근거로 한 예외 이것이 얼마나 까다로운 지에 대한 아이디어를 얻으려면). 모든 상황 (불행한 상황 포함)에 적절하게 반응하는 코드를 작성하는 것은 지루하고 쓰기가 어렵지만 오류가없는 코드를 작성하는 것은 오류 코드를 통과하기 때문에 지루하고 어렵 기 때문입니다.

둘 다 레이몬드 첸 그리고 조엘 모든 것에 대한 예외를 사용하는 것에 대해 웅변적인 주장을했습니다.

나는 예외를 선호하기 때문에 선호합니다

  • 그들은 논리의 흐름을 무너 뜨립니다
  • 더 많은 기능/기능을 제공하는 클래스 계층 구조로부터 혜택을받습니다.
  • 올바르게 사용될 때 광범위한 오류를 나타낼 수 있습니다 (예 : 유효하지 않은 메토드 카일 플렉스는 또한 런타임 전에 감지 할 수있는 코드에 버그가있을 때 발생할 때 발생하기 때문에 로지 픽스크도 마찬가지입니다).
  • 오류를 향상시키는 데 사용될 수 있습니다 (즉, FilereadException 클래스 정의에는 코드가 포함되어 파일이 존재하는지 또는 잠긴 것 등).

오류 코드는 기능의 발신자가 무시할 수 있습니다. 예외는 적어도 어떤 식 으로든 오류를 처리하도록 강요합니다. 그들의 버전을 다루는 버전에 있어도 빈 캐치 핸들러가 있어야합니다 (한숨).

오류 코드에 대한 예외는 의심의 여지가 없습니다.오류 코드와 마찬가지로 예외로부터 많은 이점을 얻을 수 있을 뿐만 아니라 오류 코드의 단점 없이 훨씬 더 많은 이점을 얻을 수 있습니다.예외에 대한 유일한 노크는 약간 더 많은 오버헤드가 있다는 것입니다.그러나 오늘날에는 거의 모든 애플리케이션에 대해 이러한 오버헤드가 무시할 만한 수준으로 간주되어야 합니다.

다음은 두 가지 기술을 논의, 비교 및 ​​대조하는 몇 가지 기사입니다.

더 많은 내용을 읽을 수 있는 좋은 링크가 있습니다.

나는 두 모델을 혼합하지 않을 것입니다 ... 오류 코드를 사용하는 스택의 한 부분에서 예외를 사용하는 더 높은 조각으로 이동할 때 하나에서 다른 모델로 변환하기가 너무 어렵습니다.

예외는 "방법이나 서브 루틴이 당신이 요청한 일을하는 것을 막거나 억제하는 모든 것"에 대한 것입니다 ... 불규칙성이나 비정상적인 상황, 시스템 상태에 대한 메시지를 전달하지 마십시오. 반환 값 또는 Ref를 사용하십시오. (또는 외부) 매개 변수.

예외를 통해 방법의 기능에 의존하는 의미론으로 메소드를 작성 (및 활용) 할 수 있습니다. 즉, 직원 개체 또는 직원 목록을 반환하는 메소드를 입력하여 전화를 통해이를 활용할 수 있습니다.

Employee EmpOfMonth = GetEmployeeOfTheMonth();

오류 코드를 사용하면 모든 메소드가 오류 코드를 반환하므로 호출 코드에서 사용할 다른 것을 반환 해야하는 사람들의 경우 해당 데이터로 채워 지도록 참조 변수를 전달하고의 반환 값을 테스트해야합니다. 모든 기능 또는 메소드 호출에서 오류 코드를 처리하고 처리합니다.

Employee EmpOfMonth; 
if (getEmployeeOfTheMonth(ref EmpOfMonth) == ERROR)
    // code to Handle the error here

각 메소드가 하나의 간단한 일만 수행하도록 코딩하면 메소드가 원하는 목표를 달성 할 수 없을 때마다 예외를 던져야합니다. 예외는 오류 코드보다 이러한 방식으로 훨씬 더 풍부하고 사용하기 쉽습니다. 코드는 훨씬 더 깨끗합니다. "일반"코드 경로의 표준 흐름은 메소드가 원하는 작업을 수행 할 수있는 경우에 엄격하게 바칠 수 있습니다. 방법이 성공적으로 완료되는 것을 방지하는 나쁜 일이 발생하는 "예외적 인"상황은 일반 코드에서 멀어 질 수 있습니다. 또한, 발생한 곳의 예외를 처리 할 수없고 스택을 UI로 전달 해야하는 경우 (또는 미드 계층 구성 요소에서 UI로 와이어를 가로 질러 더 나쁘게) 예외 모델을 사용하면 스택의 모든 중재 메소드를 스택을 인식하고 전달하기 위해 스택의 모든 중재 메소드를 코딩 할 필요는 없습니다 ... 예외 모델은 자동으로이를 수행합니다 .... 오류 코드를 사용하면이 퍼즐 조각이 매우 빠르게 번거롭게 될 수 있습니다. .

과거에는 ErrorCode 캠프에 가입했습니다 (너무 많은 C 프로그래밍). 그러나 지금 나는 빛을 보았다.

예, 예외는 시스템에 약간의 부담입니다. 그러나 코드를 단순화하여 오류 수 (및 WTF)를 줄입니다.

따라서 예외를 사용하지만 현명하게 사용하십시오. 그리고 그들은 당신의 친구가 될 것입니다.

부수적으로. 나는 어떤 방법으로 어떤 예외를 던질 수 있는지 문서화하는 법을 배웠습니다. 불행히도 이것은 대부분의 언어에 필요하지 않습니다. 그러나 올바른 수준에서 올바른 예외를 처리 할 가능성이 높아집니다.

깨끗하고 명확하고 올바른 방법으로 예외를 사용하는 것이 번거로운 상황이있을 수 있지만 대부분의 시간 예외는 명백한 선택입니다. 가장 큰 이점 예외 처리는 오류 코드가 과도한 오류 코드를 가지고 있습니다. 실행 흐름이 변경되므로 두 가지 이유로 중요합니다.

예외가 발생하면 응용 프로그램이 더 이상 '정상적인'실행 경로를 따르지 않습니다. 이것이 중요한 첫 번째 이유는 코드의 저자가 잘 진행되고 진정으로 나쁘지 않으면 프로그램이 중단되고 예측할 수없는 일을 계속하지 않기 때문입니다. 오류 코드가 확인되지 않고 잘못된 오류 코드에 대한 응답으로 적절한 조치를 취하지 않으면 프로그램은 수행하는 작업을 계속 수행하며 해당 조치의 결과가 무엇인지 알고 있습니다. 프로그램이 '무엇이든'하는 것이 매우 비쌀 수있는 상황이 많이 있습니다. 회사가 판매하는 다양한 금융 상품에 대한 성과 정보를 검색하고 해당 정보를 중개인/도매 업체에게 제공하는 프로그램을 고려하십시오. 문제가 발생하고 프로그램이 계속 진행되면 중개인과 도매 업체에게 잘못된 성능 데이터를 배송 할 수 있습니다. 나는 다른 사람에 대해 모르지만, VPS 사무실에 앉아있는 사람이되고 싶지는 않습니다. 왜 내 코드가 회사가 7 자리에 걸쳐 7 자리의 규제 벌금을 얻었는지 설명하고 싶지 않습니다. 고객에게 오류 메시지를 전달하는 것은 일반적으로 '실제'로 보일 수있는 잘못된 데이터를 제공하는 것이 바람직하며, 후자의 상황은 오류 코드와 같은 훨씬 덜 공격적인 접근 방식으로 훨씬 쉽게 실행하기가 훨씬 쉽습니다.

내가 예외를 좋아하고 정상적인 실행을 깨뜨리는 두 번째 이유는 그것이 '정상적인 일이 일어나고있다'는 논리를 '무언가 잘못된 논리'와 분리하는 논리를 훨씬 쉽게 유지하기 때문입니다. 나에게 이것은 :

try {
    // Normal things are happening logic
catch (// A problem) {
    // Something went wrong logic
}

... 이것보다 바람직하다 :

// Some normal stuff logic
if (errorCode means error) {
    // Some stuff went wrong logic
}
// Some normal stuff logic
if (errorCode means error) {
    // Some stuff went wrong logic
}
// Some normal stuff logic
if (errorCode means error) {
    // Some stuff went wrong logic
}

예외에 대한 다른 작은 것들도 있습니다. 함수에서 호출되는 메소드에 오류 코드가 반환되었는지 여부를 추적하기 위해 조건부 논리가 많으며 오류 코드를 더 높이 리턴하는 것은 많은 보일러 플레이트입니다. 사실, 그것은 잘못 될 수있는 많은 보일러 플레이트입니다. 나는 대부분의 언어의 예외 시스템에 대해 훨씬 더 많은 믿음을 가지고있다. 나는 '신입생의 신입생'프레드가 쓴 if-else-if-else 진술의 쥐 둥지를하는 것보다 훨씬 더 많은 믿음을 가지고 있으며, 나는 할 일이 훨씬 더 좋은 일이있다. 코드를 검토하는 것보다 내 시간으로 쥐의 둥지.

둘 다 사용해야 합니다.문제는 각각을 언제 사용할지 결정하는 것입니다..

있다 예외가 확실한 선택인 몇 가지 시나리오:

  1. 어떤 상황에서는 오류 코드로는 아무것도 할 수 없습니다, 그리고 당신은 단지 호출 스택의 상위 수준에서 처리해야 합니다., 일반적으로 오류를 기록하거나 사용자에게 내용을 표시하거나 프로그램을 닫습니다.이러한 경우 오류 코드를 사용하려면 오류 코드를 수준별로 수동으로 표시해야 하며 이는 분명히 예외를 처리하는 것이 훨씬 쉽습니다.요점은 이것이다. 예상치 못한 일과 처리할 수 없는 일 상황.

  2. 그러나 상황 1(예상치 못한 처리할 수 없는 일이 발생하여 기록하고 싶지 않은 경우)의 경우 예외가 도움이 될 수 있습니다. 상황에 맞는 정보 추가.예를 들어 하위 수준 데이터 도우미에서 SqlException이 발생하면 해당 정보를 캡처할 수 있도록 하위 수준(오류를 발생시킨 SQL 명령을 알고 있는 위치)에서 해당 오류를 포착하려고 합니다. 그리고 다시 던지기 추가 정보가 포함되어 있습니다.여기서 마법의 단어를 주목하세요: 다시 던지고 삼키지 말라. 예외 처리의 첫 번째 규칙: 예외를 삼키지 마라.또한 외부 catch에는 전체 스택 추적이 있고 이를 기록할 수 있으므로 내부 catch에는 아무 것도 기록할 필요가 없습니다.

  3. 어떤 상황에서는 일련의 명령이 있고 그 중 하나라도 실패하면 당신은해야 자원 정리/폐기(*) 복구할 수 없는 상황(발생해야 함)인지 복구 가능한 상황(이 경우 로컬로 또는 호출자 코드에서 처리할 수 있지만 예외가 필요하지 않음)인지 여부입니다.분명히 각 메서드 다음에 오류 코드를 테스트하고 finally 블록에서 정리/폐기하는 대신 모든 명령을 한 번 시도하는 것이 훨씬 쉽습니다.점에 유의하시기 바랍니다 오류가 발생하기를 원하는 경우(아마도 원하는 것일 수 있음) 오류를 잡을 필요조차 없습니다. 정리/처리를 위해 finally를 사용하기만 하면 됩니다. - 상황별 정보를 추가하려는 경우에만 catch/retrow를 사용해야 합니다(글머리 기호 2 참조).

    한 가지 예는 트랜잭션 블록 내부의 일련의 SQL 문입니다.다시 말하지만, 이는 또한 "처리할 수 없는" 상황입니다. 조기에 발견하기로 결정하더라도(상위로 거품이 생기지 않고 로컬로 처리) 여전히 문제가 발생합니다. 치명적인 상황 최선의 결과는 모든 것을 중단하거나 적어도 프로세스의 상당 부분을 중단하는 것입니다.
    (*) 이것은 다음과 같습니다 on error goto 이전 Visual Basic에서 사용했던

  4. 생성자에서는 예외만 발생시킬 수 있습니다.

그렇긴 하지만, 당신이 어떤 정보를 반환하는 다른 모든 상황에서는 발신자는 어떤 조치를 취할 수 있거나/해야 합니다., 반환 코드를 사용하는 것이 아마도 더 나은 대안일 것입니다.여기에는 모두 포함됩니다. 예상되는 "오류", 아마도 직접 호출자가 처리해야 하고 스택에서 너무 많은 레벨 위로 버블링할 필요가 거의 없기 때문입니다.

물론 예상되는 오류를 예외로 처리하고 한 수준 위 즉시 catch하는 것이 가능하며, try catch에 모든 코드 줄을 포함하고 가능한 각 오류에 대해 조치를 취하는 것도 가능합니다.IMO, 이것은 나쁜 디자인입니다. 훨씬 더 장황할 뿐만 아니라 특히 던져질 수 있는 예외가 소스 코드를 읽지 않고서는 명확하지 않기 때문입니다. 그리고 예외는 딥 메소드에서 던져질 수 있습니다. 보이지 않는 고토스.코드를 읽고 검사하기 어렵게 만드는 보이지 않는 종료점을 여러 개 만들어 코드 구조를 깨뜨립니다.즉, 절대 사용하면 안 됩니다. 다음과 같은 예외 흐름 제어, 왜냐하면 그것은 다른 사람들이 이해하고 유지하기 어려울 것이기 때문입니다.테스트를 위해 가능한 모든 코드 흐름을 이해하는 것은 심지어 어려울 수 있습니다.
다시: 올바른 정리/폐기를 위해 아무것도 잡지 않고 try-finally를 사용할 수 있습니다..

반환 코드에 대한 가장 대중적인 비판은 "누군가 오류 코드를 무시할 수 있지만 같은 의미에서 누군가 예외를 삼킬 수도 있습니다. 잘못된 예외 처리가 쉽습니다. 두 가지 방법 모두에서.하지만 좋은 오류 코드 기반 프로그램을 작성하는 것은 예외 기반 프로그램을 작성하는 것보다 훨씬 쉽습니다..그리고 어떤 이유로든 모든 오류를 무시하기로 결정한 경우(이전 on error resume next), 반환 코드를 사용하여 쉽게 수행할 수 있지만 많은 try-catch 상용구 없이는 수행할 수 없습니다.

반환 코드에 대한 두 번째로 가장 대중적인 비판은 "버블링하기 어렵다"는 것입니다. 그러나 이는 복구할 수 없는 상황에 대한 예외는 있지만 오류 코드는 그렇지 않다는 사실을 사람들이 이해하지 못하기 때문입니다.

예외와 오류 코드 사이를 결정하는 것은 회색 영역입니다.재사용 가능한 비즈니스 메서드에서 오류 코드를 가져와야 하는 경우에도 이를 예외로 래핑하여(정보 추가 가능) 버블링되도록 하기로 결정할 수도 있습니다.그러나 모든 오류가 예외로 처리되어야 한다고 가정하는 것은 설계상의 실수입니다.

그것을 요 ​​약하기:

  • 나는 할 일이 많지 않은 예상치 못한 상황이 발생했을 때 예외를 사용하는 것을 좋아하며 일반적으로 큰 코드 블록이나 심지어 전체 작업이나 프로그램을 중단하고 싶습니다.이것은 예전의 "on error goto"와 같습니다.

  • 나는 호출자 코드가 어떤 조치를 취할 수 있거나 취해야 하는 상황이 예상되는 경우 반환 코드를 사용하는 것을 좋아합니다.여기에는 대부분의 비즈니스 방법, API, 유효성 검사 등이 포함됩니다.

예외와 오류 코드의 이러한 차이는 GO 언어의 설계 원칙 중 하나입니다. 이는 예상치 못한 치명적 상황에 대해 "패닉"을 사용하는 반면, 일반적으로 예상되는 상황은 오류로 반환됩니다.

그러나 GO에 대해서는 다음과 같이 허용합니다. 여러 반환 값 , 이는 오류와 다른 것을 동시에 반환할 수 있기 때문에 반환 코드 사용에 많은 도움이 됩니다.C#/Java에서는 매개변수, Tuple 또는 (내가 가장 좋아하는) Generic을 사용하여 이를 달성할 수 있으며, 열거형과 결합하면 호출자에게 명확한 오류 코드를 제공할 수 있습니다.

public MethodResult<CreateOrderResultCodeEnum, Order> CreateOrder(CreateOrderOptions options)
{
    ....
    return MethodResult<CreateOrderResultCodeEnum>.CreateError(CreateOrderResultCodeEnum.NO_DELIVERY_AVAILABLE, "There is no delivery service in your area");

    ...
    return MethodResult<CreateOrderResultCodeEnum>.CreateSuccess(CreateOrderResultCodeEnum.SUCCESS, order);
}

var result = CreateOrder(options);
if (result.ResultCode == CreateOrderResultCodeEnum.OUT_OF_STOCK)
    // do something
else if (result.ResultCode == CreateOrderResultCodeEnum.SUCCESS)
    order = result.Entity; // etc...

내 메서드에 가능한 새 반환을 추가하면 예를 들어 모든 호출자가 스위치 문에서 해당 새 값을 다루고 있는지 확인할 수도 있습니다.예외 없이 그렇게 할 수는 없습니다.반환 코드를 사용하면 일반적으로 가능한 모든 오류를 미리 알고 테스트할 수 있습니다.예외를 제외하면 일반적으로 무슨 일이 일어날지 알 수 없습니다.제네릭 대신 예외 내부에 열거형을 래핑하는 것은 대안이지만(각 메서드에서 발생하는 예외 유형이 명확한 경우) IMO에서는 여전히 잘못된 디자인입니다.

나는 여기 울타리에 앉아 있을지 모르지만 ...

  1. 그것은 언어에 따라 다릅니다.
  2. 어떤 모델을 선택하든 사용 방법에 대해 일관성을 유지하십시오.

파이썬에서 예외의 사용은 표준 관행이며, 내 예외를 정의하게되어 매우 기쁩니다. C에는 예외가 전혀 없습니다.

C ++에서 (적어도 STL에서) 예외는 일반적으로 진정으로 예외적 인 오류에 대해서만 던져집니다 (사실상 직접 볼 수는 없습니다). 내 코드에서 다른 일을 할 이유가 없습니다. 예, 반환 값을 무시하기는 쉽지만 C ++는 예외를 포착하도록 강요하지 않습니다. 나는 당신이 그 일을하는 습관에 들어가야한다고 생각합니다.

내가 작업하는 코드 기반은 대부분 C ++이며 거의 모든 곳에서 오류 코드를 사용하지만 매우 예외적 인 오류를 포함하여 모든 오류에 대한 예외를 제외하는 모듈이 있으며 해당 모듈을 사용하는 모든 코드는 꽤 끔찍합니다. 그러나 그것은 우리가 예외와 오류 코드를 혼합했기 때문일 수 있습니다. 일관되게 오류 코드를 사용하는 코드는 작업하기가 훨씬 쉽습니다. 코드가 지속적으로 예외를 사용했다면 나쁘지 않을 수도 있습니다. 둘을 섞는 것은 그렇게 잘 작동하지 않는 것 같습니다.

C ++와 함께 일하고 RAII가 사용하기에 안전하게 사용하기 때문에 거의 독점적으로 예외를 사용합니다. 일반 프로그램 흐름에서 오류 처리를 가져오고 의도를 더 명확하게 만듭니다.

그래도 예외적 인 상황에 대한 예외를 남깁니다. 특정 오류가 많이 발생할 것으로 예상되는 경우 작업을 수행하기 전에 작업이 성공할 것인지 확인하거나 오류 코드를 대신 사용하는 기능의 버전을 호출합니다. TryParse())

메소드 서명은 메소드가하는 일을 전달해야합니다. 긴 ErrorCode = getErrorCode ()와 같은 것; 괜찮을 수 있지만 긴 ErrorCode = FetchRecord (); 혼란 스럽습니다.

내 추론은 실제로 성능이 필요한 저수준 드라이버를 작성한 다음 오류 코드를 사용하는 경우입니다. 그러나 해당 코드를 상위 레벨 애플리케이션에서 사용하고 약간의 오버 헤드를 처리 할 수있는 경우 해당 코드를 인터페이스로 랩핑하여 해당 오류 코드를 확인하고 예외를 제기합니다.

다른 모든 경우에 예외는 아마도 갈 길입니다.

내 접근 방식은 예외와 오류 코드를 동시에 사용할 수 있다는 것입니다.

여러 유형의 예외 (예 : DataValidationException 또는 ProcessInterruptexcepion)를 정의하는 데 사용되며 각 예외 내에서는 각 문제에 대한 자세한 설명을 정의합니다.

Java의 간단한 예 :

public class DataValidationException extends Exception {


    private DataValidation error;

    /**
     * 
     */
    DataValidationException(DataValidation dataValidation) {
        super();
        this.error = dataValidation;
    }


}

enum DataValidation{

    TOO_SMALL(1,"The input is too small"),

    TOO_LARGE(2,"The input is too large");


    private DataValidation(int code, String input) {
        this.input = input;
        this.code = code;
    }

    private String input;

    private int code;

}

이런 식으로 예외를 사용하여 범주 오류를 정의하고 오류 코드를 정의하여 문제에 대한 자세한 정보를 정의합니다.

예외는입니다 특별한 상황 - 즉 코드의 정상 흐름의 일부가 아닌 경우.

예외와 오류 코드를 혼합하는 것은 합법적입니다. 여기서 오류 코드가 코드 자체를 실행하는 오류가 아니라 오류의 상태를 나타냅니다 (예 : 어린이 프로세스에서 리턴 코드를 확인하는).

그러나 탁월한 상황이 발생하면 예외가 가장 표현적인 모델이라고 생각합니다.

예외 대신 오류 코드를 선호하거나 사용하는 경우가 있으며, 이는 이미 적절하게 다루어졌습니다 (컴파일러 지원과 같은 다른 명백한 제약 외에).

그러나 다른 방향으로 진행하면 예외를 사용하면 오류 처리에 더 높은 수준의 추상화를 구축 할 수있어 코드가 더욱 표현적이고 자연스럽게 만들 수 있습니다. C ++ 전문가 Andrei Alexandrescu가 "집행"의 주제에 대해이 훌륭하지만 과소 평가 된 기사를 읽는 것이 좋습니다. http://www.ddj.com/cpp/184403864. C ++ 기사이지만 원칙은 일반적으로 적용 가능하며, 시행 개념을 C#로 상당히 성공적으로 번역했습니다.

첫째, 나는 Tom의 의견에 동의합니다. 답변 SOA(서비스 지향 아키텍처)가 아닌 한 높은 수준의 경우 예외를 사용하고 낮은 수준의 경우 오류 코드를 사용합니다.

여러 시스템에서 메서드가 호출될 수 있는 SOA에서는 예외가 연결을 통해 전달되지 않을 수 있습니다. 대신 아래와 같은 구조로 성공/실패 응답을 사용합니다(C#).

public class ServiceResponse
{
    public bool IsSuccess => string.IsNullOrEmpty(this.ErrorMessage);

    public string ErrorMessage { get; set; }
}

public class ServiceResponse<TResult> : ServiceResponse
{
    public TResult Result { get; set; }
}

그리고 다음과 같이 사용하세요:

public async Task<ServiceResponse<string>> GetUserName(Guid userId)
{
    var response = await this.GetUser(userId);
    if (!response.IsSuccess) return new ServiceResponse<string>
    {
        ErrorMessage = $"Failed to get user."
    };
    return new ServiceResponse<string>
    {
        Result = user.Name
    };
}

이것이 서비스 응답에서 일관되게 사용되면 애플리케이션에서 성공/실패를 처리하는 아주 좋은 패턴이 생성됩니다.이를 통해 서비스 내에서뿐만 아니라 서비스 전반에서 비동기 호출의 오류 처리가 더 쉬워집니다.

실패가 기본 데이터 유형을 반환하는 함수의 예상 가능한 버그가없는 결과 인 경우를 제외하고는 모든 오류 사례에 대한 예외를 선호합니다. 예를 들어 더 큰 문자열 내에서 서브 스트링의 색인을 찾는 것은 NotFoundException을 올리는 대신 일반적으로 찾을 수없는 경우 -1을 반환합니다.

부정 할 수있는 유효하지 않은 포인터를 반환하는 것은 (예 : Java에서 NullPointerException을 일으키는) 허용되지 않습니다.

클라이언트가 "<0"대신 "== -1"점검을 수행 할 수 있으므로 동일한 함수의 반환 값으로 여러 다른 숫자 오류 코드 (-1, -2)를 사용하는 것은 일반적으로 나쁜 스타일입니다.

여기서 명심해야 할 한 가지는 시간이 지남에 따라 API의 진화입니다. 좋은 API는 클라이언트를 깨지 않고 여러 가지 방법으로 실패 동작을 변경하고 확장 할 수 있습니다. 예 : 클라이언트 오류 핸들이 4 개의 오류 사례를 확인하고 기능에 5 번째 오류 값을 추가하면 클라이언트 핸들러가 테스트하고 중단되지 않을 수 있습니다. 예외를 제기하면 일반적으로 클라이언트가 최신 버전의 라이브러리로 마이그레이션 할 수 있습니다.

고려해야 할 또 다른 점은 팀에서 일할 때 모든 개발자가 그러한 결정을 내릴 수있는 명확한 라인을 그릴 때입니다. 예를 들어 "높은 수준의 물건에 대한 예외, 낮은 수준의 물건에 대한 오류 코드"는 매우 주관적입니다.

어쨌든, 하나 이상의 사소한 유형의 오류가 가능한 경우, 소스 코드는 숫자 리터럴을 사용하여 오류 코드를 반환하거나 처리하지 않아야합니다 (x == -7 ... 인 경우 -7 ...). 항상 명명 된 상수 (X == NO_SUCH_FOO 인 경우 return no_such_foo).

큰 프로젝트에서 작업하는 경우 예외 또는 오류 코드 만 사용할 수 없습니다. 다른 경우 다른 접근법을 사용해야합니다.

예를 들어, 예외 만 사용하기로 결정합니다. 그러나 일단 Async 이벤트 처리를 사용하기로 결정하면. 이 상황에서 오류 처리에 예외를 사용하는 것은 나쁜 생각입니다. 그러나 응용 프로그램의 어느 곳에서나 오류 코드를 사용하는 것은 지루합니다.

따라서 예외와 오류 코드를 동시에 사용하는 것이 정상이라고 생각합니다.

대부분의 응용 프로그램의 경우 예외가 더 좋습니다. 소프트웨어가 다른 장치와 통신 해야하는 시점은 예외입니다. 내가 일하는 도메인은 산업 통제입니다. 여기서 오류 코드가 선호되고 예상됩니다. 그래서 내 대답은 상황에 달려 있다는 것입니다.

또한 결과에서 스택 추적과 같은 정보가 실제로 필요한지 여부에 달려 있다고 생각합니다. 그렇다면, 당신은 객체에 문제에 대한 많은 정보를 가득 채우는 예외로 이동합니다. 그러나 결과에 관심이 있고 그 결과에 관심이없는 경우 그 결과를 신경 쓰지 않으면 오류 코드를 사용하십시오.

예를 들어 파일을 처리하고 IOException에 직면 할 때 클라이언트는 파일 또는 파일을 개설하는 데있어서 트리거 된 위치에서 알고있는 데 관심이있을 수 있습니다. 그러나 로그인 메소드와 같은 시나리오는 성공 여부를 알고 싶어합니다. 부울을 반환하거나 올바른 메시지를 표시하고 오류 코드를 반환합니다. 여기서 클라이언트는 논리의 어느 부분이 해당 오류 코드를 일으킨 지 아는 데 관심이 없습니다. 그는 자격 증명이 유효하지 않거나 계정 잠금 등을 알고 있습니다.

내가 생각할 수있는 또 다른 usecase는 데이터가 네트워크에서 이동할 때입니다. 원격 메소드는 예외 대신 오류 코드 만 반환하여 데이터 전송을 최소화 할 수 있습니다.

내 일반적인 규칙은 다음과 같습니다.

  • 함수에 하나의 오류 만 나타날 수 있습니다. 오류 코드 사용 (함수의 매개 변수)
  • 둘 이상의 특정 오류가 나타날 수 있습니다.

메소드가 숫자 값 이외의 다른 것을 반환 할 때 오류 코드도 작동하지 않습니다 ...

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top