Why do commands include the entity id when creating entities? #17

Closed
ThomasJaeger opened this Issue Jan 3, 2016 · 26 comments

Comments

Projects
None yet
7 participants
@ThomasJaeger

I'm curious and I think I know the answer to my own question but I wanted to confirm this. In the example command handler, the "CreateInventoryItem" command includes the InventoryItemId which is used by the aggregate as its identity:

https://github.com/gregoryyoung/m-r/blob/master/SimpleCQRS/CommandHandlers.cs#L16

The reason of doing this, is this because that all commands should pass data that is required to create an entity? Before, I have used immutable value objects for entity ids. I guess my question is: "Who creates an aggregate's Id when using CQRS and DDD?" Before, my entities were generating their own Ids (as value objects).

I can see the advantage of passing an id with a command when that command's execution will create a domain entity because I could replay commands if I would persist these commands and assuming all commands pass required information with them.

What are you thoughts?

@ThomasJaeger

This comment has been minimized.

Show comment
Hide comment
@ThomasJaeger

ThomasJaeger Jan 9, 2016

Since nobody has replied and assuming people have seen my question, I assume my assumption was correct? Well, I was thinking about this for some time now and checked with how Vaughn Vernon is doing this. He is creating the aggregate ids from the repositories but called from by the application services. I like this better because the application services have and should have control and oversight over the access to the domain model. Creating aggregate ids should be within the control of the domain model.

So, I think I will stay with creating the entities ids from within the domain model. Everything else can come into the application services via commands in CQRS. Then, the domain model has full control and can make sure it generates "good" ids.

So, if you do want to replay your commands that is to say that you have persisted your commands, you can replay them, its just with different ids every time. I think this is acceptable.

Since nobody has replied and assuming people have seen my question, I assume my assumption was correct? Well, I was thinking about this for some time now and checked with how Vaughn Vernon is doing this. He is creating the aggregate ids from the repositories but called from by the application services. I like this better because the application services have and should have control and oversight over the access to the domain model. Creating aggregate ids should be within the control of the domain model.

So, I think I will stay with creating the entities ids from within the domain model. Everything else can come into the application services via commands in CQRS. Then, the domain model has full control and can make sure it generates "good" ids.

So, if you do want to replay your commands that is to say that you have persisted your commands, you can replay them, its just with different ids every time. I think this is acceptable.

@gregoryyoung

This comment has been minimized.

Show comment
Hide comment
@gregoryyoung

gregoryyoung Jan 9, 2016

Owner

No.

There are a multitude of reasons you would prefer to create ids on a client
if possible. To start with what about when you want to send 3 commands?
Also you will what start returning ids from commands? What if a command
creates 3 entities?

On Sat, Jan 9, 2016 at 4:43 PM, Thomas Jaeger notifications@github.com
wrote:

Since nobody has replied and assuming people have seen my question, I
assume my assumption was correct? Well, I was thinking about this for some
time now and checked with how Vaughn Vernon is doing this. He is creating
the aggregate ids from the repositories but called from by the application
services. I like this better because the application services have and
should have control and oversight over the access to the domain model.
Creating aggregate ids should be within the control of the domain model.

So, I think I will stay with creating the entities ids from within the
domain model. Everything else can come into the application services via
commands in CQRS. Then, the domain model has full control and can make sure
it generates "good" ids.

So, if you do want to replay your commands that is to say that you have
persisted your commands, you can reply them, its just with different ids
every time. I think this is acceptable.


Reply to this email directly or view it on GitHub
#17 (comment).

Studying for the Turing test

Owner

gregoryyoung commented Jan 9, 2016

No.

There are a multitude of reasons you would prefer to create ids on a client
if possible. To start with what about when you want to send 3 commands?
Also you will what start returning ids from commands? What if a command
creates 3 entities?

On Sat, Jan 9, 2016 at 4:43 PM, Thomas Jaeger notifications@github.com
wrote:

Since nobody has replied and assuming people have seen my question, I
assume my assumption was correct? Well, I was thinking about this for some
time now and checked with how Vaughn Vernon is doing this. He is creating
the aggregate ids from the repositories but called from by the application
services. I like this better because the application services have and
should have control and oversight over the access to the domain model.
Creating aggregate ids should be within the control of the domain model.

So, I think I will stay with creating the entities ids from within the
domain model. Everything else can come into the application services via
commands in CQRS. Then, the domain model has full control and can make sure
it generates "good" ids.

So, if you do want to replay your commands that is to say that you have
persisted your commands, you can reply them, its just with different ids
every time. I think this is acceptable.


Reply to this email directly or view it on GitHub
#17 (comment).

Studying for the Turing test

@ThomasJaeger

This comment has been minimized.

Show comment
Hide comment
@ThomasJaeger

ThomasJaeger Jan 9, 2016

Interesting questions. I can see the advantage of a client sending 3 commands with the same id for each command, say in a batch. But, say, the domain model needs to create 3 entities. The fact that the domain needed to do this, would that not be a domain knowledge that is not necessarily "leaked" outside the domain to an external command? In other words, why would a command have knowledge of the creation of internal domain entities? Would not the client be aware of possibly intimate internals of the domain model?

Interesting questions. I can see the advantage of a client sending 3 commands with the same id for each command, say in a batch. But, say, the domain model needs to create 3 entities. The fact that the domain needed to do this, would that not be a domain knowledge that is not necessarily "leaked" outside the domain to an external command? In other words, why would a command have knowledge of the creation of internal domain entities? Would not the client be aware of possibly intimate internals of the domain model?

@gregoryyoung

This comment has been minimized.

Show comment
Hide comment
@gregoryyoung

gregoryyoung Jan 9, 2016

Owner

You misunderstand, how will the domain get those ids back to the client?

On Sat, Jan 9, 2016 at 5:10 PM, Thomas Jaeger notifications@github.com
wrote:

Interesting questions. I can see the advantage of a client sending 3
commands with the same id for each command, say in a batch. But, say, the
domain model needs to create 3 entities. The fact that the domain needed to
do this, would that not be a domain knowledge that is not necessarily
"leaked" outside the domain to an external command? In other words, why
would a command have knowledge of the creation of internal domain entities?
Would not the client be aware of possibly intimate internals of the domain
model?


Reply to this email directly or view it on GitHub
#17 (comment).

Studying for the Turing test

Owner

gregoryyoung commented Jan 9, 2016

You misunderstand, how will the domain get those ids back to the client?

On Sat, Jan 9, 2016 at 5:10 PM, Thomas Jaeger notifications@github.com
wrote:

Interesting questions. I can see the advantage of a client sending 3
commands with the same id for each command, say in a batch. But, say, the
domain model needs to create 3 entities. The fact that the domain needed to
do this, would that not be a domain knowledge that is not necessarily
"leaked" outside the domain to an external command? In other words, why
would a command have knowledge of the creation of internal domain entities?
Would not the client be aware of possibly intimate internals of the domain
model?


Reply to this email directly or view it on GitHub
#17 (comment).

Studying for the Turing test

@ThomasJaeger

This comment has been minimized.

Show comment
Hide comment
@ThomasJaeger

ThomasJaeger Jan 9, 2016

I would assume those ids come back from the read model, would they not? Ohhh, now that I think about it, even the creation of ids is in fact a mutating behavior and therefore should be captured in an event and with that, it should come from a command. Is that correct?

I would assume those ids come back from the read model, would they not? Ohhh, now that I think about it, even the creation of ids is in fact a mutating behavior and therefore should be captured in an event and with that, it should come from a command. Is that correct?

@gregoryyoung

This comment has been minimized.

Show comment
Hide comment
@gregoryyoung

gregoryyoung Jan 9, 2016

Owner

How would I "get it from a read model".

My UI is creating an account then the next step is managing some details.
How does the UI go from one step to the next without knowing the account id?

On Sat, Jan 9, 2016 at 5:38 PM, Thomas Jaeger notifications@github.com
wrote:

I would assume those ids come back from the read model, would they not?
Ohhh, now that I think about it, even the creation of ids is in fact a
mutating behavior and therefore should be captured in an event and with
that, it should come from a command. Is that correct?


Reply to this email directly or view it on GitHub
#17 (comment).

Studying for the Turing test

Owner

gregoryyoung commented Jan 9, 2016

How would I "get it from a read model".

My UI is creating an account then the next step is managing some details.
How does the UI go from one step to the next without knowing the account id?

On Sat, Jan 9, 2016 at 5:38 PM, Thomas Jaeger notifications@github.com
wrote:

I would assume those ids come back from the read model, would they not?
Ohhh, now that I think about it, even the creation of ids is in fact a
mutating behavior and therefore should be captured in an event and with
that, it should come from a command. Is that correct?


Reply to this email directly or view it on GitHub
#17 (comment).

Studying for the Turing test

@Narvalex

This comment has been minimized.

Show comment
Hide comment
@Narvalex

Narvalex Jan 9, 2016

And a Guid is never a bad Id. Is unique in the world. Is, and should be the id for the aggregate. Why wrap it with a value object? No reason that I know. You can have custom keys for the aggregate ( a string perhaps) but that is related to your domain, but in the end, the real Id of an entity is a Guid, and you can safely create it fro. the UI because it does not tell you anything about the internals of your system. I remember read that Vaughn Vernon does like reactive systems but WITHOUT event sourcing. And this repo is more about event sourcing than CQRS. CQRS is only there to simplify the work of querying event sourced systems.

Narvalex commented Jan 9, 2016

And a Guid is never a bad Id. Is unique in the world. Is, and should be the id for the aggregate. Why wrap it with a value object? No reason that I know. You can have custom keys for the aggregate ( a string perhaps) but that is related to your domain, but in the end, the real Id of an entity is a Guid, and you can safely create it fro. the UI because it does not tell you anything about the internals of your system. I remember read that Vaughn Vernon does like reactive systems but WITHOUT event sourcing. And this repo is more about event sourcing than CQRS. CQRS is only there to simplify the work of querying event sourced systems.

@ThomasJaeger

This comment has been minimized.

Show comment
Hide comment
@ThomasJaeger

ThomasJaeger Jan 9, 2016

@gregoryyoung
Good point about creating an account and going into a detail account section of the same account. The client still has the created ID of that account. You have convinced me now. :-) Thank you very much for replying to my questions.

@Narvalex
I love Guid based ids and have done so for many years. Before I did CQRS and event sourcing, ids were generated by the domain model and all ids were Guids but expressed as value objects. One reason to use immutable value objects for ids it is that is explicit on your code when you look at it instead of "just" being a string, for example. Another is that the the actual type of id you are creating is encapsulated. It could also be a composite but you would never know since it is an explicit value object. Many reasons and I'm sure I missed a few more. There is no harm in using value objects for ids but more benefits that I can think of.

@gregoryyoung
Good point about creating an account and going into a detail account section of the same account. The client still has the created ID of that account. You have convinced me now. :-) Thank you very much for replying to my questions.

@Narvalex
I love Guid based ids and have done so for many years. Before I did CQRS and event sourcing, ids were generated by the domain model and all ids were Guids but expressed as value objects. One reason to use immutable value objects for ids it is that is explicit on your code when you look at it instead of "just" being a string, for example. Another is that the the actual type of id you are creating is encapsulated. It could also be a composite but you would never know since it is an explicit value object. Many reasons and I'm sure I missed a few more. There is no harm in using value objects for ids but more benefits that I can think of.

@gregoryyoung

This comment has been minimized.

Show comment
Hide comment
@gregoryyoung

gregoryyoung Jan 9, 2016

Owner

"One reason to use immutable value objects for ids is that is explicit on
your code when you look at it instead of "just" being a string, for
example. Another is that the the actual type of id you are creating is
encapsulated."

I think he meant why not just use Guid/Uuid type

On Sat, Jan 9, 2016 at 8:05 PM, Thomas Jaeger notifications@github.com
wrote:

@gregoryyoung https://github.com/gregoryyoung
Good point about creating an account and going into a detail account
section of the same account. The client still has the created ID of that
account. You have convinced me now. :-) Thank you very much for replying to
my questions.

@Narvalex https://github.com/narvalex
I love Guid based ids and have done so for many years. Before I did CQRS
and event sourcing, ids were generated by the domain model and all ids were
Guids but expressed as value objects. One reason to use immutable value
objects for ids is that is explicit on your code when you look at it
instead of "just" being a string, for example. Another is that the the
actual type of id you are creating is encapsulated. It could also be a
composite but you would never know since it is an explicit value object.
Many reasons and I'm sure I missed a few more. There is no harm in using
value objects for ids but more benefits that I can think of.


Reply to this email directly or view it on GitHub
#17 (comment).

Studying for the Turing test

Owner

gregoryyoung commented Jan 9, 2016

"One reason to use immutable value objects for ids is that is explicit on
your code when you look at it instead of "just" being a string, for
example. Another is that the the actual type of id you are creating is
encapsulated."

I think he meant why not just use Guid/Uuid type

On Sat, Jan 9, 2016 at 8:05 PM, Thomas Jaeger notifications@github.com
wrote:

@gregoryyoung https://github.com/gregoryyoung
Good point about creating an account and going into a detail account
section of the same account. The client still has the created ID of that
account. You have convinced me now. :-) Thank you very much for replying to
my questions.

@Narvalex https://github.com/narvalex
I love Guid based ids and have done so for many years. Before I did CQRS
and event sourcing, ids were generated by the domain model and all ids were
Guids but expressed as value objects. One reason to use immutable value
objects for ids is that is explicit on your code when you look at it
instead of "just" being a string, for example. Another is that the the
actual type of id you are creating is encapsulated. It could also be a
composite but you would never know since it is an explicit value object.
Many reasons and I'm sure I missed a few more. There is no harm in using
value objects for ids but more benefits that I can think of.


Reply to this email directly or view it on GitHub
#17 (comment).

Studying for the Turing test

@michaelajr

This comment has been minimized.

Show comment
Hide comment
@michaelajr

michaelajr Apr 1, 2018

Having the client generate the ID feels wrong. The format of an Entity ID is domain logic. Is the ID a UUID? Is it an int? Is it a combo of tenant ID and a UUID? It seems this logic needs to stay in the domain. And that is where Vaughn Vernon puts it in his examples. Getting the ID back is certainly an issue. I think I'm going to play around with DomainEvents and have my client (in this case a REST adaptor) subscribe to the "created" event. Maybe there's a way to get the entity ID that way?

Having the client generate the ID feels wrong. The format of an Entity ID is domain logic. Is the ID a UUID? Is it an int? Is it a combo of tenant ID and a UUID? It seems this logic needs to stay in the domain. And that is where Vaughn Vernon puts it in his examples. Getting the ID back is certainly an issue. I think I'm going to play around with DomainEvents and have my client (in this case a REST adaptor) subscribe to the "created" event. Maybe there's a way to get the entity ID that way?

@gregoryyoung

This comment has been minimized.

Show comment
Hide comment
@gregoryyoung

gregoryyoung Apr 1, 2018

Owner

There are multiple viewpoints on this. EventStore supports two of the major ones and a hybrid of them.

#1 if the server handles the ID generation how does it also handle idempotency? You can't really handle both at the same time no? More on this below.
#2 not all clients are capable of generating an id and some (looking at you javascript and uuids...) require rather complex and buggy logic. In this case you are redirected to a now idempotent uri when you post that includes the id.

ES offers both models as an example. You either give us an id if you can or not if you can't. If you can't we will redirect you to an idempotent uri containing the event id of your new event as part of your post.

Owner

gregoryyoung commented Apr 1, 2018

There are multiple viewpoints on this. EventStore supports two of the major ones and a hybrid of them.

#1 if the server handles the ID generation how does it also handle idempotency? You can't really handle both at the same time no? More on this below.
#2 not all clients are capable of generating an id and some (looking at you javascript and uuids...) require rather complex and buggy logic. In this case you are redirected to a now idempotent uri when you post that includes the id.

ES offers both models as an example. You either give us an id if you can or not if you can't. If you can't we will redirect you to an idempotent uri containing the event id of your new event as part of your post.

@gregoryyoung

This comment has been minimized.

Show comment
Hide comment
Owner

gregoryyoung commented Apr 1, 2018

Check out here for more info https://eventstore.org/docs/http-api/writing-to-a-stream/

@ThomasJaeger

This comment has been minimized.

Show comment
Hide comment
@ThomasJaeger

ThomasJaeger Apr 1, 2018

@michaelajr Generating entity IDs sure is the responsibility of the domain. I still think that when a client sends this id via the command, is the best way about this. Remember, a client sends a "command" to the domain. The domain can deny this command altogether for whatever the reasons may be. For example, if a client sends "CreateAccount" command and this command contains an AccountId as a Guid, the domain can look at it and say: "hmm, I will accept this suggested ID and it looks like it is unique".

My point is that the client only sends "suggestions or requests" to the domain. There is nothing stopping the domain to use this ID for another purpose or as part of a a bigger ID for that entity.

Also, how would I be able to "re-play" the commands if the id would be 100% generated by the domain? Would it matter?

ThomasJaeger commented Apr 1, 2018

@michaelajr Generating entity IDs sure is the responsibility of the domain. I still think that when a client sends this id via the command, is the best way about this. Remember, a client sends a "command" to the domain. The domain can deny this command altogether for whatever the reasons may be. For example, if a client sends "CreateAccount" command and this command contains an AccountId as a Guid, the domain can look at it and say: "hmm, I will accept this suggested ID and it looks like it is unique".

My point is that the client only sends "suggestions or requests" to the domain. There is nothing stopping the domain to use this ID for another purpose or as part of a a bigger ID for that entity.

Also, how would I be able to "re-play" the commands if the id would be 100% generated by the domain? Would it matter?

@michaelajr

This comment has been minimized.

Show comment
Hide comment
@michaelajr

michaelajr Apr 1, 2018

@ThomasJaeger Makes sense. But then the question still remains. If the domain generates IDs, how do we get that ID back to the client if the application layer always returns void on all commands? I feel like this is a great use case for Domain Events. Events are raised on all state changes. Since the application layer provides a mechanism for port adaptors to subscribe to events, maybe there's a way to provide an "entity created" subscriber? I'm not doing Event Sourcing. Just have a basic hexagonal architecture using port adaptors and trying to figure out best practices. Thanks for the responses @gregoryyoung @ThomasJaeger.

@ThomasJaeger Makes sense. But then the question still remains. If the domain generates IDs, how do we get that ID back to the client if the application layer always returns void on all commands? I feel like this is a great use case for Domain Events. Events are raised on all state changes. Since the application layer provides a mechanism for port adaptors to subscribe to events, maybe there's a way to provide an "entity created" subscriber? I'm not doing Event Sourcing. Just have a basic hexagonal architecture using port adaptors and trying to figure out best practices. Thanks for the responses @gregoryyoung @ThomasJaeger.

@gregoryyoung

This comment has been minimized.

Show comment
Hide comment
@gregoryyoung

gregoryyoung Apr 1, 2018

Owner
Owner

gregoryyoung commented Apr 1, 2018

@michaelajr

This comment has been minimized.

Show comment
Hide comment
@michaelajr

michaelajr Apr 1, 2018

If IDs are typed, TenantId or UserId, then they are immutable value objects. So Maybe that is fine to leak out. Guess we have to make compromises.

If IDs are typed, TenantId or UserId, then they are immutable value objects. So Maybe that is fine to leak out. Guess we have to make compromises.

@michaelajr

This comment has been minimized.

Show comment
Hide comment
@michaelajr

michaelajr Apr 1, 2018

@gregoryyoung But the application boundary is suppose to return void on commands, so the response your REST adaptor will get from the createFoo command method will be void. How do you get the ID?

@gregoryyoung But the application boundary is suppose to return void on commands, so the response your REST adaptor will get from the createFoo command method will be void. How do you get the ID?

@alexlawrence

This comment has been minimized.

Show comment
Hide comment
@alexlawrence

alexlawrence Apr 16, 2018

Forgive if I´m wrong but this conversation reads like multiple topics are partially mixed together. One is about the practical advantages of generating entity IDs on the client. The other one is about the conceptual question in which layer identity generation belongs.

Regarding the practical advantages: I worked on a project where commands to create entities were immediately followed by commands that worked with the entities. We started with generating IDs inside the domain and returning them as command result. Resulted in additional complexity in the client code. After reading about the idea of passing in the IDs from the outside, we refactored our code. This decreased the complexity and made the code much more straight forward. For practical reasons this is definitely recommendable.

As for the conceptual topic, I have been asking this myself recently again. I very much like the statement from @ThomasJaeger : "My point is that the client only sends "suggestions or requests" to the domain. There is nothing stopping the domain to use this ID for another purpose or as part of a a bigger ID for that entity.". Still, I´m wondering whether it is a problem that domain knowledge is leaking to the client(s). What if there many different types of clients (web, mobile, json over http, etc.)? Isn´t the domain knowledge how to create IDs then duplicated across them?

Forgive if I´m wrong but this conversation reads like multiple topics are partially mixed together. One is about the practical advantages of generating entity IDs on the client. The other one is about the conceptual question in which layer identity generation belongs.

Regarding the practical advantages: I worked on a project where commands to create entities were immediately followed by commands that worked with the entities. We started with generating IDs inside the domain and returning them as command result. Resulted in additional complexity in the client code. After reading about the idea of passing in the IDs from the outside, we refactored our code. This decreased the complexity and made the code much more straight forward. For practical reasons this is definitely recommendable.

As for the conceptual topic, I have been asking this myself recently again. I very much like the statement from @ThomasJaeger : "My point is that the client only sends "suggestions or requests" to the domain. There is nothing stopping the domain to use this ID for another purpose or as part of a a bigger ID for that entity.". Still, I´m wondering whether it is a problem that domain knowledge is leaking to the client(s). What if there many different types of clients (web, mobile, json over http, etc.)? Isn´t the domain knowledge how to create IDs then duplicated across them?

@BackDoorMan00

This comment has been minimized.

Show comment
Hide comment
@BackDoorMan00

BackDoorMan00 Jul 6, 2018

Ids should be generated on the server unless you have a very specific need to generate them on the client-side which is also something I would personally never do.

I didn't read the entire conversation but when you are using CQRS then commands "can't" return anything, so there's no way to return the id of created entity. So you need to know the id so you can later query created object with a 2nd call. Note that you can't really use auto-incremented ids with CQRS.

Minimal example when using some library like MediatR to dispatch messages/events/commands.

var id = Guid.NewGuid();
_mediator.Send(new CreateSomethingCommand(id));
var something = _mediator.Send(new GetSomethingCommand(id));

Personally because of that I'm not such a big fan of CQRS, because it makes me feel limited. It's over-hyped pattern and you can achieve same things without it.

BackDoorMan00 commented Jul 6, 2018

Ids should be generated on the server unless you have a very specific need to generate them on the client-side which is also something I would personally never do.

I didn't read the entire conversation but when you are using CQRS then commands "can't" return anything, so there's no way to return the id of created entity. So you need to know the id so you can later query created object with a 2nd call. Note that you can't really use auto-incremented ids with CQRS.

Minimal example when using some library like MediatR to dispatch messages/events/commands.

var id = Guid.NewGuid();
_mediator.Send(new CreateSomethingCommand(id));
var something = _mediator.Send(new GetSomethingCommand(id));

Personally because of that I'm not such a big fan of CQRS, because it makes me feel limited. It's over-hyped pattern and you can achieve same things without it.

@gregoryyoung

This comment has been minimized.

Show comment
Hide comment
@gregoryyoung

gregoryyoung Jul 6, 2018

Owner
Owner

gregoryyoung commented Jul 6, 2018

@BackDoorMan00

This comment has been minimized.

Show comment
Hide comment
@BackDoorMan00

BackDoorMan00 Jul 6, 2018

@gregoryyoung What problem is coming exactly? Do you mean sending those commands with 1 HTTP request?

BackDoorMan00 commented Jul 6, 2018

@gregoryyoung What problem is coming exactly? Do you mean sending those commands with 1 HTTP request?

@gregoryyoung

This comment has been minimized.

Show comment
Hide comment
@gregoryyoung

gregoryyoung Jul 6, 2018

Owner
Owner

gregoryyoung commented Jul 6, 2018

@BackDoorMan00

This comment has been minimized.

Show comment
Hide comment
@BackDoorMan00

BackDoorMan00 Jul 6, 2018

@gregoryyoung

send command -> receive response -> send command -> receive response

Seems like the most common use.

send 2 commands -> receive responses

Just complicates things

BackDoorMan00 commented Jul 6, 2018

@gregoryyoung

send command -> receive response -> send command -> receive response

Seems like the most common use.

send 2 commands -> receive responses

Just complicates things

@gregoryyoung

This comment has been minimized.

Show comment
Hide comment
@gregoryyoung

gregoryyoung Jul 6, 2018

Owner
Owner

gregoryyoung commented Jul 6, 2018

@gregoryyoung

This comment has been minimized.

Show comment
Hide comment
@gregoryyoung

gregoryyoung Jul 6, 2018

Owner
Owner

gregoryyoung commented Jul 6, 2018

@mklinke

This comment has been minimized.

Show comment
Hide comment
@mklinke

mklinke Jul 6, 2018

Contributor

In my company, we have built an API layer (accessed via HTTP POST) that generates the command ID (this is important, it's NOT the entity ID), sends the command and returns the command ID to the client immediately. So basically the send/receive/send/receive pattern mentioned above, but not on an entity level, but on an infrastructure level. So technically, the command does not return anything, but the API that generates the command returns something. So the client can track the status of the command by subscribing to changes based on the command ID.

However, I find the "either they all succeed or none do"-part of @gregoryyoung 's answer interesting to think about. Would you enforce this technically e.g. by sending the commands in a single message and processing the message atomically? Basically, that's the A in ACID. If that's the case, you can conceptually think of the batch as a single command and then it's an implementation detail if you need to set the entity ID in advance or if it will be generated internally when processing the command. Otherwise, you'd probably need some kind of process manager or saga (unfortunately pretty overloaded and ambiguous terms IMHO) to handle partial failure etc.

With our approach, we'd have a notification as soon as the command was processed. We also have the option to subscribe to changes in read-models that could rather easily be mapped to a command e.g. via a correlation ID.

Just my 2 cents to this very important discussion.

Contributor

mklinke commented Jul 6, 2018

In my company, we have built an API layer (accessed via HTTP POST) that generates the command ID (this is important, it's NOT the entity ID), sends the command and returns the command ID to the client immediately. So basically the send/receive/send/receive pattern mentioned above, but not on an entity level, but on an infrastructure level. So technically, the command does not return anything, but the API that generates the command returns something. So the client can track the status of the command by subscribing to changes based on the command ID.

However, I find the "either they all succeed or none do"-part of @gregoryyoung 's answer interesting to think about. Would you enforce this technically e.g. by sending the commands in a single message and processing the message atomically? Basically, that's the A in ACID. If that's the case, you can conceptually think of the batch as a single command and then it's an implementation detail if you need to set the entity ID in advance or if it will be generated internally when processing the command. Otherwise, you'd probably need some kind of process manager or saga (unfortunately pretty overloaded and ambiguous terms IMHO) to handle partial failure etc.

With our approach, we'd have a notification as soon as the command was processed. We also have the option to subscribe to changes in read-models that could rather easily be mapped to a command e.g. via a correlation ID.

Just my 2 cents to this very important discussion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment