나는 한 데이터 저장소에 세분화 된 데이터를 보유 할 수있는 유연성을 좋아해 분석에 대한 큰 가능성을 제공하여 비즈니스 가치를 높이고 필요할 때 성능 향상을 위해 비정규 화 된 데이터를 포함하는 읽기에 다른 데이터를 제공하기 때문에 가난한 사람의 CQRS 1 을 꽤 오랫동안 적응해 왔습니다. .
그러나 불행히도 처음부터 나는이 유형의 아키텍처에 비즈니스 로직을 정확하게 배치 해야하는 문제로 어려움을 겪었습니다.
내가 이해 한 바에 따르면, 명령은 의도를 전달하는 수단이며 도메인 자체와는 관련이 없습니다. 기본적으로 데이터 (원하는 경우 바보) 전송 개체입니다. 이는 서로 다른 기술간에 명령을 쉽게 전송할 수 있도록하기위한 것입니다. 성공적으로 완료된 이벤트에 대한 응답으로 이벤트에도 동일하게 적용됩니다.
일반적인 DDD 애플리케이션에서 비즈니스 로직은 엔터티, 값 개체, 집계 루트 내에 있으며 데이터와 동작이 풍부합니다. 그러나 명령은 도메인 객체가 아니므로 데이터의 도메인 표현으로 제한되어서는 안됩니다.
실제 질문은 다음과 같습니다. 논리가 정확히 어디에 있습니까?
나는 값의 조합에 대한 규칙을 설정하는 매우 복잡한 집계를 만들려고 할 때이 문제에 가장 자주 직면하는 것을 알았습니다. 또한 도메인 객체를 모델링 할 때 객체가 메소드에 도달하는 시점을 알고 있으면 오류없는 패러다임 을 따르고 싶습니다 .
골재 Car
가 두 가지 구성 요소를 사용 한다고 가정 해 봅시다 .
Transmission
,Engine
.
모두 Transmission
와 Engine
값 객체 슈퍼 타입으로 표현하고있어서, 서브 타입을 가지고있다 Automatic
및 Manual
전송하거나 Petrol
및 Electric
엔진 각각.
이 도메인에서 성공적으로 생성 자체 A의 생활 Transmission
이라고해도, Automatic
또는 Manual
, 또는 유형 중 하나는 Engine
완전히 괜찮습니다. 그러나 Car
집계에는 몇 가지 새로운 규칙이 도입 되었으며, 동일한 컨텍스트에서 Transmission
및 Engine
개체를 사용하는 경우에만 적용 할 수 있습니다. 즉:
- 자동차가
Electric
엔진을 사용 하는 경우 허용되는 변속기 유형은Automatic
입니다. - 자동차가
Petrol
엔진을 사용할 때 두 가지 유형 중 하나를 가질 수 있습니다Transmission
.
명령을 만드는 수준 에서이 구성 요소 조합 위반을 잡을 수는 있지만 이전에 언급했듯이 명령에 도메인 계층으로 제한되어야하는 비즈니스 논리가 포함되어 있기 때문에 수행해서는 안되는 것으로 이해합니다.
옵션 중 하나는이 비즈니스 로직 유효성 검사를 명령 유효성 검사기 자체로 옮기는 것입니다. 그러나 이것이 옳지 않은 것 같습니다. 명령을 해체하고 getter를 사용하여 검색 된 속성을 확인하고 유효성 검사기 내에서 속성을 비교하고 결과를 검사하는 것처럼 느껴집니다. 그건 데메테르 법칙을 어기는 것 같아요 .
언급 된 유효성 검사 옵션은 실행 가능하지 않은 것으로 보이기 때문에 명령을 사용하고 집계를 구성해야합니다. 그러나이 논리는 어디에 존재해야 하는가? 구체적인 명령을 처리하는 명령 처리기 내에 있어야합니까? 아니면 명령 유효성 검사기 내에 있어야합니까 (이 방법은 마음에 들지 않습니다)?
현재 명령을 사용하고 있으며 담당 명령 핸들러 내에서 집계를 만듭니다. 그러나이 작업을 수행 할 때 명령 유효성 검사기가 있으면 아무것도 포함하지 않을 것입니다. CreateCar
명령이 존재하면 별도의 경우에 유효한 것으로 알고 있지만 구성 요소가 다르게 말할 수있는 구성 요소가 포함 되기 때문 입니다.
CreateUser
명령을 사용하여 새 사용자를 만드는 다른 유효성 검사 프로세스를 혼합 한 다른 시나리오를 상상해 봅시다 .
이 명령에는 Id
생성 될 사용자와 해당 사용자가 포함되어 있습니다 Email
.
시스템은 사용자의 이메일 주소에 대해 다음 규칙을 명시합니다.
- 특별해야 해,
- 비워 둘 수 없습니다
- 최대 100 자 (db 열의 최대 길이) 여야합니다.
이 경우 고유 한 전자 메일을 갖는 것이 비즈니스 규칙이지만 시스템에서 현재 전자 메일 전체를 메모리에로드하고 명령에서 전자 메일을 확인해야하기 때문에 집계로 확인하는 것은 거의 의미가 없습니다. 집합에 대한 ( Eeeek! 뭔가, 뭔가, 성능). 이 때문에이 검사를 명령 유효성 검사기로 옮기면 UserRepository
종속성으로 사용되며 리포지토리를 사용하여 명령에 전자 메일이있는 사용자가 이미 존재하는지 확인합니다.
이와 관련하여 갑자기 다른 두 개의 전자 메일 규칙을 명령 유효성 검사기에도 넣는 것이 합리적입니다. 그러나 규칙이 실제로 User
집계 내에 있어야한다는 느낌이 들며 명령 유효성 검사기는 고유성에 대해서만 확인해야하며 유효성 검사가 성공하면 User
집계 를 작성하여 CreateUserCommandHandler
저장 될 저장소로 전달해야합니다.
리포지토리의 save 메서드는 집계가 전달되면 일단 불변이 충족되도록 보장하는 집계를 허용하기 때문에 이런 느낌이 듭니다. 논리 (예 : 비어 있지 않음)가 명령 유효성 검증 자체에만 존재하는 경우 다른 프로그래머가이 유효성 검증을 완전히 건너 뛰고 오브젝트 UserRepository
와 함께 save 메소드를 User
직접 호출하여 치명적인 데이터베이스 오류가 발생할 수 있습니다. 너무 오래되었습니다.
이러한 복잡한 검증 및 변환을 개인적으로 어떻게 처리합니까? 나는 대부분 내 솔루션에 만족하지만 내 아이디어와 접근 방식이 선택에 매우 만족하기 위해 완전히 어리석지 않다는 확신이 필요하다고 생각합니다. 나는 완전히 다른 접근법에 전적으로 개방되어 있습니다. 당신이 개인적으로 시도하고 당신을 위해 잘 일한 것이 있다면 나는 당신의 해결책을보고 싶습니다.
1 RESTful 시스템 생성을 담당하는 PHP 개발자로 일하면서 CQRS에 대한 해석은 표준 비동기 명령 처리 방식과 약간 다릅니다 . 명령을 동기식으로 처리해야하기 때문에 명령에서 결과를 반환하는 경우가 있습니다.
CommandDispatcher
.