2016-08-23 5 views
2

포럼의 게임 인 마피아라는 프로젝트를 작성합니다. 나는 CQRS Event Sourcing + MongoDB를 사용한다. 게임이 시작되면 게임은 각 플레이어에게 임의의 역할을 부여해야합니다. 내가 어떻게 그것을 실현할 수있는 경우, 집계 루트가 이벤트, 예를 들어 "주어진 역할"을 DB에서 (지금 저장 한 이벤트가 아닌) 적용한다면, 항상 다른 결과를 반환 할 임의 함수를 호출 할 것인가?CQRS + 이벤트 소싱에서 임의로 사용하는 방법

답변

0

집계 루트가 이벤트 (예 : "주어진 역할", 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)); 
     } 
    } 
} 

이벤트 핸들러는 그들은 단지

+0

좋아,하지만 난 로 전화'클래스 GameEventHandler { 공공 무효 핸들 (GameStartedEvent 메시지) { VAR randomRoles = _randomizer.GetRandomRoles(); 항상 gameAggregate 이벤트 GameStarted를 적용한 것이다 의 foreach (userAggregates의 사용자) { user.RoleAssign (새 AssignRoleCommand (randomRoles [I])) } } } '와 그 의미는 랜덤 랜덤 역할을 전송. 코드를 어떻게 변경해야합니까? –

+0

아니면 (무작위로 역할을 지정하는) 수동으로 한 번만 만들어야합니까? –

1

일반적으로 일부 도메인 동작 (즉, 임의의 역할 할당)을 트리거하는 명령을 사용하면 역할이 데이터베이스의 이벤트에 저장됩니다. 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을 다시 호출하지 마십시오.

+0

예, 나는 당신을 이해하고 다른 사람에게 작업을 위임, 그들은 아무것도하지 않는, 관리자처럼,하지만 난이 원하는 경우에, 그 역할 할당은 자동입니다. 내 프로젝트에서 명령 및 명령 처리기는 요청을 보낼 때 시스템의 상태를 변경합니다. 자동 응답을 원한다면 Event Handlers에 기록하지만 BD에 기록됩니다. 어떻게해야합니까? (나의 끔찍한 영어로 유감스럽게 생각한다) –

+0

나는 혼란 스럽다. 역할을 한 번만 지정 하시겠습니까? 그렇다면, 내가 설명하는대로 명령 처리기 플로우에서 수행하십시오. 그것은 여전히 ​​자동적입니다 - 그 비트는 어디에서나 동일한 로직이어야합니다. – tomliversidge

+0

@tomliversidge 다른 방법으로 임의의 AssignRole 명령을 생성하여 실행할 수 있습니다. 물론 이것은 비즈니스 트랜잭션이 될 것이고 전체 GameStart가 단일 원자 트랜잭션이되지 못하게 할 것입니다. 그러나 이벤트 소싱 스타일에 따라 어쨌든 엄격한 1 "수정 된"AR = 1 트랜잭션을 시행해야하며 AR이 '플레이어'인 경우 범위는 작게 유지됩니다. – guillaume31