How granular command should be?

426 views
Skip to first unread message

Veniamin Goldin

unread,
Nov 20, 2011, 9:41:23 AM11/20/11
to DDD/CQRS
Hi,

I have a silly question from a new CQRS follower. Considering an
example UC to register a new customer in CRM system.
Customer has an address, which in turn has street, country, etc.,
customer has all sorts of names, contact information etc.

If the command is CreateNewCustomer, should the constructor of such
command accept all the atomic values for each of the attribute, or:
a) I should I create a separate command, like CreateNewCustomer,
ModifyCustomerAddress, ModifyCustomerEmployee, etc, and execute this
commands consequently from the UseCase.
b) Create a DTO, which will include references to ValueObjects from
the domain, and pass it to the constructor of the CreateNewCustomer
command? I suppose this might not be good practice, because DTO is
from the query model.

Any other best practices?

Thanks.

Philip Jander

unread,
Nov 20, 2011, 10:12:11 AM11/20/11
to ddd...@googlegroups.com
Hi Veniamin,

> I have a silly question from a new CQRS follower. Considering an
> example UC to register a new customer in CRM system.
> Customer has an address, which in turn has street, country, etc.,
> customer has all sorts of names, contact information etc.
>
> If the command is CreateNewCustomer, should the constructor of such
> command accept all the atomic values for each of the attribute, or:
> a) I should I create a separate command, like CreateNewCustomer,
> ModifyCustomerAddress, ModifyCustomerEmployee, etc, and execute this
> commands consequently from the UseCase.
Short answer:
My take is that one command should equal one use case. This immediately
shifts your question to how granular use cases should be. That depends
on your project.
In a rich-UI scenario, you can probably get away with the super-size
CreateNewCustomer which is fired off by a large viewmodel.
In an ajax web app, you will more likely have fine-grained use cases,
where small edits lead to small commands. It just depends....

Long answer: maybe search this group's archive. IIRC, this question has
been discussed more than once in the not-too-distant past.

> b) Create a DTO, which will include references to ValueObjects from
> the domain, and pass it to the constructor of the CreateNewCustomer
> command? I suppose this might not be good practice, because DTO is
> from the query model.

You are right. DTOs from the query side and DTOs from the command side
(which are essentially *the commands*) never match in detail, not even
in a pure "update" scenario, which we all don't want to do anyways. The
reason is that on the query side you will always have additional data
for display purposes whereas the command side tends to be a lot of IDs
plus some entered data. Also, query side DTOs are only dumb data
containers whereas commands can very well contain validation and even
some preliminary authentication logic. Trying to combine both eventually
leads into a mess in my experience.

>
> Any other best practices?
Just a comment on vocabulary. "Value object" is a term from the domain
model. As such, a value object is first defined by its behaviour. In the
context of CQRS, by definition you cannot have a refence to a value
object in either queries or commands.
You can have a DTO that closely follows the internal state of a value
object. You can also have a part of a command that provides data
required in construction a value object within the domain. The first is
about behaviour, the latter about data (upon which the behaviour "behaves").

As always, just my 2 cts, Although I am beginning to feel quite strong
about these distinctions, so maybe I'll raise to 4 cts :)

Cheers
Phil
>

Veniamin Goldin

unread,
Nov 21, 2011, 1:50:04 PM11/21/11
to DDD/CQRS
Philip, thanks for your feedback.

Ok, since my user intent is to register a new customer, and this is
also a single task from the user perspective, hence I have created a
single command - RegisterNewCustomer.

However, in order not to have any direct references to the domain, and
since the command is DTO, the command should cary all the attributes
of the customer entity and the related value objects, eventually
repeating them. It does not seem to be very good design. Did I missed
something?

Thanks.

João Bragança

unread,
Nov 21, 2011, 2:08:03 PM11/21/11
to ddd...@googlegroups.com
It depends on how complicated your user registration process is. Are
there many screens in this process or just one? If you have many
screens (and therefore many html forms or their equivalent) then you
might want to look at 1 use case = 1 form = 1 command

Veniamin Goldin

unread,
Nov 21, 2011, 2:20:23 PM11/21/11
to DDD/CQRS
Well, actually it is a tab-based form, however, it would be enough to
mention at least one tab, which contains:
1. General information on the person, i.e. names, DoB, citizenship,
etc.
2. Employment (employee, title)
3. Education
4. Marital Status
5. Registration Address (country, city, street, building, apartment,
postal code)
6. Post Address (if differs from 5)

Other tabs contains contact details, identification documents etc.

What is the "best practice" here?

Thanks.

Philip Jander

unread,
Nov 21, 2011, 3:29:26 PM11/21/11
to ddd...@googlegroups.com
Hi again,

> However, in order not to have any direct references to the domain, and
> since the command is DTO, the command should cary all the attributes
> of the customer entity and the related value objects, eventually
> repeating them. It does not seem to be very good design. Did I missed
> something?

No you didn't. I have come to accept this as a necessary side-effect of
cqrs+task-based ui. You will end up with partially similar - although
not identical - data structures in several places:
Viewmodels, commands, domain constituents, events, read models and query
results.

That per se is not bad design, rather the result of explicitly
decoupling the different models involved. The code you will need to
write connecting them is the explicit mapping between the different
models. CQRS doesn't come for free :)
Some people on this group endeavour to minimize this apparent overhead
by code generation off a meta model, but if you are just starting out, I
would recommend against that.
Tools like automapper can possibly reduce the required coding while
keeping flexibility and expressiveness.

Some of these data structures may even be eliminated by reuse:
- For entry forms, instead of repeating command parameters, I often use
live command objects as a property of an (input) viewmodel also
providing validation and basic authentication. This is actually a great
thing as my command DLLs are available on client and server side,
providing identical validation and authentication information.
- Query result and viewmodel: I design my query results such that they
can be directly bound to a view, so a viewmodel takes query result
objects as some properties. There is really no point in duplication here.
- Readmodel and query results may well be identical, too. But very often
I am doing some light joining with other BCs in the query, so my query
results tend to be richer than the individual readmodels. That's a
matter of taste, I suppose.

However, I maintain a strong separation between command parameters,
domain constituents (<- those are private implementation details of the
domain model anyways), event properties and readmodel data. In my
experience, coupling them leads to data-centric domains, which I try to
avoid.

BUT: if you find yourself having 100% correspondence on command
parameters -> domain objects -> readmodel, to me this is a very strong
indication that that particular business context shouldn't be using
cqrs+ddd in the first place. Check non-functional requirements to see if
you cannot get away with something simpler. Have a look at Udi Dahan's
video from DDDx 2011 at skillsmatter for some inspiration in this regard.

Regarding the tabbed wizard data entry, I see no problem in collection
data upfront and putting it in a single command. There was some
contribution by Udi Dahan some time ago towards that question, but I
confess I don't recall his bottom line right now. Maybe you can find it
in the archives.

Cheers
Phil

Nuno Lopes

unread,
Nov 21, 2011, 5:07:12 PM11/21/11
to ddd...@googlegroups.com
I think you are one step ahead.

Instead of thinking on commands (man I hate that part of CQRS), I would first think of an Entity: CustomerRegistration.

And refactor as you get more information about correlated use cases.

Cheers,

Nuno

Nuno Lopes

unread,
Nov 21, 2011, 5:26:45 PM11/21/11
to ddd...@googlegroups.com
I think you are one step ahead.

Instead of thinking on commands (man I hate that part of CQRS), I would first think of an Entity: CustomerRegistration.

And refactor as you get more information about correlated use cases.

Cheers,

Nuno

On Nov 21, 2011, at 8:29 PM, Philip Jander wrote:

andho

unread,
Nov 22, 2011, 12:49:23 PM11/22/11
to ddd...@googlegroups.com
Wouldn't CustomerRegistration be a saga then?

Joseph Daigle

unread,
Nov 22, 2011, 1:30:45 PM11/22/11
to ddd...@googlegroups.com
As a user, I'm personally not a fan of giant forms with a single "submit" button at the end. I would rather break it down into discrete steps, maybe with a review and confirm screen at the end.

Not knowing much about your domain, maybe start with the minimum pieces of information needed to "identify" a new record. For instance, Name and DOB.

So you start with one command: StartRegistration(regId, name, dob);

At this point "Registration" becomes sort of a long-running workflow, referenced by a regId. All of your other stuff can be commands which correlate with this regId.

- RegisterEmployment()
- RegisterEducation()
- RegisterMaritalStatus()
- etc. etc.

The "Registration" workflow itself can maintain state. You can keep track of how much information has been collected, what is still needed, etc.

At some point you could even let the user review all of the information collected during registration, and make changes if needed. Then you could publish "Registration Completed", this could be a message to other parts of the system to signal other state changes.


João Bragança

unread,
Nov 22, 2011, 5:10:41 PM11/22/11
to ddd...@googlegroups.com
+1. You can treat registration as its own aggregate (not really a saga
since it isn't orchestrating anything) if it sufficiently complicated.

Veniamin Goldin

unread,
Nov 23, 2011, 11:59:30 AM11/23/11
to DDD/CQRS
Thanks. That's perfectly makes sense. I will first try to understand
the intent of the data once again, then de-compose the form into
smaller forms and commands upon CustomerRegistration entity.

I have seen Rinat's approach on binding several commands, related to
the same entity, into one CommandMessage. I think this should work
here as well?

Regards,
Veniamin

Rinat Abdullin

unread,
Nov 23, 2011, 12:16:51 PM11/23/11
to ddd...@googlegroups.com
Batching commands in a single message is just a hack that allows you to avoid creating separate composite commands.
Of course, your message dispatcher has to support transactional processing (either in form of ES or classical transactions) in order for this to work as expected (ie. if one of the commands fails - the entire batch fails)

Best,
Rinat

√iktor Ҡlang

unread,
Nov 23, 2011, 12:26:39 PM11/23/11
to ddd...@googlegroups.com
On Wed, Nov 23, 2011 at 6:16 PM, Rinat Abdullin <rinat.a...@gmail.com> wrote:
Batching commands in a single message is just a hack that allows you to avoid creating separate composite commands.
Of course, your message dispatcher has to support transactional processing (either in form of ES or classical transactions) in order for this to work as expected (ie. if one of the commands fails - the entire batch fails)

Can of worms
 



--
Viktor Klang

Akka Tech Lead
Typesafe - Enterprise-Grade Scala from the Experts

Twitter: @viktorklang

Rinat Abdullin

unread,
Nov 23, 2011, 12:28:39 PM11/23/11
to ddd...@googlegroups.com
?

√iktor Ҡlang

unread,
Nov 23, 2011, 12:37:27 PM11/23/11
to ddd...@googlegroups.com
On Wed, Nov 23, 2011 at 6:28 PM, Rinat Abdullin <rinat.a...@gmail.com> wrote:
?



On Wed, Nov 23, 2011 at 6:16 PM, Rinat Abdullin <rinat.a...@gmail.com> wrote:
Batching commands in a single message is just a hack that allows you to avoid creating separate composite commands.
Of course, your message dispatcher has to support transactional processing (either in form of ES or classical transactions) in order for this to work as expected (ie. if one of the commands fails - the entire batch fails)

Can of worms

composition of arbitrary commands paired with transactionality in a concurrent/parallel environment is a can of worms

 

Rinat Abdullin

unread,
Nov 23, 2011, 12:42:30 PM11/23/11
to ddd...@googlegroups.com
I've been doing it in volatile cloud environments (which can be considered as parallel and concurrent, when you have multiple multithreaded VMs that come up and down according to the load). No problems with command batching and logical ES transactions whatsoever.

Am I doing something wrong? :)


2011/11/23 √iktor Ҡlang <viktor...@gmail.com>

√iktor Ҡlang

unread,
Nov 23, 2011, 12:48:06 PM11/23/11
to ddd...@googlegroups.com
On Wed, Nov 23, 2011 at 6:42 PM, Rinat Abdullin <rinat.a...@gmail.com> wrote:
I've been doing it in volatile cloud environments (which can be considered as parallel and concurrent, when you have multiple multithreaded VMs that come up and down according to the load). No problems with command batching and logical ES transactions whatsoever.

Am I doing something wrong? :)

Well, that depends on what you've sacrificed to get there ;-)
 

Rinat Abdullin

unread,
Nov 23, 2011, 12:50:10 PM11/23/11
to ddd...@googlegroups.com
chicken blood, vow to avoid SQL whenever possible, usual stuff))

Greg Young

unread,
Nov 24, 2011, 2:20:18 AM11/24/11
to ddd...@googlegroups.com
It can be depending on the transactional constraints of the write
side. There are however some times that it is unavoidable
(occasionally connected clients is an example). I however prefer to
say that the batch must only live within a transactional boundary
(thus negating many of the very bad constraints that get hoisted)

2011/11/23 √iktor Ҡlang <viktor...@gmail.com>:

--
Le doute n'est pas une condition agréable, mais la certitude est absurde.

Rinat Abdullin

unread,
Nov 24, 2011, 2:40:50 AM11/24/11
to ddd...@googlegroups.com
Yeah, forgot to mention that rule: only commands to the same entity are allowed to be batched. No crossing of the consistency boundaries with the transactional logic.

Rinat

√iktor Ҡlang

unread,
Nov 24, 2011, 4:11:24 AM11/24/11
to ddd...@googlegroups.com
On Thu, Nov 24, 2011 at 8:40 AM, Rinat Abdullin <rinat.a...@gmail.com> wrote:
Yeah, forgot to mention that rule: only commands to the same entity are allowed to be batched. No crossing of the consistency boundaries with the transactional logic.

Busted ;-) j/k
 

Rinat Abdullin

unread,
Nov 24, 2011, 4:28:20 AM11/24/11
to ddd...@googlegroups.com
Duh. I've been burned upon this so long ago, that I tend forget about mentioning this small detail. Sorry about that part

Rinat


2011/11/24 √iktor Ҡlang <viktor...@gmail.com>

Greg Young

unread,
Nov 24, 2011, 4:36:03 AM11/24/11
to ddd...@googlegroups.com
There are some systems where you can't avoid it. But if you can limit
it takes away the nasty side of constraints (like not being able to
partition).

On Thu, Nov 24, 2011 at 4:28 AM, Rinat Abdullin

Rinat Abdullin

unread,
Nov 24, 2011, 4:38:47 AM11/24/11
to ddd...@googlegroups.com
Example of unavoidable cases being?

Greg Young

unread,
Nov 24, 2011, 4:39:50 AM11/24/11
to ddd...@googlegroups.com
Occasionally connected clients

On Thu, Nov 24, 2011 at 4:38 AM, Rinat Abdullin

Rinat Abdullin

unread,
Nov 24, 2011, 4:42:33 AM11/24/11
to ddd...@googlegroups.com
Ah. But in this case we are talking about different approach applicable:
Deal with the consequences (as merging events) as opposed to try to enforce them (as in tx scopes)

Greg Young

unread,
Nov 24, 2011, 4:44:03 AM11/24/11
to ddd...@googlegroups.com
You can.

On Thu, Nov 24, 2011 at 4:42 AM, Rinat Abdullin

Daniel Pittman

unread,
Nov 24, 2011, 1:45:41 PM11/24/11
to ddd...@googlegroups.com
Forgive the stupid question, but wouldn't it make more sense to send a
"batch" of commands at the transport layer, but process them as
independent commands that just happen to come in one after the other?

Daniel

--
♲ Made with 100 percent post-consumer electrons

√iktor Ҡlang

unread,
Nov 24, 2011, 4:23:38 PM11/24/11
to ddd...@googlegroups.com
On Thu, Nov 24, 2011 at 7:45 PM, Daniel Pittman <dan...@rimspace.net> wrote:
Forgive the stupid question, but wouldn't it make more sense to send a
"batch" of commands at the transport layer,

What problem are you trying to solve with this solution?
 

Rinat Abdullin

unread,
Nov 25, 2011, 12:48:04 AM11/25/11
to ddd...@googlegroups.com
Daniel,

There are certain cases, when you might want to have second command executed only if the first one has succeeded.

Rinat

Daniel Pittman

unread,
Nov 25, 2011, 1:48:57 PM11/25/11
to ddd...@googlegroups.com
2011/11/24 √iktor Ҡlang <viktor...@gmail.com>:

> On Thu, Nov 24, 2011 at 7:45 PM, Daniel Pittman <dan...@rimspace.net> wrote:
>>
>> Forgive the stupid question, but wouldn't it make more sense to send a
>> "batch" of commands at the transport layer,
>
> What problem are you trying to solve with this solution?

Short term, my own understanding of why the experts make some of their
choices. It seems like treating batching as a transport layer
property would be a better model for a smart, disconnected client to
me, but Greg gives it as an example of where you can't avoid batching
at (what I read as) a higher level.

Longer term, we have clients in our system that currently receive a
batch of "commands", process them, generate a batch of results, and
ship that back as a report. We have a bunch of pressures to make them
less batch focused.

It seems like batching those responses at the "transport" level would
decouple more of our system from the details of the client, and the
fact that part of a service was operating in "disconnected" mode
compared to "connected" mode. (eg: explode the batch out, and now it
looks like a connected client to most of the system.)

Does that make sense?

Daniel

stacy

unread,
Nov 25, 2011, 11:26:26 PM11/25/11
to ddd...@googlegroups.com
That's exactly how I do it. If I need some "specific orchestration" I use a saga. Keeps everything clean and simple.

Nuno Lopes

unread,
Nov 28, 2011, 7:24:30 AM11/28/11
to ddd...@googlegroups.com
Hi,

I have seen Rinat's approach on binding several commands, related to
the same entity, into one CommandMessage. I think this should work
here as well?

Humm. No.

The CustomerRegistration i advised is a long running business process where customer information is captured/collected.

class CustomerAccountRegistration {
CollectCustomerAddress(...) -> CustomerAddressCollectedForRegistration()
CollectCustomerName(....); -> CustomerNameCollectedForRegistration()

CompleteRegistration() -> RegistrationCompleted(......);
}

Something will handle the RegistrationCompleted and creating the customer account and other "stuff" as required by the system

The idea is that you have ONE and only ONE Domain Object handling Commands / Use case, while several Aggregates can handle Domain Events.

The RegistrationCompleted Event/Fact can encapsulate all the information of course. If you have a lot of data in the Fact to the point that hurts throughput, you can have the Handle query a CustomerRegistration view to get the relevant data has necessary by Aggregates "subscribing" to the RegistrationComplete event/fact.

No need for batch processing of several commands in this case.

Cheers,

Nuno

Nuno Lopes

unread,
Nov 28, 2011, 8:19:24 AM11/28/11
to ddd...@googlegroups.com
Correction. I said "long running business" when I actually meant "long running business operation".

Also now that you don't necessarily need to use ES.

I've mentioned this several times. This similar to the ShoppingCart/PurchaseRegistration concept in relationship to a PurchaseOrder, PaymentOrder, ShippingOrder, other correlated long running business operations.

Each of these Aggregates can run on distinct Bounding Contexts but not necessarily.

Cheers,

Nuno

Sent from my iPhone

Reply all
Reply to author
Forward
0 new messages