DDD의 예외


11

DDD를 배우고 있으며 특정 상황에서 예외를 던지는 것에 대해 생각하고 있습니다. 객체가 나쁜 상태로 들어갈 수 없으므로 예외는 괜찮지 만 많은 예에서 데이터베이스에 전자 메일이있는 새 사용자를 추가하려고하면 예를 들어 예외가 발생합니다.

public function doIt(UserData $userData)
{
    $user = $this->userRepository->byEmail($userData->email());
    if ($user) {
        throw new UserAlreadyExistsException();
    }

    $this->userRepository->add(
        new User(
            $userData->email(),
            $userData->password()
        )
    );
}

따라서이 전자 메일을 가진 사용자가 있으면 응용 프로그램 서비스에서 예외를 잡을 수는 있지만 try-catch 블록을 사용하여 응용 프로그램의 작동을 제어해서는 안됩니다.

가장 좋은 방법은 무엇입니까?


1
도메인 서비스 (핸들러)가 예외를 던지는 것이 좋습니다.
Andy

답변:


20

DDD의 기본 원칙 중 하나는 비즈니스 규칙을 시행해야 할 장소에 가능한 한 가깝게 배치하는 것입니다. 이것은 시스템을보다 "일관성있게"만들기 때문에 매우 중요한 개념입니다. "위쪽으로"이동 규칙은 일반적으로 빈혈 모델의 표시입니다. 여기서 개체는 단지 데이터의 백이며 규칙에는 해당 데이터가 적용되어 적용됩니다.

빈혈 모델은 DDD로 시작하는 개발자에게 많은 의미가 있습니다. 이메일을 검증하는 데 필요한 정보가 주입 된 User모델 및 모델을 작성합니다 EmailMustBeUnqiueRule. 단순한. 우아한. 문제는 이러한 "종류의"사고는 본질적으로 기본적으로 절차 적이라는 것입니다. DDD가 아닙니다. 결국 수십 가지가 Rules깔끔하게 포장되고 캡슐화 된 모듈이 남아 있지만 더 이상 변경이 불가능한 시점에 대한 컨텍스트가 완전히 없어서 언제 어디서 시행되는지 명확하지 않기 때문입니다. 말이 돼? 그것은 자명 A는 것일 EmailMustBeUnqiueRulea의 생성에 적용됩니다 User에 대한,하지만 UserIsInGoodStandingRule?. 천천히 그러나 확실하게, 추출의 입자 화Rules문맥에서 벗어나면 이해하기 어려운 시스템을 갖게되므로 변경할 수 없습니다. 실제 크 런칭 / 실행이 너무 길어서 모델이 초점을 풀기 시작할 때에 만 규칙을 캡슐화해야합니다.

이제 구체적인 질문으로 : Service/ CommandHandler던지기 문제 Exception는 비즈니스 로직이 도메인에서 유출되기 시작한다는 것입니다 ( "상향"). 왜 않는 Service/의 CommandHandler이메일을 알 필요가 고유해야합니다? 애플리케이션 서비스 계층은 일반적으로 구현보다는 조정에 사용됩니다. ChangeEmail시스템에 메소드 / 명령을 추가하면 간단히 그 이유를 알 수 있습니다 . 이제 두 메소드 / 명령 핸들러 모두 고유 한 검사를 포함해야합니다. 개발자가를 "추출"하려는 유혹을받는 곳 EmailMustBeUniqueRule입니다. 위에서 설명했듯이, 우리는 그 길을 가고 싶지 않습니다.

추가적인 지식 경색은 우리에게 더 많은 DDD 답변으로 이어질 수 있습니다. 전자 메일의 고유성은 User개체 컬렉션 전체에 적용되어야하는 고정적입니다 . 도메인에 " User객체 컬렉션"을 나타내는 개념이 있습니까? 아마 내가 어디로 가는지 알 수있을 것 같아요.

이 특별한 경우 (그리고 여러 콜렉션에 걸쳐 불변을 적용하는 것과 관련하여)이 논리를 구현하기에 가장 좋은 장소는 귀하 Repository입니다. 이러한 Repository종류의 유효성 검사 (데이터 저장소)를 실행하는 데 필요한 추가 인프라를 "알기" 때문에 특히 편리합니다 . 귀하의 경우, 나는이 검사를 add방법 에 넣을 것 입니다. 이 말이 맞습니까? 개념적으로이 방법은 User시스템에 진정으로 a 를 추가 합니다. 데이터 저장소는 구현 세부 사항입니다.


무슨 말인지 물어봐도 Moving rules "upwards" is generally a sign of an anemic model될까요? 위쪽은 응용 프로그램 계층을 의미합니까? 또는 도메인 모델?
Anyname Donotcare

1
"상향"은 애플리케이션 계층을 향한 것을 의미합니다 (계층화 된 아키텍처를 고려하십시오). 위의 내용을 다루었지만 규칙을 위로 올리는 이유는 빈혈 모델의 신호이기 때문에 핵심 도메인 모델을 갖는 전체 목적을 상실하는 방식으로 데이터와 동작의 분리를 나타냅니다. 이메일 유효성 검사가 이메일을 보내는 것과 별개의 모듈에있는 경우 Email모델은 전송하기 전에 변이를 검사하는 데이터 백이어야합니다. 참조 : softwareengineering.stackexchange.com/questions/372338/…
킹 사이드 슬라이드

2
도메인 논리를 리포지토리로 이동하는 것이 잘못되었습니다. 도메인 계층에서 루트를 집계하여 도메인 규칙을 시행해야합니다.
Arash

1
@Arash Set 유효성 검사는 까다 롭고 종종 DDD와 잘 어울리지 않습니다. 해당 프로세스 시도 하기 전에 (a를 추가 하기 전에) 일부 프로세스가 작동하는지 확인 User하거나이 특정 종류의 불변이 도메인에 깔끔하게 캡슐화되지 않는다는 사실을 인정해야합니다. 전자는 절차상의 패러다임을 초래하는 데이터와 행동의 분리를 나타냅니다. 이것은 이상적이지 않습니다. 검증이 존재한다 하지, 데이터를 중심으로 데이터입니다. 또한이 규칙 하나만 확인하는 도메인 서비스를 만들면 어떤 이점이 있습니까? 표면 상으로,이 서비스는 ...
킹 사이드 슬라이드

1
@Arash 커플 여러분 Repository, User그러므로,이 불변을하고 어쨌든 추진하는 순수 주의자의 비전을 달성하지 않습니다. 리포지토리 구현은 도메인의 일부이므로 특정 책임이 부여 될 수 있습니다.
킹 사이드 슬라이드

0

응용 프로그램의 모든 계층에서 유효성 검사를 시행 할 수 있습니다. 어떤 규칙을 적용 할 것인지는 응용 프로그램에 따라 다릅니다.

예를 들어 엔터티는 비즈니스 규칙을 나타내는 메서드를 구현하고 유스 케이스는 애플리케이션에 특정한 규칙을 구현합니다.

Gmail과 같은 이메일 서비스를 구축하는 경우 "사용자는 고유 한 이메일 주소를 가져야합니다"규칙이 비즈니스 규칙이라고 주장 할 수 있습니다.

새 CRM 시스템에 대한 등록 프로세스를 구축하는 경우이 규칙이 사용 사례의 일부일 수 있으므로이 규칙은 사용 사례에서 가장 잘 구현 될 수 있습니다. 또한 사용 사례 테스트에서 리포지토리 호출을 쉽게 스텁 할 수 있으므로 테스트하기가 더 쉬울 수도 있습니다.

추가 보안을 위해이 규칙을 저장소에 적용 할 수도 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.