2013-04-26 5 views
64

사용자를 생성하는 작업이 있다고 가정합니다. 지정된 전자 메일 또는 사용자 이름이 있으면이 작업이 실패 할 수 있습니다. 실패한 경우 정확히 이유를 알아야합니다. 내가보기에 이것을하는 세 가지 접근법이 있으며 나는 확실한 승자가 있는지 궁금해하고 있습니다.가장 바람직한 디자인은 test-create, try-create, create-catch입니까?

class User 
{ 
    public string Email { get; set; } 
    public string UserName { get; set; } 
} 

그리고 작업을 만들 달성의 3 가지 방법이 있습니다 :

if (UserExists(user)) act on user exists error; 
if (UsernameExists(user)) act on username exists error; 
CreateUser(user); 

UserExists 및 UsernameExists을 테스트-만들기에 요청 만든다

그래서, 여기에 클래스 사용자입니다 db 서버가 유효성 검사를 수행합니다. 이러한 호출은 API가 올바르게 사용되도록 CreateUser에서 다시 반복됩니다. 유효성 검사에 실패하면 두 경우 모두 ArgumentOutOfRangeException을 throw합니다. 그래서 성과가 있습니다.

enum CreateUserResultCode 
{ 
    Success, 
    UserAlreadyExists, 
    UsernameAlreadyExists 
} 

if (!TryCreate(user, out resultCode)) 
{ 
    switch(resultCode) 
    { 
     case UserAlreadyExists: act on user exists error; 
     case UsernameAlreadyExists: act on username exists error; 
    } 
} 

이 패턴은 한 번만 검증을 수행을 시도-만들기, 그러나 우리는 좋은 습관으로 간주되지 않습니다 소위 오류 코드를 사용하여 리조트.

try 
{ 
    CreateUser(user); 
} 
catch(UserExistsException) 
{ 
    act on user exists error; 
} 
catch(UsernameExistsException) 
{ 
    act on username exists error; 
} 

내가 여기에 오류 코드를 사용하지 않는 잡기 만들기,하지만 지금은 모든 경우에 대해 별도의 예외 클래스를 만들어야합니다. 그것은 다소 예외가 어떻게 사용되어지기를 원하지만 enum 엔트리 대신 별도의 예외를 만드는 것이 가치가 있는지 궁금합니다.

그래서 우리는 확실한 승자가 있습니까? 아니면 더 맛이 좋은가요?

+9

관심을 가질만한 곳 Raymond Chen의 블로그 게시물 [ "Cleaner, elegant and wrong"] (http://blogs.msdn.com/b/oldnewthing/archive/2004/04/22/118161.aspx) 및 "더 깨끗하고, 우아하고, 알아보기가 더 힘듭니다"(http://blogs.msdn.com/b/oldnewthing/archive/2005/01/14/352949.aspx), 오류 코드 예외보다 낫다. – ruakh

+0

다른 외부 참조는 무엇입니까? 나는 매우 흥미 롭다. – QED

답변

80

그럼 우승자가 분명합니까? 아니면 더 맛이 좋은가요?

첫 번째 옵션은 근본적인 결함이있다 - CreateUser 외부 자원에 의존하고, 다른 구현하여 테스트 사이에 만들 수 있습니다 경우는 결코 안전하거나 스레드 안전 할 않을거야. 일반적으로이 때문에 "패턴"을 피하는 경향이 있습니다.

다른 두 가지 옵션과 마찬가지로 - 오류가 인 것으로 예상되는지 여부는 실제로는입니다. CreateUser이 다소 정상적으로 실패 할 것으로 예상되는 경우 예외를 사용하면 기본적으로 제어 흐름에 예외가 사용되므로 Try * 패턴을 선호합니다.

오류가 실제로 예외적 인 경우 예외가 더 이해할 수 있습니다.

+13

+1 스레드 안전 문제 – ken2k

+0

@Reed 나는 Try * 접근법을 점점 더 고려하고 있지만 오류 처리를 위해 오류 코드를 사용해서는 안되는 모든 책과 기사에 실망합니다 (예 : [Exception Throwing] (http://msdn.microsoft.com/en-us/library/ms229030 (v = vs.100) .aspx)). 그들은 가장 큰 문제 중 하나가 호출 스택 위로 오류 코드를 전달하는 방법이라고 설명합니다. 어떤 생각 하나? – andriys

+2

@andriys 호출 스택을 넘겨야하는지 여부에 따라 다릅니다. 필요하다면 예외가 더 좋을 수 있습니다. 그러나 이것이 실제로 제어 흐름 (예제 코드와 같음)이면 단일 결과를 얻는 것이 더 간단하고 깨끗합니다. 그래도 별도의 검사는 피할 수 있습니다 .... –

37

시험 만들기는 경쟁 조건을 야기 할 수 있으므로 좋은 생각이 아닙니다. 그것은 또한 여분의 일을 할 가능성이 있습니다.

Try-Create는 오류 (예 : 사용자 입력의 경우)가 정상적인 코드 흐름의 일부일 것으로 예상되는 경우에 유용합니다.

오류가 정말로 예외적 인 경우 (성능에 대해 걱정하지 않으려는 경우) Create-Catch가 유용합니다.

+3

스레드 안전 문제 +1 – ken2k

+2

데이터베이스를 쳤을 때와 같은 많은 경우에 예외의 성능 비용은 큰 문제가 아님을 지적합니다. 그러나 이러한 예외를 다루는 데 드는 비용은 개념적입니다. 만약 누군가가 당신의'Create-Catch' 로직을 복제하고'Catch' 파트를 잊어 버리면 이상한 일들이 일어날 것입니다,하지만'Try-Create' 케이스에서는 반환 값이 훨씬 더 명백하게 보이고 실패는 조용합니다. 물론 모든 장단점. – Guvante

9

이것은 다소 주관적이지만 지적 할 가치가있는 구체적인 장단점이 있습니다.

테스트 생성 방식의 단점은 경쟁 조건입니다. 두 클라이언트가 거의 같은 시간에 동일한 사용자를 만들려고하면 둘 다 테스트를 통과 한 다음 동일한 사용자를 만들 수 있습니다.

Try-Create와 Create-Catch 사이에서 Create-Catch를 선호하지만 개인적인 취향입니다. Create-Catch는 일반적으로 싫어하는 흐름 제어에 예외를 사용한다고 주장 할 수 있습니다. 반면에 Try-Create는 약간 어색한 output 매개 변수가 필요합니다.이 매개 변수는 쉽게 간과 될 수 있습니다.

그래서 Create-Catch를 선호하지만 논쟁의 여지가 있습니다.

+0

나는 또한이 상황에서 Create-Catch를 선호합니다. 기본 키 위반은 확실히 유효한 예외입니다. 유효하지 않은 사용자 입력에 대해서는 좀 더 모호하지만, 아마도 FormatException을 던질 것입니다. – JosephHirn

4

UserExistsUsernameExists은 모두 DB 호출을 지정했습니다. CreateUser도 데이터베이스 호출을한다고 가정합니다.

왜 데이터베이스가 스레딩 문제를 처리하지 못하게합니까? 테이블에 적절한 제약 조건이 설정되어 있다고 가정하면 저장된 proc 호출에서 오류를 제거 할 수 있습니다.

따라서 Create-Catch에 대한 투표를하겠습니다.

관련 문제