Seeing some frustration with repetition of properties in CQRS

630 views
Skip to first unread message

Chris Nicola

unread,
Apr 13, 2011, 8:27:46 PM4/13/11
to ddd...@googlegroups.com
I've noticed a couple of people new to CQRS who have been somewhat frustrated by the repetition of data properties (commands, events, domain, read model) with CQRS.  My typical response has been these are just sunoke data and message objects so the duplication is really not a big deal but I do still feel their pain and I'm starting to see why.

Consider the following scenario, a new property is required to be on a read model, it's never previously been part of the domain model.  Admittedly this is a bit of a cruddy scenario, but some things are going to be like this no matter how behavior driven we try to keep our domain.

In order to make this happen the following needs to happen:

- Update a command, possibly multiple with the new data property
- Update the command handler (possibly multiple) to pass this property to the Aggregate Root
- Update or add an exposed AggregateRoot behavior that allows the setting/updating of the data property
- Update or add an event that will communicate this data to the read model
- Update or add an event handler that will write this data to the persistent storage (and possibly also update static classes that represent the read model)

All through this process we are updating our unit tests and we also have to update the client(s) too.

To a lot of people this seems like duplication of effort and a brutal violation of DRY.  My excuse that we are just communicating messages and that this isn't all that hard seems to fall a little flat in the face of all this.  I still think there is a ton of value in the CQRS model, the code stays cleaner and the very fact that I can easily describe a fairly repeatable pattern for making *domain safe* changes is of huge value in my mind (no hacking around the domain model and writing directly to the database).

I'm curious if other people have had similar conversations, I'm also curious if people have ideas for keeping CQRS a bit DRY'er.

Adam Dymitruk

unread,
Apr 13, 2011, 8:41:58 PM4/13/11
to ddd...@googlegroups.com, Chris Nicola
After adding that property, do a 'git add . -A --intend-to-add' and
then 'git diff'. This should show you all the changes in your
solution. If you have CRUDy stuff like this, you can codegen your way
to happiness.

--
Adam

http://adventuresinagile.blogspot.com/
http://twitter.com/adymitruk/
http://www.agilevancouver.net/
http://altnetvan.grou.ps/

Rickard Öberg

unread,
Apr 13, 2011, 9:57:25 PM4/13/11
to ddd...@googlegroups.com
On 4/14/11 08:27 , Chris Nicola wrote:
> In order to make this happen the following needs to happen:
>
> - Update a command, possibly multiple with the new data property
> - Update the command handler (possibly multiple) to pass this property
> to the Aggregate Root
> - Update or add an exposed AggregateRoot behavior that allows the
> setting/updating of the data property
> - Update or add an event that will communicate this data to the read model
> - Update or add an event handler that will write this data to the
> persistent storage (and possibly also update static classes that
> represent the read model)

Here's what I do, usually, in Qi4j-land. First off, in situations where
there is likelyhood that the properties will be expanded (e.g. contact
info for a user) I usually use value objects to convey them. This value
gets put into the command, event, and snapshot state. And so, for me the
change boils down to adding this to the value class:
Property<String> myNewProperty();

Done.

/Rickard

Simon Harris

unread,
Apr 13, 2011, 11:54:26 PM4/13/11
to DDD/CQRS
TBH, it sounds more like an issue with the underlying language/use of
the language. I'm in Ruby and I have (for >95%) generic commands,
events, and dispatching, so all I do above what I'd have to do in a
CRUD world is:

* Add an event handler to my AggregateRoot/Entity
* Add event handlers to whatever view models need to know about the
change

Chris Nicola

unread,
Apr 14, 2011, 1:36:30 AM4/14/11
to ddd...@googlegroups.com
Yeah language is definitely a factor, obviously there is more ceremony
in the static world. That said Rickard's solution using Value objects
is also an option, but it means planning head for the need for value
objects or using them for absolutely everything. That doesn't really
feel all that good to me.

Chris

Rickard Öberg

unread,
Apr 14, 2011, 1:39:12 AM4/14/11
to ddd...@googlegroups.com
On 4/14/11 13:36 , Chris Nicola wrote:
> Yeah language is definitely a factor, obviously there is more ceremony
> in the static world. That said Rickard's solution using Value objects
> is also an option, but it means planning head for the need for value
> objects or using them for absolutely everything. That doesn't really
> feel all that good to me.

Yeah, you need to get a feel for when you have a situation where the
fields are likely to expand later. For example, the contact info is an
obvious one where you can add any number of fields really. Knowing when
to do what is just based on experience, I think.

/Rickard

Fossmo

unread,
Apr 14, 2011, 4:07:01 AM4/14/11
to DDD/CQRS
In my current CQRS project we had the same problem. What we did was to
build a generator to make this tedious and error prone job much faster
and simpler. We still have to update the domain model, but all the
events, commands, handlers and read tables are generated. This is
a .NET project, but we used Ruby to generate the C# code (ERB and
Thor). We could of course have used T4, but we liked the Ruby syntax,
so we went for that.

Pål

Nuno Lopes

unread,
Apr 14, 2011, 4:27:16 AM4/14/11
to ddd...@googlegroups.com
What we got rid of the Commands?

Cheers,

Nuno

Greg Young

unread,
Apr 14, 2011, 7:10:35 AM4/14/11
to ddd...@googlegroups.com
there is also another well known "dsl" that works very well for this.
Define commands/events/dtos from xsd :)

--
Les erreurs de grammaire et de syntaxe ont été incluses pour m'assurer
de votre attention

Chris Nicola

unread,
Apr 14, 2011, 11:43:21 AM4/14/11
to ddd...@googlegroups.com
Perhaps some decent code-gen is all that's missing from the puzzle here for me.  I've never spent much time doing code-gen. 

+1 for T4 being ugly and unwieldy though

Not sure how I feel about using XSD either, sorry Greg ;-).

I do like the idea of using ERB, mainly because it also brings in some decent scripting power.  I'll need to set aside some time to toy with this a bit more.

Greg Young

unread,
Apr 14, 2011, 12:02:19 PM4/14/11
to ddd...@googlegroups.com

Xsd actually works very well for this (using a tool to create them... Not by hand). We were doing the creation of these as part of our estimation proces

Jimmy Bogard

unread,
Apr 14, 2011, 12:17:09 PM4/14/11
to ddd...@googlegroups.com

You could also check out steve sanderson's T4 scaffolding project. Using the powershell host you can add files, classes, members etc. to a variety of files. Steve's demos just show ef4 and mvc, but it's built upon a generic framework. You get access to the project files and so on so you're now just at the conceptual level of templatizing "add a member to these four classes".

For situations like these, we'll try to rely on conventions if possible to reduce pointless wiring.

Chris Nicola

unread,
Apr 14, 2011, 12:30:52 PM4/14/11
to ddd...@googlegroups.com
What tool are you using for this?

@yreynhout

unread,
Apr 14, 2011, 1:03:59 PM4/14/11
to DDD/CQRS
If this is a reply to Greg, I presume he's referring to xsd.exe. I use
it all the time to spit out classes for use in plain old webservices.
Of course, purists will frown upon the mutability of command
properties and no ctor (at least I don't know how to enforce such with
xsd.exe)
As for tooling there's Altova's XmlSpy if you don't mind spending the
cash and brushing up your rusty xml skills now we've all moved onto
json and other human readable data formats. Actually, that's not true,
it has a json editor: http://www.altova.com/xmlspy/json-editor.html
(going to watch my shares go up).

Chris Nicola

unread,
Apr 14, 2011, 4:49:21 PM4/14/11
to ddd...@googlegroups.com
So after some more thought I'm considering a potential solution to
simplify the problem of managing trivial data oriented state changes
to being represented by a single state with the values encapsulated in
a single VO:

1. Encapsulate the trivial data properties into a single object (you
can call it a value object but it's really more of a DTO) that is part
of the command. Something like ProductValues.

2. This DTO is passed directly to the aggregate root in a single
behavior Product.UpdateValues(ProductValues values) I know that's
terrible for DDD, but again we aren't really dealing with much
behavior related stuff in these changes. These changes are arguably
of little business value.

3. The Aggregate Root's trivial data values are then applied by a
single event which contains a "difference" object representing what
changed. This is somewhat consistent with the version control model
for changes to a document this is managed as a fairly dynamic such
that we can expand or contract the concept without affecting our
history.

I feel this approach allows trivial data changes to be managed and
refactored quickly and dynamically without a lot of ceremony and
avoids even the need for code-gen, leaving most of the other events
focused on communicating state changes that are of clear business
value.

Chris

Colin Jack

unread,
Apr 14, 2011, 5:27:21 PM4/14/11
to DDD/CQRS
One question I would have is whether this is cqrs' sweet spot?

If it really is CRUD, and the resulting design is a bit of a kludge
(ProductValues and diff object), then is it really worth the effort?

Rickard Öberg

unread,
Apr 15, 2011, 12:49:29 AM4/15/11
to ddd...@googlegroups.com
On 4/15/11 04:49 , Chris Nicola wrote:
> So after some more thought I'm considering a potential solution to
> simplify the problem of managing trivial data oriented state changes
> to being represented by a single state with the values encapsulated in
> a single VO:
>
> 1. Encapsulate the trivial data properties into a single object (you
> can call it a value object but it's really more of a DTO) that is part
> of the command. Something like ProductValues.

Yeah, I name mine *DTO. *Value I reserve for purely internal values that
can have some logic in them.

> 2. This DTO is passed directly to the aggregate root in a single
> behavior Product.UpdateValues(ProductValues values) I know that's
> terrible for DDD, but again we aren't really dealing with much
> behavior related stuff in these changes. These changes are arguably
> of little business value.
>
> 3. The Aggregate Root's trivial data values are then applied by a
> single event which contains a "difference" object representing what
> changed. This is somewhat consistent with the version control model
> for changes to a document this is managed as a fairly dynamic such
> that we can expand or contract the concept without affecting our
> history.
>
> I feel this approach allows trivial data changes to be managed and
> refactored quickly and dynamically without a lot of ceremony and
> avoids even the need for code-gen, leaving most of the other events
> focused on communicating state changes that are of clear business
> value.

+1. Although I did XDoclet way back in EJB land, nowadays I try to stay
away from codegen as much as possible.

/Rickard

Rickard Öberg

unread,
Apr 15, 2011, 12:50:42 AM4/15/11
to ddd...@googlegroups.com
On 4/15/11 05:27 , Colin Jack wrote:
> One question I would have is whether this is cqrs' sweet spot?
>
> If it really is CRUD, and the resulting design is a bit of a kludge
> (ProductValues and diff object), then is it really worth the effort?

In my case there's a bit of crud, there's a bit of places where
CQRS/EventSourcing is really needed, but having CQRS/EventSourcing for
everything makes much more sense, in spite of the pockets of CRUD.

/Rickard

Dan Malcolm

unread,
Apr 16, 2011, 7:47:52 AM4/16/11
to DDD/CQRS
What kind of things are being stored in ProductValues?

I'm guessing this might be "contenty" properties, such as title, short
description, long description, images, video etc? Sure, changing these
values feels like a CRUDDY operation - there's no functionality within
the Product domain object, it's basically a setter. However it is
still an important part of the behaviour of your system: marketing
activity. Is the business interested in questions like "How soon is a
new product enriched with polished and SEO-friendly content?", "How
can we review content changes to our products?" or "Who uploaded that
picture of a meerkat?" ?

This helps to guide decisions on how granular we need to model changes
to these properties. In this case separate methods / events for
ChangeTitle, ChangeDescription would be crazy. As you and others have
suggested, using a value object to store clusters of properties makes
it easy to add new properties. I think we could be letting ourselves
down with a generic term like ProductValues though. Why not model the
various properties as a ProductContent value type, change it via a
ChangeContent method and raise a ContentChanged event.

Follow this through on other clusters of values and you'll end up with
nice expressive domain model and set of events.

I've made a few assumptions about Product here. If I'm way off,
perhaps you could give us a summary of the kind of properties that
belong to ProductValues.

Dan

On Apr 14, 9:49 pm, Chris Nicola <chnic...@gmail.com> wrote:

Dan Malcolm

unread,
Apr 16, 2011, 9:41:14 AM4/16/11
to DDD/CQRS
On Apr 14, 10:27 pm, Colin Jack <colin.j...@gmail.com> wrote:
> One question I would have is whether this is cqrs' sweet spot?

Colin

Perhaps the best way to decide whether domain events / CQRS is a good
fit for CRUD scenarios is to ask "Does anything else need to happen
when things are created, updated and deleted?".

We discussed using events / CQRS for CRUD recently:
http://groups.google.com/group/dddcqrs/browse_thread/thread/7ba217a171211fd9

In this case, although the tenant configuration and content management
BC (see above thread for details) felt inherently CRUDDY, we pressed
on and used the "standard" domain model / CQRS architecture: domain
model, domain events, handlers to update read models etc. It's still
early days, but I think it was a good decision.

So, some of our objects have very little "behaviour", they mostly just
have methods that change their state. For example, Tenant.AddProperty
adds a new Property (Property is a hotel / resort) to a collection.
Property.ChangeContent modifies description, images and videos used to
display the property.

However, let's move the focus on behaviour away from the objects
themselves and shift it towards the set of business operations that
change their state. The addition of domain events to the DDD picture
is critically important. It makes the _occurence_ of these business
events a first class concept within the domain. Our domain now tells
us things like "this tenant has changed their backend configuration",
"this tenant has added a new property". This really enriches what
could otherwise be seen as an "anaemic" domain model.

There is a lot of value in making these events explicit, even for CRUD
scenarios, because they make things like auditing, updating read
models, starting workflows (sagas), integrating between other
systems / BCs so easy.

We don't have to have a domain model to do CQRS, e.g. controllers
could raise events before updating a code-generated LINQ2SQL entity.
However, to me it just makes sense for the domain model to be the
place where the events are raised.

Dan

Colin Jack

unread,
Apr 17, 2011, 1:04:50 PM4/17/11
to ddd...@googlegroups.com
Sure but you can easily publish events without using many of the other
practices.

Just reading this thread made me wonder if in some cases we're ending
up with complex solutions to simple problems.

Tom Janssens

unread,
Apr 18, 2011, 6:09:12 AM4/18/11
to ddd...@googlegroups.com
In the beginning I applied CQRS everywhere.
Now, I usually start without it, using POCO's/domain services/MVC, but I do respect command-query separation.
I try to group my command domain services by AR as much as possible.

An example:

 // every command procedure should only handle a single user
interface IUserCommand
{
   void RegisterUser(GUID userid,string username,string passwordhashcode,string salt)
}

public interface IQueries
{
   VMUserDashboard GetUserDashboard(GUID userid)
}
  
class UserController
   IUserCommands usercommands;
   IQueries queries;

   public UserController(IUserCommands usercommands,IQueries queries)
   {
      this.usercommands = usercommands;
      this.queries = queries;
   }

   ControllerResult Register(GUID userid,string username,string passwordhashcode,string salt)
   {
      usercommands.RegisterUser(userid,username,passwordhashcode,salt)
      return RedirectTo<UserController>(x=>x.ShowDashboard(userid))
   }

  ControllerResult ShowDashboard(Guid userid)
  {
     return View(queries.GetUserDashboard(userid));
  }
}

This is my personal approach to projects, you could consider it a distillation of full-blown CQRS with a focus on YAGNI & SRP.

It does not add a lot of overhead, and migrating this to the full-blown CQRS approach when necessary is a rather trivial exercise. In most cases I find that I really do not need full-blown CQRS.

I like CQRS because it leverages proper DDD, and IMHO this approach does provide something similar without the added overhead.

Chris Nicola

unread,
Apr 18, 2011, 8:00:47 PM4/18/11
to ddd...@googlegroups.com
+1 to this.  I think I'm basically discovering the same thing, perhaps full CQRS with event sourcing is a bit like REST that way.  You are generally never going to start out prototyping with a full REST api, but it's still good to be RESTful.


Reply all
Reply to author
Forward
0 new messages