#1 2015-05-06 10:12:26

willo
Member
From: Cape Town, South Africa
Registered: 2014-11-15
Posts: 67
Website

Implementing Event Sourcing and CQRS using mORMot

Hi Ab,

Event Sourcing has been on the road map for a while now. I'm wondering how mORMot can help in implementing these patterns at this stage?

Offline

#2 2015-05-06 17:14:40

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,655
Website

Re: Implementing Event Sourcing and CQRS using mORMot

We have almost everything needed.

CQRS may be easily implemented:
- at SOA level, see http://synopse.info/files/html/api-1.18 … ICQRSQUERY - and also http://synopse.info/files/html/Synopse% … #TITLE_400
- at ORM level, using http://synopse.info/files/html/Synopse% … l#TITL_147

Event Source may be implemented easily with SOA interfaces, and their callbacks.
See http://synopse.info/files/html/Synopse% … l#TITL_150
and https://github.com/synopse/mORMot/tree/ … WebSockets

Offline

#3 2015-05-07 10:37:34

willo
Member
From: Cape Town, South Africa
Registered: 2014-11-15
Posts: 67
Website

Re: Implementing Event Sourcing and CQRS using mORMot

The CQRS stuff, seems great!

In terms of Event Source, I'm more concerned with assistance the ORM can provide in persisting the various events, snapshotting and providing general assistance managing the Event Log, as described here: https://github.com/eventstore/eventstor … ing-Basics

Offline

#4 2015-05-07 11:05:09

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,655
Website

Re: Implementing Event Sourcing and CQRS using mORMot

The pattern of event stores is exactly what master/slave replication allows.
You define a dedicated event-oriented ORM table on the server, then any slave can subscribe to it.
When the main process takes place, some events are dispatched using services, then the dedicated event-oriented ORM table is updated on the server side.
Then, each slave (i.e. each event processing node), will receive all the events, in the form of event-oriented ORM table.
Using the master/slave replication, you can optionally raise callbacks on the client side, for each incoming notification of the event-oriented ORM table.

The main point here is that you create an event store on the server (in a DB or in memory), then use the ORM synchronization feature to propagate the events.
These event-oriented ORM tables are not the same than the main ORM tables, used to persist the actual DDD aggregates.
IMHO this may be a mistake, especially in the DDD/Fowler's perspective, to use the main ORM tables for event sourcing.
Events should NOT be linked to actual persistence details.
Events may come from, and be translated into, persisted objects - but this is not part of the event itself.

In practice, I do not like how events are implemented in all those documentation.
They all define events as objects.
In fact, classical events object are messages, in those implementations.
Event Driven code following this approach is easily bloated and difficult to follow - especially in C# or Java, when you commonly have a single class per file...

In mORMot, the SOA approach for events can be diverse.
Thanks to the interface-based callbacks, there is no need to define one object per event: in fact each event is an interface method. The method parameters replace the object properties.
You could consume the events outside your object boundaries, since you would be able to communication via plain JSON objects, mapping the method parameters.

Offline

#5 2015-05-27 11:22:54

willo
Member
From: Cape Town, South Africa
Registered: 2014-11-15
Posts: 67
Website

Re: Implementing Event Sourcing and CQRS using mORMot

Hi Ab,

Going through your updated documentation on DDD and implementing CQRS, I'm curios why you implemented your IDomUserQuery they way you did.

Wouldn't it be easier/simpler to have:

 IDomUserQuery = interface(ICQRSService)
    ['{198C01D6-5189-4B74-AAF4-C322237D7D53}']
    function SelectByLogonName(const aLogonName: RawUTF8; out aAggregate: TUser): TCQRSResult;
    function SelectByEmailValidation(aValidationState: TDomUserEmailValidation; out aAggregate: TUser): TCQRSResult;
    function SelectByLastName(const aName: TLastName; aStartWith: boolean; out aAggregates: TUserObjArray): TCQRSResult;
    function GetAll(out aAggregates: TUserObjArray): TCQRSResult;
    function GetCount: integer;
    function HowManyValidatedEmail: integer;
  end;

Offline

#6 2015-05-27 11:35:29

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,655
Website

Re: Implementing Event Sourcing and CQRS using mORMot

Because you may Select an aggregate without retrieving it, e.g. for deletion.
You run SelectByLogonName + Delete methods.
Or you run SelectByLogonName + Get method + Update method.
Or you run SelectByLogonName + Update method, with no Get.

The method names should do what they mean.
So if you modify the SelectByLogonName() to return TUser, IMHO you should rename them as GetByLogonName() e.g.
I do not have any particular problem about adding a GetByLogonName() method.

Offline

#7 2015-05-27 12:05:21

willo
Member
From: Cape Town, South Africa
Registered: 2014-11-15
Posts: 67
Website

Re: Implementing Event Sourcing and CQRS using mORMot

Okay, thanks.

Offline

Board footer

Powered by FluxBB