Disadvantages of having CRUD as part of your CQRS-ES?

1,198 views
Skip to first unread message

Werner Clausen

unread,
Dec 12, 2011, 8:24:47 AM12/12/11
to ddd...@googlegroups.com
Hi,
 
I have read the recommendations several places: CRUD does not fit well inside your CQRS-ES structure. And I'd like to relate this to an example before I ask my question(s): Suppose you have to deal with Customers - in general I find it to be very much under the CRUD recommendations that I read about. We have the Customer class with 20+ standard properties like name, address etc:
 
[Customer]
Firstname
Lasname
...
 
More precisely, I'm not talking about actual deletion, but just a "deleted" marker of some sort. We'd really like history of all changes in the system. Not just important business data. In other words, we would like to be able to see who created the customer and what changes has the customer went through. With this in mind, would you still keep "Customer" outside CQRS-ES? And find another way to deal with history? If not, could you explain what the disadvantages are?
 
The only disadvantage I can Google is the overhead. That it would be much easier just to manage the Customer data the old way. But given the fact that we'd like history on everything, I would have to say, that setting up an EventStore and just have my "Aggregate" handle CRUD seems much much easier to implement that anyhing else I can think of. This tends to suggest that I am missing some crucial disadvantages and thus this thread :)
 
Any advice appreciated.
 
--
Werner
 
 
 
 

Tom Janssens

unread,
Dec 12, 2011, 12:56:15 PM12/12/11
to ddd...@googlegroups.com
I've used cqrs for crud as well, using a simple dictionary of (string, object) named ApplyChangeSet.

Tom

Typed on a mobile

Philip Jander

unread,
Dec 12, 2011, 1:56:39 PM12/12/11
to ddd...@googlegroups.com
Hi Werner,

for the occiasional crud-like operation within a bounded context for
which cqrs is otherwise sensible, I see no disadvantage. The additional
overhead is not that high, somtimes it is far easier to reuse the
infrastructure.
With event sourcing, there usually is one "XYZUpdated" event and one or
multiple projections making use of the event. Within the domain itself,
there simply is a method emitting the appropriate event.
You can even handle such commands in a command handler and not have a
domain model involved at all.

Even for some purely crud style use cases, the audit log may be of
value. Think e.g. of changing the account # of a payee. Maybe the
account # is read of the read model in the end, so you will never even
have that field in the domain. But having a record of who changed it is
crucial.

Cheers
Phil

Werner Clausen

unread,
Dec 13, 2011, 3:44:19 AM12/13/11
to ddd...@googlegroups.com
@PhilJ and @Tom,
 
Thanks for your answers, and I agree with everything Phil says. 
It has confirmed to me, that our intended usage in fact is perfectly valid.  
 
Thanks.
 
Werner

Peter Ritchie

unread,
Dec 13, 2011, 9:13:36 AM12/13/11
to ddd...@googlegroups.com
I don't think there's really any disadvantages.  CQRS is usually used for complex software projects.  DDD is also used for complex software projects and seems to be associated with CQRS.   DDD attempts to deal with the complexity of the behaviour.  CRUD systems have little or no behaviour.  A system with little or no behaviour doesn't really have a complex event structure (just created events, archived events, and updated events), so it's hard to say how much benefit you get from CQRS.

But, usually people are doing CQRS for other reasons.  Clearly if you're doing CQRS+ES then you're keeping a record of events in some way.  Auditing events as they occur is much easier than trying to audit actions with no consistent data structures (you end up just creating event structures; but without the explicitness of events in your system).  Also, CQRS works well in distributed systems; if you have a distributed CRUD system you're probably getting benefit out of CQRS in that area too because you have to physically send defined messages over the wire.

In summary, if you're doing ES or transferring messages then you're not just CRUD.

Cheers -- Peter
--
"Refactoring with Microsoft Visual Studio 2010": http://bit.ly/c13trs
http://PeterRitchie.com/blog/
http://twitter.com/PeterRitchie
http://facebook.com/Peter.Ritchie/
http://www.linkedin.com/in/PeterARitchie
Skype:Peter.a.Ritchie

Rinat Abdullin

unread,
Dec 13, 2011, 12:36:01 PM12/13/11
to ddd...@googlegroups.com
Anemic domain model is considered to be the CRUD in CQRS/DDD world (even with AR+ES).

It still has the benefit of avoiding object-relational impedance mismatch associated with traditional databases.

But you can get a lot of that by using NoSQL DBs as well.

Best,
Rinat

Nuno Lopes

unread,
Dec 13, 2011, 1:13:10 PM12/13/11
to ddd...@googlegroups.com
Well, anaemic domain model is not the same as CRUD either :)

If we organize our logic primarily around Command and Queries the end result is usually an anemic domain model. This has been done for decades. It is called Imperative/Procedural Programming. Pascal and C are examples of that. Events by themselves do not guarantee that we are following a behavioral paradigm either. In CQRS they work as signals. Typically in CQRS events are converted to Commands (more transaction scripts). 

The tipping turn is when commands are actioned by Aggregate methods. And event Aggregation is made by Aggregates, not Sagas. But there is nothing in CQRS that calls for this requirement.

I'm not saying that this is good or bad, it is just what it is.

Nuno

Sharas

unread,
Dec 13, 2011, 1:42:09 PM12/13/11
to ddd...@googlegroups.com
CRUD rocks, anemic domain model sucks. I hope that shed some light on a discussion.

Dylan Smith

unread,
Dec 13, 2011, 4:04:10 PM12/13/11
to ddd...@googlegroups.com

If you are doing plain old CRUD, do you even need a domain model?  You can still do CQRS/ES, but just have your command-handlers implemented like transaction-script pattern and generate events directly.  If we have no behaviour, there is no need for AR’s as far as I can see.

Nuno Lopes

unread,
Dec 14, 2011, 3:41:18 AM12/14/11
to ddd...@googlegroups.com

You can still do CQRS/ES, but just have your command-handlers implemented like transaction-script pattern and generate events directly. 

+1 That show how well CQRS/ES fits an anaemic domain model. I've used CQRS with CRUD more then a couple of times.

Cheers,

Nuno

Werner Clausen

unread,
Dec 14, 2011, 5:43:47 AM12/14/11
to ddd...@googlegroups.com
@Dylan && @Nuno,
 
PhilJ said the same in his answer, and for simple CRUD, no, I don't think that I even need a domain. But on the other hand, saving an event to the ES and publishing that exact same event is a key task of the repository. Taking that out of context could introduce errors. But this is theory while yours is based on hands-on experience which of course count for more.
 
I will discuss this with my colleagues - to be honest, I was thinking about restricting the Eventstore so that access from outside the domain would be read-only. Hmm, perhaps that would be too restricted?
 
Werner

Tom Janssens

unread,
Dec 14, 2011, 7:41:35 AM12/14/11
to ddd...@googlegroups.com
I think I might need to clarify my post a little bit: I have a command like this for CRUD on a customer for example:

class ApplyCustomerChangeSet // used to update customer properties which are irrelevant to the AR
{
   public string CustomerId;
   Dictionary<string,object> ChangeSet; // property names & values
}

class CustomerChangeSetApplied // used when a customer is updated
{
   public string CustomerId;
   Dictionary<string,object> ChangeSet;
}


This allows you to keep your customer AR as clean as possible while still allowing tons of extra info being propagated to the events. 
It also allows you to intercept/check/translate values if necessary, but you do not have to if you do not need to...

Dylan Smith

unread,
Dec 14, 2011, 11:43:44 AM12/14/11
to ddd...@googlegroups.com

I would still have a Repository layer that knew how to publish/store events.  I would just generate the events directly in my command handlers then pass them to the repository, instead of the usual approach of having the command handler call out to the domain model to gen events.  E.g. :

 

 

public void HandleCommand(DeleteCustomerCommand cmd) {

    _repository.PublishEvent(new CustomerDeletedEvent(cmd.CustomerId));

}

 

 

Cheers,

Dylan

 

 

From: ddd...@googlegroups.com [mailto:ddd...@googlegroups.com] On Behalf Of Werner Clausen
Sent: Wednesday, December 14, 2011 5:44 AM
To: ddd...@googlegroups.com
Subject: Re: [DDD/CQRS] Disadvantages of having CRUD as part of your CQRS-ES?

 

@Dylan && @Nuno,

Philip Jander

unread,
Dec 15, 2011, 5:41:54 AM12/15/11
to ddd...@googlegroups.com
Hallo Werner,

some more thoughts on that.

Conceptually, every part* of the system that uses a different
architecture (e.g. domain model vs pure-crud vs. transaction script)
should be using a separate event store.
The implementation may very well be a single store, but e.g. an
aggregate should never request an event not originating from it. This
does not preclude responding to the published event within an event
handler, I am just talking about access to the storage. So you do not
need to restrict access to the event store to the domain model, but to
restrict access to events to those parts of your code from which the
events originate. With the exception of projections/denormalizers, which
obviously need to have access to all events.

For the CRUD part, you do not really need to load up any events. Loading
up previous events means conditional reaction depending on state. Such
rules should be implemented in the domain model. For the cruddy
operations, I limit myself to "update" and "mask/delete" events that are
idempotent and - well CRUDdy. As soon as something requires previous
state, I model it as an entity/aggregate to avoid the
transaction-script/anemic domain model path.

There is one exception however: for major version upgrades that require
generation of "correction" events, I use a lot of transaction scripts.
In such situations usually the alyout of aggregates change, and
therefore it makes sense to momentarily lift the consistency boundary
when transitioning from one domain model to another.

Cheers Phil

* (These parts are often called "bounded context" here, but I feel that
the term has actually been overloaded with at least two seperate meanings.)

@yreynhout

unread,
Dec 15, 2011, 7:02:01 AM12/15/11
to DDD/CQRS
Ugh, isn't that more of a bus, rather than a repository?

Werner Clausen

unread,
Dec 16, 2011, 3:35:01 AM12/16/11
to ddd...@googlegroups.com
PhilJ,
 
Thanks for your thoughts here - really appreciated.
As I see it, one of the important things to derive here, is that an update isn't partial in CRUD. For example you would not have "UpdateCustomerAddress(customerId, address)" - but just "UpdateCustomer(customer)". Which would mean that I do not need to load up any events from CRUD.
 
Werner

Philip Jander

unread,
Dec 16, 2011, 6:35:06 AM12/16/11
to ddd...@googlegroups.com
Not at all.

You really want to have that granularity.

UpdateCustomerAddress(customerId, address)
and
AddressWasChanged as a corresponding event is perfectly valid.

Partial updates was not the point I tried to make, rather conditional
updates.

You don't want to have a condition refering to current state in the CRUD
command handler (e.g. "Address is changed only if the customer is still
active").
As soon as you have any kind of logic, include that in your domain
model. In other words: Update and Deletes must not fail and must be
idemponent.
Otherwise, it's no longer a crUd operation.

Cheers
Phil

Werner Clausen

unread,
Dec 20, 2011, 7:14:19 AM12/20/11
to ddd...@googlegroups.com
@PhilJ
 
Point taken. I don't want conditional updates in CRUD. But I could (and probably should) have partial updates.
 
Werner
Reply all
Reply to author
Forward
0 new messages