Nice programing

테스트 생성, 시도 생성, 생성 캐치 중 가장 바람직한 디자인은 무엇입니까?

nicepro 2020. 11. 20. 09:36
반응형

테스트 생성, 시도 생성, 생성 캐치 중 가장 바람직한 디자인은 무엇입니까?


사용자를 생성하는 작업이 있다고 가정 해 보겠습니다. 지정된 이메일 또는 사용자 이름이 있으면이 작업이 실패 할 수 있습니다. 실패한 경우 그 이유를 정확히 알아야합니다. 내가보기에이를 수행하는 세 가지 접근 방식이 있으며 확실한 승자가 있는지 궁금합니다.

그래서 여기에 클래스 사용자가 있습니다.

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

그리고 생성 작업을 수행하는 세 가지 방법이 있습니다.

테스트 만들기

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;
}

여기서는 오류 코드를 사용하지 않지만 이제 모든 경우에 대해 별도의 예외 클래스를 만들어야합니다. 예외가 사용되는 방법은 다소 다르지만 열거 형 항목 대신 별도의 예외를 만드는 것이 가치가 있는지 궁금합니다.

그렇다면 우리는 확실한 승자가 있습니까, 아니면 취향의 문제입니까?


그렇다면 우리는 확실한 승자가 있습니까, 아니면 취향의 문제입니까?

첫 번째 옵션에는 근본적인 결함이 있습니다 CreateUser. 외부 리소스에 의존하는 경우 스레드로부터 안전하거나 안전하지 않으며 테스트 사이에 다른 구현이 생성 될 수 있습니다. 일반적으로 저는이 "패턴"을 피하는 경향이 있습니다.

As for the other two options - it really comes down to whether the failure is expected to happen. If CreateUser would be expected to fail on a somewhat normal basis, the Try* pattern is my preference, as using exceptions essentially becomes using exceptions for control flow.

If the failure would truly be an exceptional case, then exceptions would be more understandable.


Test-Create can cause race conditions, so it's not a great idea. It also likely does extra work.

Try-Create is good if you expect errors to be part of normal code flow (such as in the case of user input).

Create-Catch is good if errors are truly exceptional (so you're not worried about performance).


This is somewhat subjective, but there are some concrete pros and cons that are worth pointing out.

One drawback of the test-create approach is the race condition. If two clients attempt to create the same user at approximately the same time, it may be possible for them to both pass the tests, and then attempt to create same user.

Between Try-Create and Create-Catch, I prefer Create-Catch, but that's personal taste. One could argue that Create-Catch uses exceptions for flow control, which is usually frowned upon. On the other hand, Try-Create requires a somewhat awkward output parameter, which could be more easily overlooked.

So, I prefer Create-Catch, but there's definitely room for debate here.


You specified that UserExists and UsernameExists both make DB calls. I'll assume that CreateUser also makes a database call.

Why not let the database handle your threading issues? Assuming further that there are proper constraints set up on your table(s), you can let it err-out within a stored proc call.

Therefore, I'll cast my vote for Create-Catch.

참고URL : https://stackoverflow.com/questions/16241866/which-design-is-most-preferable-test-create-try-create-create-catch

반응형