Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I'm considering a project to migrate part of our WCF-based SOA over to a service bus model (probably nServiceBus) and using some basic pub-sub to achieve Command-Query Separation.

I'm not new to SOA, or even to service bus models, but I confess that until recently my concept of "separation" was limited to run-of-the-mill database mirroring and replication. Still, I'm attracted to the idea because it seems to provide all the benefits of an eventually-consistent system while sidestepping many of the obvious drawbacks (most notably the lack of proper transactional support).

I've read a lot on the subject from Udi Dahan who is basically the guru on ESB architectures (at least in the Microsoft world), but one thing he says really puzzles me:

As we get larger entities with more fields on them, we also get more actors working with those same entities, and the higher the likelihood that something will touch some attribute of them at any given time, increasing the number of concurrency conflicts.

[...]

A core element of CQRS is rethinking the design of the user interface to enable us to capture our users’ intent such that making a customer preferred is a different unit of work for the user than indicating that the customer has moved or that they’ve gotten married. Using an Excel-like UI for data changes doesn’t capture intent, as we saw above.

-- Udi Dahan, Clarified CQRS

From the perspective described in the quotation, it's hard to argue with that logic. But it seems to go against the grain with respect to SOAs. An SOA (and really services in general) are supposed to deal with coarse-grained messages so as to minimize network chatter - among many other benefits.

I realize that network chatter is less of an issue when you've got highly-distributed systems with good message queuing and none of the baggage of RPC, but it doesn't seem wise to dismiss the issue entirely. Udi almost seems to be saying that every attribute change (i.e. field update) ought to be its own command, which is hard to imagine in the context of one user potentially updating hundreds or thousands of combined entities and attributes as it often is with a traditional web service.

One batch update in SQL Server may take a fraction of a second given a good highly-parameterized query, table-valued parameter or bulk insert to a staging table; processing all of these updates one at a time is slow, slow, slow, and OLTP database hardware is the most expensive of all to scale up/out.

Is there some way to reconcile these competing concerns? Am I thinking about it the wrong way? Does this problem have a well-known solution in the CQS/ESB world?

If not, then how does one decide what the "right level" of granularity in a Command should be? Is there some "standard" one can use as a starting point - sort of like 3NF in databases - and only deviate when careful profiling suggests a potentially significant performance benefit?

Or is this possibly one of those things that, despite several strong opinions being expressed by various experts, is really just a matter of opinion?

share|improve this question

2 Answers 2

On the topic of "every attribute change"

I think you missed the point. Mr. Udi Dahan is saying you should capture the user's intent as a command. An end-user is concerned with being able to indicate that a customer has moved. Depending on the context that command could contain a customer identification, the new address (split up into street, streetnumber, zipcode, ...), optionally a new phone number (not uncommon when you move - maybe less so with all these cellphones). That's hardly one attribute. A better question is "how do I design commands?". You design them from a behavioral perspective. Each use-case, flow, task an end-user is trying to complete, will be captured in one or more commands. What data goes with those commands comes naturally, as you start reasoning about them in more detail. The thing to watch out for is data that gets interpreted as "logic flow control" on the server side. That might be an indication that you need to split up the command. I hope you never find that standard with regard to command granularity. Good question though!

share|improve this answer
    
This definition still feels very arbitrary to me; a CSR's conceptual model may lump preferred status and martial status together the same way you lump address and postcode together. I don't mean to split hairs, it just seems to me that in order to really understand if they're different behaviours, you have to be able to predict the downstream effects, and OTOH the whole idea of ESB and CQS and pub/sub is that you aren't supposed to know or care what happens downstream. Thank you for your answer, I do appreciate it, although I can't say I feel any more enlightened so far... –  Aaronaught Apr 8 '11 at 18:51
    
@Aaronaught: The definition is arbitrary. The granularity of a Command should be whatever makes sense for your particular scenario. There's no one size fits all. There are several guidelines, such as matching commands to use cases or tasks or actions available in the UI - another is to prefer more granular commands over less granular commands (particulaly as Yves said being wary of data that is interpreted as logic control flow) - but no hard and fast rule. Is there an actual scenario where "one user potentially updating hundreds or thousands of combined entities and attributes"? –  qes Apr 8 '11 at 19:18
    
That's the whole point! Don't lump together. Divide according to behavior! Don't put data in the command that does not align with the intent of the command/end-user. And that's not about downstream systems. –  Yves Reynhout Apr 8 '11 at 19:20
    
@qes: In our systems there are several such scenarios, very real and very necessary. To state it as simply as possible, they need to modify entire sequences of data and these sequences only make sense as sequences. Of course they don't usually make these changes record by record, they apply some algorithm to the bulk of it and then fix a few exceptions. Maybe this just isn't an appropriate scenario for CQS to begin with, but that decision is just a subset of my broader question. –  Aaronaught Apr 8 '11 at 19:24
1  
@qes: Fair enough, and that's an answer in and of itself. I certainly understand the concept of a logical operation (that's how the existing services are modeled), I guess I've just been concerned that CQS seems to change a few of the rules around how you ought to define an operation. "Traditional" SOA seems to start from the coarsest possible definition and move down the abstraction ladder if necessary; my understanding of CQS so far seems to indicate the opposite, start from the most granular definition possible and abstract if it looks too much like RPC or control flow. –  Aaronaught Apr 8 '11 at 19:36

The message Udi is trying to get across is that CQRS is more than just CRUD. Why did I create this record? Why am I changing this record? Why is it being deleted/marked as deleted?

Commands should correspond to actions/use cases that the user makes with the system and express the intent of the action rather than just saying change this. Also, it may seem like it's finer grained but it could be much coarser than it first appears. For instance the upgrade to gold status might involve a change to several attributes and a number of other aggregates might even respond and change in response to the corresponding event.

CQRS is about capturing the language of the business in the Service layer so the UI doesn't have to worry about what happens when I make that gold status upgrade or the shipment has been marked as undeliverable by the carrier, or the employee has been promoted to manager of the technology group. Well technically I'm talking about Event Sourcing now but you get my drift. There are more distinct messages but they are not necessarily more fine grained than standard CUD.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.