Guidance on updating the read model

540 views
Skip to first unread message

Franck

unread,
Nov 12, 2012, 1:17:19 PM11/12/12
to ddd...@googlegroups.com
I'm in the process of writing a little application using CQRS to play with the concepts and learn it. I'm not using event sourcing as I want to start slow and grasp what this is all about.

I've written my domain model and put a great deal of effort to try and make all of my members private so to push myself to think about behaviors rather than public properties (tell don't ask stuff). I listed some behaviors associated with that model and I've also written the command used to "trigger" that behavior.

I have a command named "CreateScheduleCommand" which not so surprisingly creates a schedule. Now in an event sourced world something would, at the end of the command, gather all the chances and publish them to who ever is listening, and I assume someone's job would be to update the read model associated with the affected domain model. But now, not using event sourcing and not having public properties, I can't access the changed properties of the domain model being updated or created, to update the read model. My command returns void so what I did was that the command dispatcher calls "Handle" on the handler and passes a continuation, and that continuation is an action taking the processed domain model as a parameter so that the dispatcher can play with it after the command has finished doing his business. What I had in mind was that the dispatcher could then "resolve" a "IDenormalizer<TCommand>" which would know what to do to update the read model of the domain model being modified.

So I guess my question is:

- Is this a good idea? (if not, how to update the read model in a non-event-source world?)
- Would it be a good idea to put my fields public so that the denormalizer can see them? (I had also thought about passing a DTO instead of the real domain object in the continuation, but then again, how to iniutialize the DTO if all the fields are private?)

here is a little bit of code some people know what I'm talking about:

        public void Dispatch<T>(T command) where T : ICommand
        {
            // TODO wrap within transaction
            // TODO add a OnError callback

            var handler = _container.Resolve<ICommandHandler<T>>();
            try
            {
                handler.Handle(command, new Just<Action<object>>(o =>
                    {
                        // do stuff, get denormalizer for object and update read model
                    }));
            }
            catch (Exception ex)
            {
                // TODO do stuff
            }
        }

        public void Handle(CreateScheduleCommand command, Maybe<Action<object>> continuation)
        {
            // inserting in persistence store
            continuation.Do<Action<object>>(c =>
                {
                    //var schedule = new Schedule(command.Name, command.StartDateTime, command.EndDateTime);
                    c(new ScheduleDto()
                        {
                            Id = id,
                            Name = command.Name,
                            StartTime = command.StartDateTime,
                            EndTime = command.EndDateTime
                        });
                });
        }

I'm also populating the DTO from the command itself and I don't really like that idea... but since all my fields are private...

Phil

unread,
Nov 12, 2012, 2:12:14 PM11/12/12
to ddd...@googlegroups.com
  Why not publish the event just so you can handle it.  The "Event Sourcing" part is only about storing the events for replay (I think).  If you at least publish the event you can write event handlers to write your projections.
  That also makes it nice if in the future you decide to store the events and use event sourcing.

Phil
--
Phil

Thomas Tomanek

unread,
Nov 13, 2012, 12:03:15 PM11/13/12
to ddd...@googlegroups.com
I agree with Phil - having your domain objects publish events doesn't mean you're  using event sourcing. All you're doing is capturing a state change and using it to notify interested parites. What I really love about my domain objects is that they're strictly commands in -> events out, with all state completely encapsulated.

You could publish events using the approach you've outlined above  (as far as I understand it) from the handler, but a potential problem is that your handler arguably shouldn't know what events are relevant - that's the domain object's business. My handlers are generally pretty dumb, they just take the command, rehydrate the domain object from a repository, and apply it said object. You could always have a domain object publish events onto some sort of memory bus to be picked up by event handlers that pass the events onto denormalizers.

Cheers,
Thomas

Franck

unread,
Nov 13, 2012, 1:48:53 PM11/13/12
to ddd...@googlegroups.com
I agree that I could introduce the concept of keeping changes within my domain and some "GetChanges" method to retreive those changes. I didn`t what to do it by fear of having to introduce an event bus and event handlers and all that jazz. Also, should I create denormilazers per command or per event? I fail to find a downside of having one per command since you should be able to know what do update knowing the command. I guess that in the traditional CQRS, the projections don`t have a clue about what a command is.

It is the command dispatcher which than have the reponsability of getting the denormalizer for the command being executed and not the command handler. The command handler only calls the continuation with the object being changed. But the more I read your answers the less I think it`s a good design.

Greg Young

unread,
Nov 13, 2012, 4:25:42 PM11/13/12
to ddd...@googlegroups.com
event bus and "all that jazz"? For the simplest thing its < 20 loc
(see simplecqrs)
--
Le doute n'est pas une condition agréable, mais la certitude est absurde.

Phil

unread,
Nov 13, 2012, 4:57:24 PM11/13/12
to ddd...@googlegroups.com
I agree.  The SimpleCQRS memory event bus is sweet and totally simple to use.  I have used it. I am also recommending the event bus from the MS CQRS journey here.  It is marginally more complicated, but I have found it to be very easy to use as well.

  Admittedly, I am pretty dense. Using a memory based command bus, event bus and event store really helped me understand the system as a whole.  I tried what you are doing(i.e. add only a command bus), but it totally changed how I developed my aggregates for the worse.

I hope this helps.

Cheers 
Phil
--
Phil

Reply all
Reply to author
Forward
0 new messages