SO style reputation system with CQRS & Event Sourcing?

My understanding is that aggregates themselves should not be be subscribing to events. The domain model only raises events. It's the query side or other infrastructure components (such as an emailing component) that subscribe to events.

Up vote 1 down vote favorite share g+ share fb share tw.

I am diving into my first forays with CQRS and Event Sourcing and I have a few points Id like some guidance on. I would like to implement a SO style reputation system. This seems a perfect fit for this architecture.

Keeping SO as the example. Say a question is upvoted this generates an UpvoteCommand which increases the questions total score and fires off a QuestionUpvotedEvent. It seems like the author's User aggregate should subscribe to the QuestionUpvotedEvent which could increase the reputation score.

But how/when you do this subscription is not clear to me? In Greg Youngs example the event/command handling is wired up in the global. Asax but this doesn't seem to involve any routing based on aggregate Id.

It seems as though every User aggregate would subscribe to every QuestionUpvotedEvent which doesn't seem correct, to make such a scheme work the event handler would have to exhibit behavior to identify if that user owned the question that was just upvoted. Greg Young implied this should not be in event handler code, which should merely involve state change. What am I getting wrong here?

Any guidance much appreciated. EDIT I guess what we are talking about here is inter-aggregate communication between the Question & User aggregates. One solution I can see is that the QuestionUpvotedEvent is subscribed to by a ReputationEventHandler which could then fetch the corresponding User AR and call a corresponding method on this object e.g. YourQuestionWasUpvoted.

This would in turn generated a user specific UserQuestionUpvoted event thereby preserving replay ability in the future. Is this heading in the right direction? EDIT 2 See also the discussion on google groups here.

Cqrs event-sourcing link|improve this question edited Sep 14 '11 at 22:29 asked Sep 10 '11 at 6:55madcapnmckay2,73421027 91% accept rate.

My understanding is that aggregates themselves should not be be subscribing to events. The domain model only raises events. It's the query side or other infrastructure components (such as an emailing component) that subscribe to events.

Domain Services are designed to work with use-cases/commands that involve more than one aggregate. What I would do in this situation: VoteUpQuestionCommand gets invoked. The handler for VoteUpQuestionCommand calls: IQuestionVotingService.

VoteUpQuestion(Guid questionId, Guid UserId); This then fecthes both the question & user aggregates, calling the appropriate methods on both, such as user. IncrementReputation(int amount) and question.VoteUp(). This would raise two events; UsersReputationIncreasedEvent and QuestionUpVotedEvent respectively, which would be handled by the query side.

I have seen examples where aggregates subscribe to event handlers but I think it does complicate matters. – madcapnmckay Sep 14 '11 at 22:30 I like your proposed solution it is similar to the one suggested by Tom, in that an external coordinator service performs the logic. What I initially wanted to avoid was having the value the reputation increased by to be in the event.

The only disadvantage I can see in your solution is that if I changed the value that reputation increased for a question upvoted, I couldn't easily recalculate (as SO has done in the past). Depending on the situation you might see that as a plus, but I would like the ability to recalc. Interesting that this sparked many differing solutions (see edit).

– madcapnmckay Sep 14 '11 at 22:31 I'm not sure if you'd necessarily have to put the amount the reputation has increased by in the event? The amount a vote is worth could just be stored in the query side, and you could just have a 'UsersQuestionVotedUpEvent' event that when handled, it looks up the current worth of an up vote and increments the users reputation by that amount. Changing the worth of an up vote would then just be a case of an update query.

Of course this only works if the domain itself is not concerned with the actual reputation score of a user. – David Masters Sep 15 '11 at 9:25.

My rule of thumb: if you do inter-AR communication use a saga. It keeps things within the transactional boundary and makes your links explicit => easier to handle/maintain.

The user aggregate should have a QuestionAuthored event... in that event is subscribes to the QuestionUpvotedEvent... similarly it should have a QuestionDeletedEvent and/or QuestionClosedEvent in which it does the proper handling like unsibscribing from the QuestionUpvotedEvent etc. EDIT - as per comment: I would implement the Question is an external event source and handle it via a gateway. The gateway in turn is the one responsible for handling any replay correctly so the end result stays exactly the same - except for special events like rejection events...

Say you have a RebuildFromEvents method on the aggregate. To replay you'd get all the events for the User's id and push them through this method. In your description you wouldn't end up with the same reputation value as before... – madcapnmckay Sep 10 '11 at 19:35 I would implement the question as an "external event source" and handle it via a gateway which in turn is responsible for dealing with the "replay mode"... this way the problem(s) describe won't arise – Yahia Sep 10 '11 at 22:08 Do you have any examples?

Every example I have seen the replay of the events is handled by the aggregate. Is the gateway in your scenario the ReputationEventHandler I mentioned in my edit? Because this handler ends up sending commands which generate user events, replay is not an issue.

The handler can also be globally subscribed. – madcapnmckay Sep 11 '11 at 3:38 I don't have source at hand right now but for a good explanation of what I mean with "external event source" with some examples esp. Regarding replay see martinfowler.com/eaaDev/EventSourcing.html – Yahia Sep 11 '11 at 3:40.

I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.

Related Questions