Comments (21)
When I started with CQRS I struggled with the same "mismatch", what helped me is this:
- leave the "update resources" thinking and think more task-oriented. This may also mean changing the user interface so that users does not see forms of fields and check boxes with a single "update" button, but multiple task buttons like "Deactivate user". There are several articles about task oriented UIs like this: https://cqrs.wordpress.com/documents/task-based-ui/
- see also: REST without PUT https://www.thoughtworks.com/insights/blog/rest-api-design-resource-modeling
from m-r.
@rganz at first I thought that was to me and was going to be forced to point out the irony that I wrote the first article :P
from m-r.
UpdateEntity Customer { id : 44465, active : false }
is very different than
DeactivateCustomer {id 44465 }
from m-r.
> <account>
> <account_number>12345</account_number>
> <balance currency="usd">100.00</balance>
> <link rel="deposit" href="/account/12345/deposit" />
> <link rel="withdraw" href="/account/12345/withdraw" />
> <link rel="transfer" href="/account/12345/transfer" />
> <link rel="close" href="/account/12345/close" />
> </account>
as example. The handlers for the operations defined then are what actually creates the command internally.
from m-r.
from m-r.
CQRS can be applied to methods or messages. To be fair the difference is rather not worth discussing as some languages use messages to implement method calls :) refactor method to message is widely available (refactor parameters to object)
from m-r.
@gregoryyoung but when you create REST API it always looks like the first example. Does it mean CQRS doesn't make sense when implementing REST API? I mean technically it can be done by creating something like UpdateCustomerCommand and using it to deactivate customer using your first example.
from m-r.
Oh, I get it now. But does it mean CQRS can't be used with CRUD? (means no operations, just passing the state/object) For example, closing the account would be setting isClosed to true. Does using it in this context make sense?
from m-r.
CQRS/CQS doesn't say anything about the single responsibility of a command. It tells to just isolate write methods from read methods.
Does it mean I don't need command-specific objects like DeactivateUserCommand
?
void DeactivateUser(int userId)
will be a command too right? even despite I don't have any input model named DeactivateUserCommand
or more general
void UpdateUser(User user)
will be a command too right?
from m-r.
@rganz Yeah there's a confusion when talking about CQRS in Task-oriented UIs vs CRUD oriented UIs. The definition of the pattern looks different for both. For example, the definition for CRUD oriented UIs presents CQRS as:
CustomerWriteService
void MakeCustomerPreferred(CustomerId)
void ChangeCustomerLocale(CustomerId, NewLocale)
void CreateCustomer(Customer)
void EditCustomerDetails(CustomerDetails)
CustomerReadService
Customer GetCustomer(CustomerId)
CustomerSet GetCustomersWithName(Name)
CustomerSet GetPreferredCustomers()
While for Task oriented UIs the definition for Command changes:
Commands
The method through which the Application Server will be told what to do is through the use of a
Command. A command is a simple object with a name of an operation and the data required to perform
that operation. Many think of Commands as being Serializable Method Calls. Listing 1 includes the code
of a basic command.
From: https://cqrs.files.wordpress.com/2010/11/cqrs_documents.pdf
It seems like it applies differently in different usage contexts.
from m-r.
The definitions for me are the same, how do you find them different?
from m-r.
@gregoryyoung There are no "SomeActionCommand" classes in your example of CQRS with CustomerWriteService and CustomerReadService and original definition describes commands as operations not data models/structures of data.
The definition says just to segregate methods that read from those that write and you're done.
But later in "Task based user interfaces" section it introduces new definition of command. Giving examples like:
public class DeactivateInventoryItemCommand {
public readonly Guid InventoryItemId;
public readononly string Comment;
public DeactivateInventoryItemCommand (Guid id, string comment) {
InventoryItemId = id;
Comment = comment;
}
Does it mean there is a different definition of Command in CQRS depending on usage?
There is no clear definition of what command really is, first it says just to use different interfaces and you're done and then all of sudden it talks of commands as of data structures where you define some data to pass to perform some action.
from m-r.
My slide for CQRS does not normally have reads going through the domain so I am a bit confused.
from m-r.
One definition says that
A command is a simple object with a name of an operation and the data required to perform that operation. Many think of Commands as being Serializable Method Calls. Listing 1 includes the code
of a basic command.
Other definition says that:
CQRS is a pattern that segregates the operations that read data (queries) from the operations that update data (commands) by using separate interfaces
One definition speaks of a command as of a "simple object". The second definition speaks of a command as operation that update data.
The original definition of CQS talks about commands as of methods, not objects.
from m-r.
@gregoryyoung I think it's worth discussing because "Command" gets a different meaning when applied to messages if by that you mean event-driven systems that handle things after receiving some message.
To make more sense it would be nice to provide example like:
class MakeCustomerPreferredCommand
{
public int CustomerId { get; set; }
}
class CreateCustomerCommand
{
public Customer Customer { get; set; }
}
class EditCustomerDetailsCommand
{
public CustomerDetails CustomerDetails { get; set; }
}
That presents commands as objects instead of methods/operations.
from m-r.
Like what SimpleCQRS does? #TrollLOLLOL :P
https://github.com/gregoryyoung/m-r/blob/master/SimpleCQRS/Commands.cs
from m-r.
@gregoryyoung Can't this duplication be a bit simplified?
Lines 43 to 46 in 31d315f
Lines 55 to 58 in 31d315f
from m-r.
Could be but you probably don't want to. They are defining schema. What happens when you have 3 levels of inheritance etc and need to change something higher up? How much time did you save through you reuse? Its frankly also a PITA to go searching through inheritance hierarchies. There are as well tools that generate this stuff for you ;-)
from m-r.
@gregoryyoung I have CRUD based UI does it make sense to apply CQRS?
from m-r.
Not usually though it can. Normally you are more interested in behaviours, why something happens is often important. If you just need CRUD why not just maintain a SQL transaction file?
To be clear "Volume changed" on our order in the stock market. Why did volume change? We could have changed it, the market could have changed it (varying rules etc), it could have traded, it could be a regulatory cancellation, etc.
if you don't have the separate events I bet you get a bunch of code figuring out which type it was in many places.
from m-r.
That was my original point. Often no. I have discussed this a lot in talks there are simpler ways of reaching the same goal such as an audit table on updates. I am not trying to put you off the idea (it has benefits) but often they will not be realized IME
from m-r.
Related Issues (20)
- EventDescriptor purpose HOT 4
- Add LICENSE to repository HOT 2
- About FakeBus sample implementation and contracts for the registration HOT 13
- How to implement business rules? HOT 10
- Why do commands include the entity id when creating entities? HOT 34
- How to implement bulk processing? HOT 6
- Event is mutable HOT 1
- Deactivate action should be POST
- Extraneous properties (and even class)? HOT 2
- Should configuration settings be eventsourced? HOT 1
- Use ReflectionMagic and get rid of InfrastructureCrap.DontBotherReadingItsNotImportant.cs HOT 2
- aggregate id and aggregate root HOT 16
- Remove bus from projections HOT 1
- Test
- What is the semantic of the Version property in the Event class ?
- Regarding the class naming convention HOT 3
- InventoryItemRenamed: Can't for the life of me see where this is being handled HOT 2
- AggregateRoot version never updated HOT 9
- Why use DelegateAdjuster? HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from m-r.