2010-12-31 2 views
6

이 말은, 예를 들어, 나는 PostsService을 가지고 게시물을 만듭니다 :서비스 계층에서 어떤 유형의 결과를 반환해야합니까?

public class PostsService : IPostsService 
{ 
    public bool Create(Post post) 
    { 
     if(!this.Validate(post)) 
     { 
      return false; 
     } 

     try 
     { 
      this.repository.Add(post); 
      this.repository.Save(); 
     } 
     catch(Exception e) 
     { 
      return false; 
     } 
    } 
} 

이 가진 문제는 예외가 저장소 작업을하는 동안 발생하는 경우, 그것을 삼킨 점이다. Create()false이고 소비자가 알고있는 것은 Post이 추가되지 않았지만 을 알지 못한다는 것입니다.

public class ServiceResult 
{ 
    public bool Success { get; private set; } 
    public Exception Exception { get; private set; } 
} 

이 좋은 디자인 될 것이다 :

대신에, 나는 ServiceResult 클래스를 갖는 생각했다? 아니면 이러한 오류를 소비자에게보고해야합니까? "게시물을 추가하는 동안 오류가 발생했습니다."라고 말하는 것으로 충분합니다. 그런 다음 서비스 내부에 예외를 기록 하시겠습니까?

기타 제안 사항에 감사드립니다.

답변

3

나는 의 범위에 따라 달라질 것이라고 생각합니다. 이유는입니다. 일부 실패 이유는 소비자와 관련되어서는 안되며 제 의견으로는 서비스에 기록되어야합니다. 반면에 소비자에게 이러한 이유에 대한 정보를 제공해야하는 경우가 있으므로 로깅 외에도 오류의 원인을 어떻게 든 표시해야합니다.

예를 들어, 사용자 등록 서비스의 매우 일반적인 사용 예를 가정 해보십시오. 사용자 (사용자 핸들, 이메일 등)를 식별하는 고유 한 속성을 가질 가능성이 큽니다. 이 고유성은 서비스 (그리고 아마도 데이터베이스 수준에서도)에 의해 시행되어야합니다. 이제 소비자가 사용자를 등록하려고 시도하고 제약 조건 위반으로 인해 실패한 경우 소비자에게이 이유를 통보해야합니다 (다른 사용자 핸들을 시도 할 수 있음). 실패한 검증은 대다수 동일한 시나리오에서 이루어집니다.

내부 DB 문제가있는 경우 소비자는 세부 사항을 알릴 필요가 없습니다 (서비스에 대한 독점 책임이므로 소비자가 아무 것도 할 수없는 것이므로).

사실을 감안할 때 부울 값을 반환하는 것은 많은 경우에 불충분하다고 생각합니다. 그래서 어떤 종류의 ServiceResult 타입은 나쁜 생각처럼 들리지 않습니다. 나는 Exception을 포함 할 것인지 확신하지 못한다. 그러나 서비스에 특정한 ServiceExpection을 만들 수 있습니다. 때로는 오류 코드도이 문제가 발생하지 않습니다.

+0

답변 해 주셔서 감사합니다. 실제 예외에 비해 오류 메시지 * 목록을 반환하는 것이 좋다고 생각하십니까? – TheCloudlessSky

+0

@ TheCloudlessSky. 내 경험으로는 큰 차이는 아니지만, 일반적으로 소비자를 Actionscript에 작성하고, 서비스 부분을 PHP 또는 .NET으로 작성하기 때문에 가능할 수 있습니다. 그래서 소비자 관점에서 볼 때, 예외는 단지 메시지 일 뿐이며, try/catch로 잡을 수있는 실제 예외는 아닙니다. 어쨌든, 중요한 측면은 이러한 메시지를 귀하의 앱에 맞게 만드는 것이라고 생각합니다. 이것은 좀 더 많은 작업 일 수 있지만, API의 일부로 만들고 있으므로 문서화되어 있으며 어떤 유형의 오류가 예상되는지에 대해 양측이 동의합니다. –

+0

(계속) 예를 들어, 예전에는 오류가 발생했을 때마다 모든 예외를 반환 한 일부 Java 서비스와 함께 작업했습니다. 예를 들어 오라클 드라이버가 예외 제한을 위반했음을 나타내는 예외 트렁크 (예 : 내 대답은, 실제로, 이것은 게으름에서였다, 나는 추측한다). 나는 이것을 시도하지 않기로 결정했다. 이것은 소비자를 백엔드의 일부 DB 드라이버에게 묶어주기 때문이다. 이것은 비합리적이다. 반면, 위반 된 비즈니스 특정 규칙을 나타내는 메시지를 갖는 것은 최종 사용자에게 알리는 데 매우 유용합니다. –

0

WCF를 사용하는 경우 ServiceResult 또는 이와 유사한 SOA 레이어의 예외 처리를 권장합니다.

귀하의 방법에 대해 FaultContract을 정의해야합니다. 이렇게하면 소비 코드가 던져 질 수있는 예외의 유형을 알 수 있고 따라서 전통적인 try/catch 블록을 사용하여 예외를 처리 할 수 ​​있습니다.

StackOverflow question has a full implementation of Fault Contracts.

프런트 엔드에 "오류가 발생했습니다."라고 말하면되지만 오류 계약을 사용하면 나중에 필요할 경우 오류가있는 UI 레이어에서 오류를 처리 할 수 ​​있습니다.

+0

FWIW - WCF를 사용하고 있지 않습니다. 내가 있어야 할까? 이것은 MVC 응용 프로그램 용입니다. 나는 많은 컨트롤러를 try/catch 블록 (필자가 피하려고했던 것)으로 쓰레기를 버리고 싶지 않았다. 귀하의 의견을 보내 주셔서 감사합니다! – TheCloudlessSky

1

(면책 조항 : 내 경험에 비추어 볼 때 WCF와 같은 기본 제공 기능이 항상 유용하지는 않지만 환경간에 노출/소비 서비스를 통해 많은 노력을 기울였습니다. 클라이언트가 서비스를 사용함).

점점 더 많은 서비스 디자인에서 요청/응답 시스템으로 이동했습니다. (사실, 나는이 점에서 agatha-rrsl 라이브러리를 많이 사용했다.) 그런 디자인에서는 모든 요청 및 응답 유형이 상속되는 BaseRequest 개체와 BaseResponse 개체가 있습니다.

당신이 생각하고있는 것을 계속하면, ServiceResult 클래스가 그러한 BaseResponse의 시작으로 잘 작동 할 것입니다. 그것은 반드시 실제 예외를 필요로하지 않는다,하지만 난 포함하는 경향이 몇 가지 있습니다 :

  1. bool도, 성공에 대한 실제 결과를 반환 한 모든 요청에 ​​대한 성공 또는 실패를 나타내는.
  2. 사용자 정의 개체는 메시지 텍스트 (UI 디스플레이 요구에 대한 추가 사용자 친숙 메시지 텍스트)뿐만 아니라 일종의 메시지 유형 (정보, 경고, 오류 등)을 포함합니다. 관련 경우 스택 추적 등

는 더 나아가, 나는 또한 몇 가지를 포함하고 싶은 BaseRequest 등 원래 사용자, 호스트 등

아이디어는 그 서비스 자체가해야이다 never 원시 예외를 throw합니다. 서비스를 사용하는 사람은 응답이 일종의 실패를 나타내는 경우에도 항상 유효한 응답을 얻을 것으로 예상해야합니다. 매회 돌아와서 그 정보를 다루는 방법을 알기 위해 몇 가지 기본 정보가 필요합니다.

+0

답변 해 주셔서 감사합니다. 이것은 내가 지향하고있는 아이디어의 일종이다. (서비스가 결코 원시 예외를 던지지 않게). 요청/응답 시스템은 꽤 깔끔하게 보입니다.하지만 현재 시스템에는 너무 많을 수 있습니다. 비용을 불문하고, 나는 그것이 정말로 산뜻하다고 생각한다. 그리고 나는 그것을 명심한다. – TheCloudlessSky

2

그래, ServiceResult 클래스는 좋은 생각이지만 예외는 포함하지 않지만 오류를보고 싶지만 예외를 만들거나 던지거나 잡을 필요가없는 경우가 있습니다. 오류 메시지 모음 또는 무엇이 잘못되었는지를 나타내는 열거 유형을 포함합니다 (예 : MembershipCreateStatus).

또한 Exception을 잡지 말고 버그를 찾기가 어렵습니다.

+0

서비스의이 시점에서 문자 그대로 * 모든 예외를 잡으려고하는 경우 왜 '예외'를 ​​잡을 수 있습니까? 나는 다른 코드에서 특정 예외를 잡아야한다는 것을 알고 있지만, 서비스가 모든 오류를 삼켜 야하기 때문에 이해가되지 않습니까? – TheCloudlessSky

+1

@ TheCloudlessSky : 왜 모든 예외 사항을 삼킬 필요가 있습니까? –

+0

소비자가 try/catch로 흩어 질 필요가 없도록. 소비자가 예외에 대해 걱정할 필요는 없지만 그에 따라 오류 메시지를 처리 ​​할 수 ​​있다는 생각을 좋아합니다. – TheCloudlessSky

1

서비스 지향 아키텍처의 주요 이점 중 하나는 시스템의 구성 요소를 분리한다는 점입니다. 호출 레이어가 서비스에 대해 더 많이 알수록 레이어가 더욱 밀접하게 결합됩니다. 이 논리에 이어 호출 계층에 가능한 한 오류를 알리는 것이 더 좋으며 서비스 호출에 실패했음을 알아야합니다.

호출 계층 이 실제로이 서비스가 실패한 이유를 알아야합니까? 그것에 대해 실제로 무엇을 할 수 있습니까? 사용자에게 더 나은 메시지를 보여줄 수 있습니까? 이 경우 사용자가 세부 사항에 대해 정말로 신경을 씁니까? 개발자가하는 것처럼 사용자가 더 많이 알고 싶어한다고 생각하는 것은 쉽습니다. 그러나 개발자는 최종 사용자 메시지가 아닌 로그에서 오류 메시지에 대한 정보를 가져와야합니다.

+0

@James - 예, 좋은 지적입니다. 이것이 내가 알아 내려고 노력한 것입니다. 소비자가 * 정말로 * 왜 * 무언가가 실패했는지 (물론 검증 이외에 ...) 신경 씁니까? 그래서 당신의 마음에,'bool'을 돌려 주면 충분할까요? – TheCloudlessSky

+0

한편 사용자에게 더 많은 정보를 제공하면 개발 속도가 빨라집니다. 사용자 프로그래머는 서비스가 "이 시간에 내가 뭘 잘못 했니?"라는 질문에 불복 할 때마다 전화로 서비스 공급자에게 전화하지 않아도됩니다. – Dialecticus

+0

@ 제임스. 나는 당신이 디커플링에 관해 말하는 것에 동의합니다. 그러나 때때로 사용자가 알아야 할 점과 더 중요한 것은 개발자가 무엇이 잘못되었는지 알아야한다는 것입니다. 나는 서비스의 내부 오류 (버그, 드문 조건 등)를 의미하지 않습니다. 그러나 일반적으로 예상되는 오류 조건은 API의 일부 여야하며 문서화되어 그에 따라 통보되어야합니다. 항상 로그에 의존 할 수는 없습니다 (페이스 북에 로그를 표시하도록 요청하여 문제가 끝났거나 요청이 잘못되었거나 잘못되었거나 필요한 버그가 있었기 때문에 요청이 실패했는지 알 수 있습니다) 고정?). –

1

모든 예외를 잡는 것은 정말 좋은 생각입니다. 당신은 합리적으로 처리 할 수있는 것을 잡습니다. 모든 예외를 처리 할 수는 없으므로 왜 잡는 중입니까? 스택 추적을 방지하려면?

사용자가 끔찍한 스택 추적을 보지 못하도록하려는 경우, 그 사실을 알게되지만 죽기를 원할뿐 아니라 무언가가 손상되지 않도록 끔찍하게 죽기를 원합니다.

서비스가 OutOfMemoryException을 던졌을 때 방금 막 잡았으며 응용 프로그램이 체를 누설하거나 부적절하게 대형 객체를 할당하고 있는지 여부를 알 수 없습니다.

그건 나쁜 것입니다. 당신이 잘못 무엇을 볼 수있는 사용자를하지 않으려면

는, 당신은 말을 당신의 캐치를 변경해야합니다 :

catch (Exception e) 
{ 
    //send it to yourself, log it. Just don't swallow it. 
    LogErrorAndEmailDevTeam(e); 
    throw new SaveFailedException("We're sorry. \n" + 
    "It's not your fault, but something bad happened.\n\n" + 
    "We've been notified and will fix it as soon as possible."); 
} 

을하지만 더 나은 응용 프로그램이 잡기의 끔찍한 죽음을 대신 죽게하는 것 그 예외가 있으므로 뭔가 잘못되었을 때 빨리 알 수 있습니다.

응용 프로그램이 손상된 상태로 계속되기를 원하지 않지만 그게 catch (Exception)입니다. 던져진 것이 무엇이든지 다룰 수 있다고 확신합니까?

+0

입력 해 주셔서 감사합니다. OP의 맨 아래에서 말했듯이, 나는 이미 잡힌 예외를 기록한 다음 거기에서부터 진행할 생각을하고있었습니다. 몇 가지 질문 : 제가 작업 패턴의 단위를 가지고 있으며, 서비스의 모든 동작이 끝날 때 커밋이 호출된다면, 작업 단위에 커밋을 시도하거나 catch하는 것이 좋습니다. 이것이 예외적 인 경우가되기 때문에 끔찍한 죽음을 맞이할 것인가? 또한'ServiceResult'를 사용하면 다른 게시물에서 언급 한 것처럼 * messages *를 반환 할 수 있습니까? 감사! – TheCloudlessSky

+0

원래 예외를 새 예외의 생성자로 전달하는 것을 잊었습니다. –

+1

@Max Nope, 그것은 의도적으로 사용되었습니다. DevTeam은 전자 메일을 열거 나 로그를 통해 경고받을 때 실제 예외를받습니다. 사용자는 친숙한 오류 메시지가 포함 된 알려진 예외 만 가져옵니다. –

관련 문제