2011-09-10 3 views
3

나는 CQRS 및 이벤트 소싱으로 첫 번째 진출에 뛰어 들고 있으며 몇 가지 지침이있는 몇 가지 ID를 가지고 있습니다. 저는 SO 스타일 평판 시스템을 구현하고 싶습니다. 이것은이 아키텍처에 가장 적합합니다.CQRS 및 이벤트 소싱을 사용하는 SO 스타일의 평판 시스템

예를 들어 그대로 유지하십시오. 질문이 올라가면 UpvoteCommand이 발생하여 총 점수가 올라가고 QuestionUpvotedEvent이 발생합니다.

평점 점수를 높일 수있는 QuestionUpvotedEvent을 구독해야하는 사용자 집계와 비슷합니다. 하지만 어떻게/언제이 구독을하는 것이 나에게 명확하지 않습니까? Greg Youngs의 예에서 이벤트/명령 처리는 global.asax에서 처리되지만 집계 ID를 기반으로하는 라우팅은 포함되지 않습니다.

모든 사용자 집합체가 올바른 것으로 보이지 않는 모든 QuestionUpvotedEvent에 가입하는 것처럼 보입니다. 그러한 구성표 작업을 만들기 위해 이벤트 처리기는 해당 사용자가 방금 upvoted 질문을 소유했는지 식별해야합니다. Greg Young은 단순히 상태 변경을 포함해야하는 이벤트 처리기 코드에 있어서는 안된다고 암시합니다.

여기에 무엇이 잘못 되었습니까?

모든 안내 사항에 감사드립니다.

편집

나는 우리가 여기서 얘기하는 것은 질문 & 사용자 골재 사이의 상호 집계 통신 것 같다. 내가 볼 수있는 한 가지 해결책은 QuestionUpvotedEventReputationEventHandler에 가입하여 해당 사용자 AR을 가져 와서 해당 개체에 대해 해당 메서드를 호출 할 수 있다는 것입니다. YourQuestionWasUpvoted. 그러면 사용자 특정 UserQuestionUpvoted 이벤트가 생성되어 향후 재생 기능이 보존됩니다. 이 방향이 바른가요? 2

편집은 또한 구글 그룹 here에 대한 설명을 참조하십시오.

답변

6

집계 자체는 이벤트에 가입하지 않아야합니다. 도메인 모델은 이벤트 만 발생시킵니다. 이벤트를 구독하는 쿼리 측면 또는 기타 인프라 구성 요소 (예 : 전자 메일 구성 요소)입니다.

도메인 서비스은 둘 이상의 집계가 관련된 use-cases/명령으로 작동하도록 설계되었습니다.

내가이 상황에서 어떻게 할 것인지 :

  • 가 호출됩니다 VoteUpQuestionCommand.
  • 의 핸들러는 전화 VoteUpQuestionCommand :

    IQuestionVotingService.VoteUpQuestion (GUID questionId, 가이 사용자 ID);

  • 그러면 사용자 질문 모음 & 사용자 집계를 모두 처리하여 user.IncrementReputation (int amount) 및 question.VoteUp()와 같은 두 가지에 적절한 메소드를 호출합니다. 그러면 두 가지 이벤트가 발생합니다. UsersReputationIncreasedEventQuestionUpVotedEvent 각각은 쿼리 측에서 처리합니다.

+0

집계가 이벤트 핸들러에 가입하는 예제를 보았지만 문제가 복잡하다고 생각합니다. – madcapnmckay

+0

제안 된 솔루션이 마음에 듭니다. 외부 조정자 서비스가 로직을 수행한다는 점에서 Tom이 제안한 솔루션과 비슷합니다. 제가 처음에 피하고 싶었던 것은 명성이 이벤트에 참여함으로써 증가한 가치를 지니고 있다는 것입니다. 내가 당신의 솔루션에서 볼 수있는 유일한 단점은 질문을 상대로 평판이 높아진 가치를 변경하면 쉽게 재 계산할 수 없다는 것입니다 (SO가 과거에 한 것처럼). 상황에 따라 플러스로 볼 수도 있지만 재조정 할 능력이 필요합니다.흥미로 웠던 것은 많은 다른 해결책을 촉발 시켰습니다 (편집 참조). – madcapnmckay

+1

명성이 이벤트에서 증가한 금액을 반드시 입력해야하는지 확실하지 않습니다. 투표 금액이 방금 쿼리 측면에 저장 될 수 있으며 'UserQuestionVotedUpEvent'이벤트가있을 수 있습니다.이 이벤트는 처리 될 때 현재 투표의 가치를 조회하고 그 금액만큼 사용자 평판을 증가시킵니다. 최대 득표의 가치를 바꾸는 것은 업데이트 쿼리의 경우 일뿐입니다. 물론 이것은 도메인 자체가 사용자의 실제 평판 점수와 관련이없는 경우에만 작동합니다. –

0

사용자 집계는 QuestionAuthored 이벤트를해야 ... 해당 이벤트에 유사 그것이이 QuestionUpvotedEvent 등으로부터 unsibscribing 같은 적절한 처리를 수행하는 QuestionDeletedEvent 및/또는 QuestionClosedEvent을 가져야한다 ... QuestionUpvotedEvent 구독입니다

편집 - 코멘트에 따라 :

내가 질문을 구현하는 것이 외부 이벤트 소스와 게이트웨이를 통해 처리합니다. 게이트웨이는 모든 재생을 올바르게 처리 할 책임이있는 사람이므로 거부 이벤트와 같은 특별한 이벤트는 제외하고 최종 결과는 정확히 동일합니다 ...

+0

이벤트에서 집계를 재구 축하려면 어떻게해야합니까? 집계에 RebuildFromEvents 메서드가 있다고 가정 해보십시오. 재생하려면 사용자 ID에 대한 모든 이벤트를 가져 와서이 메소드를 통해 밀어 넣으십시오. 귀하의 설명에서 전에 같은 평판 값을 끝내지 않을 것입니다 ... – madcapnmckay

+0

나는 "외부 이벤트 소스"로 질문을 구현하고 차례로 "재생 모드를 다루는 책임이있는 게이트웨이를 통해 처리 할 것입니다 "...이 방법으로 문제가 발생하지 않을 것입니다. – Yahia

+0

예제가 있습니까? 이벤트 재생을 본 모든 예는 집계에 의해 처리됩니다. 시나리오의 게이트웨이가 내 편집에서 언급 한 ReputationEventHandler입니까? 이 처리기는 사용자 이벤트를 생성하는 명령을 보내는 것으로 끝나기 때문에 재생은 문제가되지 않습니다. 핸들러는 전 세계적으로 등록 할 수도 있습니다. – madcapnmckay

2

내 경험칙 : AR 간 통신을 사용할 경우 사거. 그것은 트랜잭션 경계 내에서 물건을 유지하고 귀하의 링크를 명시 적으로 처리하기 쉽도록 유지합니다.

0

이것은 이전 질문이며 답변으로 태그가 지정되었지만 뭔가를 추가 할 수 있다고 생각합니다. 몇 개월 동안 CQRS + ES에서 작은 프레임 워크 및 응용 프로그램 기반을 읽고 연습하고 작성한 후 CQRS는 구성 요소의 종속성과 책임을 분리하려고합니다. 일부 리소스에서 각 명령을 작성하십시오 은 명령 처리기에서 최대 하나의 집계를 변경해야합니다 (처리기에 둘 이상의 집계를로드 할 수 있지만 그 중 하나만 변경할 수 있음). 그래서 귀하의 경우에는 모범 사례가 @Tom 대답이고 사가를 사용해야한다고 생각합니다. 프레임 워크가 내 작은 프레임 워크와 마찬가지로 saga를 지원하지 않으면 UpdateUserReputationByQuestionVotedEvent과 같은 이벤트 핸들러를 만들 수 있습니다. 이 경우 핸들러는 UpdateUserReputation(Guid user id, int amount) 또는 UpdateUserReputation(Guid user id, Guid QuestionId, int amount) 또는 UpdateUserReputation(Guid user id, string description, int amount)을 작성하십시오. 명령이 핸들러로 전송 된 후 핸들러는 사용자 ID로 사용자를로드하고 상태 및 특성을 갱신합니다. 이러한 유형의 처리에서는보다 복잡한 시나리오 또는 워크 플로를 만들 수 있습니다.