포럼의 게임 인 마피아라는 프로젝트를 작성합니다. 나는 CQRS Event Sourcing + MongoDB를 사용한다. 게임이 시작되면 게임은 각 플레이어에게 임의의 역할을 부여해야합니다. 내가 어떻게 그것을 실현할 수있는 경우, 집계 루트가 이벤트, 예를 들어 "주어진 역할"을 DB에서 (지금 저장 한 이벤트가 아닌) 적용한다면, 항상 다른 결과를 반환 할 임의 함수를 호출 할 것인가?CQRS + 이벤트 소싱에서 임의로 사용하는 방법
답변
집계 루트가 이벤트 (예 : "주어진 역할", DB에 저장 됨)가 적용될 때 실현되는 방법은 항상 임의 함수를 호출합니다. 다른 결과를 반환 할 것인가?
이벤트를 작성하고 이벤트를 적용하는 것은 다른 코드 경로입니다. 이벤트를 적용 할 때 집계가 이미 생각을했기 때문에 이벤트를 적용 할 때 "생각"이 없습니다. 신청서에서해야 할 일은 신실하게 상태를 업데이트하는 것입니다.
즉, 이벤트를 적용 할 때 규칙을 집계하는 것은 총계 작업이 아닙니다.
그래서 역사는 할 수있는 임의 아무 것도 없다는 것을
GameStarted()
RoleAssigned(Alice, Innocent)
RoleAssigned(Bob, Innocent)
RoleAssigned(Charlie, Mafia)
...
공지 사항 같은 것을 보일 것이다; 게임이 원래 무작위 배정을 묘사했는지 여부를 염려하지 않고 게임 상태를 재 확보합니다. 배정이 과거에 발생했기 때문에 배정이 완전히 결정되었습니다 지금. 과제의
랜덤 비트는 집계가 결정
void assignRole(Player p) {
Role role = getRandomRole();
this.apply(RoleAssigned(p, role));
}
추가 답변을 때, 쓰기 경로에 속하는
내가 코드를 변경하는 방법? 이벤트 처리기에 코드를 만드는
class GameEventHandler {
public void Handle(GameStartedEvent message) {
var randomRoles =_randomizer.GetRandomRoles();
foreach(user in userAggregates) {
user.RoleAssign(new AssignRoleCommand(randomRoles[i]));
}
}
}
결정은 "코드 냄새"입니다; 그것은 어딘가에 뭔가 잘못되었다는 단서입니다. 집합체가 명령을 처리 할 때 모델에서 선택해야합니다.
마피아와 같이 적절한 역할 균형을 원할 경우 역할을 할당 할 때 사용중인 변형 규칙에 대해 걱정할 필요가있는 경우 Game
집합이 역할 할당 결정을 소유 할 것으로 예상됩니다.따라서, 임의의 할당을 의미합니다 (StartGameCommand 처리기에서 일어날 것이며, 우리가 전에 보았던 모두 여기에, 하나의 명령을 실행 한 결과로 작성되는 사건이
class Game {
public void startGame() {
this.apply(GameStarted());
var randomRoles =_randomizer.GetRandomRoles();
foreach(userId in this.players) {
this.apply(RoleAssigned(userId, randomRoles[i]);
}
}
}
목록 같은 것을 보일 수 있습니다 모든 트랜잭션은 단일 트랜잭션으로 이벤트 저장소에 기록됩니다). 당신이 정말 그 역할을 할당하는 책임을 각 사용자의 집계를 필요한 경우
한편, 여기에이 논리가 너무
class Game {
public void startGame() {
this.apply(GameStarted(this.players));
}
}
class User {
public void assignRole() {
this.apply(RoleAssigned(this.id, _randomizer.getRandomRole());
}
}
처럼 깨진 것 그리고 이벤트 핸들러가 두 다리 것, 임의의 역할에 대해 모르는 사이에
class GameEventHandler {
public void Handle(GameStartedEvent message) {
foreach(userId in message.players) {
dispatch(AssignRoleCommand(userId));
}
}
}
이벤트 핸들러는 그들은 단지
일반적으로 일부 도메인 동작 (즉, 임의의 역할 할당)을 트리거하는 명령을 사용하면 역할이 데이터베이스의 이벤트에 저장됩니다. RoleAssigned
. 플레이어가 이벤트를 재생하여 게임을 다시 시작할 때이 역할을 유지합니다. 이벤트를 처리하는 코드에서 임의의 역할을 할당하지 않을 것입니다.이 이벤트는 재생되지 않는 명령 처리기에서 수행됩니다. 위의 코드에서
public void Handle<StartGameCommand>()
{
var player = someEventSourcedPlayerRepository.GetOrCreateOrWhatever();
player.assignRole(); // randomly assigns the role and creates event RoleAssigned
someEventSourcedPlayerRepository.Save(); // saves events to db
}
는, 플레이어가 자신의 역할 이벤트를해야합니다. 다음에 플레이어를로드 할 때, 그들의 역할은 이벤트에서 가져옵니다. player.assignRole을 다시 호출하지 마십시오.
예, 나는 당신을 이해하고 다른 사람에게 작업을 위임, 그들은 아무것도하지 않는, 관리자처럼,하지만 난이 원하는 경우에, 그 역할 할당은 자동입니다. 내 프로젝트에서 명령 및 명령 처리기는 요청을 보낼 때 시스템의 상태를 변경합니다. 자동 응답을 원한다면 Event Handlers에 기록하지만 BD에 기록됩니다. 어떻게해야합니까? (나의 끔찍한 영어로 유감스럽게 생각한다) –
나는 혼란 스럽다. 역할을 한 번만 지정 하시겠습니까? 그렇다면, 내가 설명하는대로 명령 처리기 플로우에서 수행하십시오. 그것은 여전히 자동적입니다 - 그 비트는 어디에서나 동일한 로직이어야합니다. – tomliversidge
@tomliversidge 다른 방법으로 임의의 AssignRole 명령을 생성하여 실행할 수 있습니다. 물론 이것은 비즈니스 트랜잭션이 될 것이고 전체 GameStart가 단일 원자 트랜잭션이되지 못하게 할 것입니다. 그러나 이벤트 소싱 스타일에 따라 어쨌든 엄격한 1 "수정 된"AR = 1 트랜잭션을 시행해야하며 AR이 '플레이어'인 경우 범위는 작게 유지됩니다. – guillaume31
좋아,하지만 난 로 전화'클래스 GameEventHandler { 공공 무효 핸들 (GameStartedEvent 메시지) { VAR randomRoles = _randomizer.GetRandomRoles(); 항상 gameAggregate 이벤트 GameStarted를 적용한 것이다 의 foreach (userAggregates의 사용자) { user.RoleAssign (새 AssignRoleCommand (randomRoles [I])) } } } '와 그 의미는 랜덤 랜덤 역할을 전송. 코드를 어떻게 변경해야합니까? –
아니면 (무작위로 역할을 지정하는) 수동으로 한 번만 만들어야합니까? –