문제

Can you use the CQRS (Command-Query Responsibility Segregation) architectural pattern to build a site like StackOverflow? I'm relatively new to CQRS and DDD (Domain Driven Design) and am exploring the pattern and trying to model sites that I'm familiar with to the pattern. While I can see CQRS being useful for many aspects for a site like StackOverflow, there are a few areas that I'm not sure are possible (or, at least, I can't figure out immediately). Specifically:

  • Asking questions When I create a question, I see it immediately and can edit it. In CQRS, I issue a command like 'AskQuestion' and an event is created called 'QuestionAsked'. Eventually, the question gets pushed to the denormalized data store. But SO's experience is immediate. Is this possible with CQRS?
  • Voting My votes are reflected immediately. In CQRS, I would imagine these commands/events eventually moving through the event bus to the read store. But SO gives me the information immediately.

My concerns are really around the concept of immediate feedback that SO provides. Can CQRS provide this? If so, how would this be done? Are there good examples out there that illustrate how to handle this?

If it helps, my environment is VS2010/C#/SQL2008R2, but I'm open to other options like SQLite, etc. I'm also looking at NCQRS and LOKAD's frameworks, along with Mark Nijhof's sample and am planning on downloading Greg Young's sample. I didn't find much else out there for CQRS samples.

Thanks!

도움이 되었습니까?

해결책

What you're actually talking about is 'eventual consistency' which is frequently talked about at the same time as CQRS, but you can use either technique independently.

The simplest thing to do is to update the model which the UI is using immediately and use this to show the question back to the user for further manipulation. The various bits of work to be done so that the other users can see the update can then proceed without blocking the UI. For this to work you need to validate your command so that is almost certain to succeed before sending it off (if the command fails during execution then you'll need to handle the situation, e.g. incorporate some sort of call back to the UI model).

It's also worth bearing in mind that usually the 'eventuallness' of this sort of thing is so quick that everything will have appeared immediately anyway, even to other users.

다른 팁

Let's look at the two questions...

Asking questions When I create a question, I see it immediately and can edit it. In CQRS, I issue a command like 'AskQuestion' and an event is created called 'QuestionAsked'. Eventually, the question gets pushed to the denormalized data store. But SO's experience is immediate. Is this possible with CQRS?

This can be easily achieved. Does every user need to see the question immediately or just the person asking it? If it takes 1-2 seconds for it to appear to everyone would it make a difference? Most often in eventually consistent systems there is a difference between the user sending a request vs every other user.

Voting My votes are reflected immediately. In CQRS, I would imagine these commands/events eventually moving through the event bus to the read store. But SO gives me the information immediately.

Does SO give it immediately? Let's try another example, Facebook. When you click like on something does this immediately show up in your likes? UI tricks like putting a thumbs up make you feel like it does. Another example, amazon. When you click add to cart does it immediately go into your cart? Visual representations like "added to cart" or a "thumbs up" make you as a user feel like its been done.

There are many tricks like these that can make an eventually consistent system feel like a fully consistent system.

As a side note many people think these kinds of thing are done for scalability (which is sometimes the case). More often they are being done for reliability. The question becomes happens if XYZ is down. Do you want weird randomized local failures or do you want to risk a wide spread outage. One of the best examples to see here is checking out on amazon for a kindle purchase, its weird that they can process your credit card in like 100ms while everyone else takes 3-5 seconds :) What happens if their credit card processing system is down?

When you ask a question, you can "fake" the data in the UI. It will look like it was updated immediately to the user (you), but it will take some time before the other users will see your question. You need to do the same thing to handle voting.

If you need immediate feedback, you might consider other solutions. But, there are some tricks you can do to give immediate feedback in a CQRS solution. If you, for example, need to validate that a username is uniqe, you can query the read database(s) to find out if the username exists. If it doesn't, you can use it. But, if a other user have choosen the same username in the meantime, you will get a conflict on the command side. You need to handle this in your domain model, and, for example, give the user a generated username and send it to him by e-mail. He can later change it to something else.

By fake or trick, you might think of the event as a "pending event", something that is likely to succeed in the commit/publish phase, but could fail. The more validation you perform clientside, prior to initial submit for commit, the more likely it will succeed. So if you intend to rely on a pending commit, plan for a thicker client in terms of validation and business rule exposure.

One could then allow the user to continue to use the data (for further modification) by marking or tagging the data within the UI as relying on "pending commit". It would be a meta attribute of the object or attribute. Of course adding and using that meta attribute will increase the complexity, but depending on application might be a necessary use-case.

Client-side command queues/histories might be one way to help handle situations where subsequent events relied on an ultimately failed pending commit. In other words, anything that relies on a pending commit could be part of a history that could be rolled up, saved while corrections are made to the failed pending commit, unrolled and reapplied to the changed and resubmitted pending event again, and once notification that the pending event was successful in commit, all subsequent client side history would start to unwind, submitted the next item in the queue, marking it as the now pending event.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top