You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@isis.apache.org by GESCONSULTOR - Óscar Bou <o....@gesconsultor.com> on 2013/07/03 16:10:41 UTC

Re: EventBusService ... opinions, please.

Excuse me for the delay in the response...

> With respect to Axon, I know you mentioned it before, and I took a look
> through its getting started guide.  There's rather a lot of boilerplate in
> there, which - I've always argued - is liable to slow down / inhibit the
> development of a ubiquitous language.  Since you use Axon, you can tell me
> if I'm mistaken in this or not.



The point with CQRS in general is that the Domain is first modeled through the Commands (Actions) that need to be available for the user's perspective, instead of through the Domain Entities "recognized" on the Domain. 
The only "properties" (state) added to those Entities is the ones needed for executing the commands in the proper context.

It requires to change one's mind. We've been applying it with a lot of confidence in some "technical" domains (such as systems monitoring) where the set of Commands (Actions) required is quite clear and those Domain Entities are not "so clear" (mainly technical or abstract concepts). Those Subdomains have strong requirements regarding Command execution scalability (as those commands can be dispatched by other systems).

Axon has really, really, really fast implementations for the Command Bus allowing the processing of thousands of events per second, so it's reallly good for those purposes. 

As is nearly always told on the CQRS community, on DDD some Subdomains can be implemented following CQRS, and some others following "traditional techniques".

For the "traditional" Subdomains directed towards "Business Users", we were using a "traditional" Hibernate-based approach (with custom automatic screen generation from the Domain Entities), and we are moving to Apache Isis and for now is working really well (still on development).
 
> I don't know that the CommandHandler stuff in Axon makes much sense from an
> Isis standpoint;

The Command Bus is just used for invoking Actions (i.e., dispatching Commands) on the context of an Aggregate Root. The steps could be:
1. "Declare" what you want to do by dispatching a Command (initialized with the information needed to identify the AggregatedRoot (AR) Entity and the action's params).
2. The Command Bus sends to a Command Handler (could be the same AR).
3. The AR is loaded from the repository by its id.
4. The AR processes the Command (executes the Action) invoking the proper method.
5. The changes made on the state of the AR are saved to the EventSourcing repository (and all defined Events informing about command execution, AR state changes, etc. are published).
---
6. Other Entities subscribed to those published Events can response by dispatching other Commands.


The fact here is that ALL the API consists only on:
1. Commands.
2. Events.
3. And an interface to work with the Command Bus (dispatching sync or async Commands) and the Event Bus (subscribing/unsubscribing to Events). 

Sure there are experts here that can give more details or correct me in any of this points.
 


On Apache Isis is used the traditional approach to:
1. Load the Entity from the repository.
2. Invoke a method on that Entity (or on a Service).

On those technical domains we have implemented with Axon, we are going to need an "Apache Isis Service" for dispatching Commands to the Axon Command Bus, and, probably, another one to handle subscriptions to the Axon's Event Bus.

The fact is that we are going to "transform" Service/Entity Actions to the proper Axon Commands through those Services.


If you want, we can provide them to the Apache Isis community. On that way, Apache Isis will also interact with CQRS Bounded Contexts, being (as far as I know) the only DDD framework to support it directly.

> Neither am I certain that an EventStore is the best
> persistence mechanism for the majority of enterprise apps that get built.

Me neither.

Think that with an Event Store, you only save the Event notifying a State change in an AR, not the "full state of the AR". 
In order to "reconstruct" the full state of the AR you need to "recreate" it from the latest snapshot (or the beginning of the times) and apply over it all changes that were saved after that snapshot. Axon can work with SQL and noSQL Event Stores, and can automatically create a snapshot each "x" events published.

The point here is that you should have Event Handlers subscribed to all those Events that would "update" the Query database (one or many) that can have each one, for example, de-normalized structures optimized for reporting or for OLAP.

All this makes CQRS a really optimized and scalable system for "executing commands". And that's its advantage.

For most enterprise apps is just "too much" engineering (one specialized database for storing events, one or more specialized databases for querying - generating the user interfaces, reports, etc.). If they are directed towards "Business Users" they cannot send Commands at the speeds where CQRS makes sense. But those "Business Users" have strong query requirements. So simply the "traditional approach" is just better for me.


Hope this helps,

Oscar






El 30/06/2013, a las 15:55, Dan Haywood <da...@haywood-associates.co.uk> escribió:

> Hi Oscar,
> Thanks for these references.
> 
> The key thing you said that's helped me was:
> 
>> All our Event Handlers are located on previously subscribed Services, so
> they will be in memory. If they need any Domain Object, they query the
> repositories on the event handler. Obviously, multiple Event Handlers can
> be registered for one kind of Event.
> 
> That to me seems like the correct solution... don't have individual
> entities subscribing to events, instead have the domain service(s) act as
> the subscriber.  As you say, when an event is received, have the service
> identify the impacted domain entities and then call them.  That's such an
> obvious approach I feel a bit embarrassed for going down the wrong path.
> 
> Anyway... I'm going to refactor the EventBusService and take out that
> subscriber loading/hint stuff.  And, then I'll implement a simplified
> version of the @PostsEvent annotation, also without the hint/loading stuff.
> 
> ~~~
> With respect to Axon, I know you mentioned it before, and I took a look
> through its getting started guide.  There's rather a lot of boilerplate in
> there, which - I've always argued - is liable to slow down / inhibit the
> development of a ubiquitous language.  Since you use Axon, you can tell me
> if I'm mistaken in this or not.
> 
> I don't know that the CommandHandler stuff in Axon makes much sense from an
> Isis standpoint; our RO viewer gives us something like that for free, I
> would've though.  Neither am I certain that an EventStore is the best
> persistence mechanism for the majority of enterprise apps that get built.
> But being able to raise events *does* make sense to me as a way of
> decoupling chunks of business logic; hence the EventBusService.
> 
> Cheers
> Dan
> 
> ~~~~
> On 30 June 2013 11:38, GESCONSULTOR - Óscar Bou <o....@gesconsultor.com>wrote:
> 
>> Opss!!! Let me resend it. The previous one did not contained the proper
>> links.
>> 
>> Just to clarify, when a Command has the @TargetAggregateIdentifier
>> annotation on one of its fields, the Command Bus will previously load that
>> Entity from the Repository and, after that, will invoke the command on that
>> Entity. More details on [2].
>> 
>> On the default implementation, the Domain Entity "identifier" field (which
>> must be compared against the @TargetAggregateIdentifier) is also annotated
>> with @AggregateIdentifier. The used Repository only needs a "findById"
>> method for locating it and dispatch the command (it's also possible to
>> query specifying also the expected "version", but this is out of scope).
>> 
>> 
>> Hope this helps again,
>> 
>> Oscar
>> 
>> 
>> 
>> ----
>> 
>> Hi, Dan.
>> 
>> I'm going to adopt your style of not mixing links with the post.
>> 
>> We are currently using as our Domain Event Bus one of the implementations
>> available on the Axon Framework [1].
>> 
>> As it's a CQRS framework, there is a difference between Command Handlers
>> and Event Handlers.
>> 
>> All our Event Handlers are located on previously subscribed Services, so
>> they will be in memory. If they need any Domain Object, they query the
>> repositories on the event handler. Obviously, multiple Event Handlers can
>> be registered for one kind of Event.
>> 
>> For Command Handlers, it's possible to pass a field which contains the
>> Aggregate Identifier (annotated with @TargetAggregateIdentifier), and also
>> to annotate as a @CommandHandler a constructor method (if the command's
>> responsibility is to create a Domain Entity). Note that only one Command
>> Handler can be registered for each kind of command. If more than one is
>> present, only the last one found will be notified by the Command Bus about
>> the Command dispatched (detailed info on [2]).
>> 
>> There is detailed documentation about Command Handlers [2] (including the
>> interface for sending Commands) and Event Handlers [3] (they cannot be
>> sent, just received) available.
>> 
>> There's a new quickstart tutorial on Axon with a small example based also
>> on a ToDo domain entity [4].
>> 
>> Hope this helps,
>> 
>> Oscar
>> 
>> 
>> 
>> [1] http://www.axonframework.org/
>> [2] http://www.axonframework.org/docs/2.0/command-handling.html
>> [3] http://www.axonframework.org/docs/2.0/event-processing.html
>> [4] http://www.axonframework.org/axon-2-quickstart-guide/
>> 
>> 
>> 
>> El 30/06/2013, a las 10:38, Dan Haywood <da...@haywood-associates.co.uk>
>> escribió:
>> 
>>> Folks,
>>> Looking for opinions here.
>>> 
>>> I recently committed an EventBusService, so that one can programmatically
>>> post an event via Guava's EventBus:
>>> 
>>> public void setStartDate(LocalDate dt) {
>>>  this.setStartDate = dt;
>>>  eventBusService.post(new StartDateChangedEvent(this, oldValue,
>>> newValue), getFoos(), getBars(), ...)
>>> }
>>> 
>>> Guava then invokes any object that has a method annotated @Subscribe
>>> accepting the event type:
>>> 
>>> @Subscribe
>>> public void handle(StartDateChangedEvent ev) { ... }
>>> 
>>> It's trivially easy for domain objects to register themselves with the
>>> event bus.  In their injectXxx method, just do the register:
>>> 
>>> public void injectEventBusService(EventBusService ebs) {
>>>  this.eventBusService = ebs;
>>>  ebs.register(this);
>>> }
>>> 
>>> 
>>> I'm reasonably happy with all of this, I think, though the downside is
>> that
>>> the publisher needs to ensure that any potential subscribers are
>> in-memory
>>> so that they get notified.  This is the purpose of the getFoos() and
>>> getBars() calls passed in to post(...); it's a hint for Isis to bring the
>>> objects in these collections into memory.
>>> 
>>> Also, strictly speaking, the publication of the event should be in
>>> modifyStartDate(...) rather than setStartDate(...) to avoid unintended
>>> side-effects with JDO when it calls setStartDate to recreate or delete
>> the
>>> object.  In fact, the JDO objectstore does protect against this, but it's
>>> all somewhat hacky.
>>> 
>>> 
>>> ~~~
>>> 
>>> I'm now thinking about introducing an annotation to publish the event,
>> eg:
>>> 
>>> @PostsEvent(type=StartDateChangedEvent.class, subscribers={"foos",
>> "bars"})
>>> public LocalDate getStartDate() { ... }
>>> public void setStartDate(LocalDate dt) { ... }
>>> 
>>> 
>>> where the "foos" and "bars" are - again - the collections of the
>> publishing
>>> object to be loaded into memory first.
>>> 
>>> Or, as a refinement:
>>> 
>>> @PostsEvent(type=StartDateChangedEvent.class,
>>> subscribersPolicy=StartDateSubscribersPolicy.class)
>>> public LocalDate getStartDate() { ... }
>>> public void setStartDate(LocalDate dt) { ... }
>>> 
>>> would allow a strategy object to be specified to allow arbitrary
>> subscriber
>>> objects to be loaded.
>>> 
>>> ~~~
>>> 
>>> I don't think any of this is too difficult to implement, but is it worth
>>> it?  Or is this subscriber loading hint basically telling me that the
>>> approach is fundamentally flawed?
>>> 
>>> Opinions welcome
>>> 
>>> Thx
>>> Dan
>> 
>> 


Re: EventBusService ... opinions, please.

Posted by Dan Haywood <da...@haywood-associates.co.uk>.
Thanks for this reply, Oscar.

It's interesting to me that you've used CQRS for the more technical
(sub)domains of your system, rather than the more business-oriented stuff.
 I shall mull on this.

Thx again
Dan



On 3 July 2013 15:10, GESCONSULTOR - Óscar Bou <o....@gesconsultor.com>wrote:

> Excuse me for the delay in the response...
>
> > With respect to Axon, I know you mentioned it before, and I took a look
> > through its getting started guide.  There's rather a lot of boilerplate
> in
> > there, which - I've always argued - is liable to slow down / inhibit the
> > development of a ubiquitous language.  Since you use Axon, you can tell
> me
> > if I'm mistaken in this or not.
>
>
>
> The point with CQRS in general is that the Domain is first modeled through
> the Commands (Actions) that need to be available for the user's
> perspective, instead of through the Domain Entities "recognized" on the
> Domain.
> The only "properties" (state) added to those Entities is the ones needed
> for executing the commands in the proper context.
>
> It requires to change one's mind. We've been applying it with a lot of
> confidence in some "technical" domains (such as systems monitoring) where
> the set of Commands (Actions) required is quite clear and those Domain
> Entities are not "so clear" (mainly technical or abstract concepts). Those
> Subdomains have strong requirements regarding Command execution scalability
> (as those commands can be dispatched by other systems).
>
> Axon has really, really, really fast implementations for the Command Bus
> allowing the processing of thousands of events per second, so it's reallly
> good for those purposes.
>
> As is nearly always told on the CQRS community, on DDD some Subdomains can
> be implemented following CQRS, and some others following "traditional
> techniques".
>
> For the "traditional" Subdomains directed towards "Business Users", we
> were using a "traditional" Hibernate-based approach (with custom automatic
> screen generation from the Domain Entities), and we are moving to Apache
> Isis and for now is working really well (still on development).
>
> > I don't know that the CommandHandler stuff in Axon makes much sense from
> an
> > Isis standpoint;
>
> The Command Bus is just used for invoking Actions (i.e., dispatching
> Commands) on the context of an Aggregate Root. The steps could be:
> 1. "Declare" what you want to do by dispatching a Command (initialized
> with the information needed to identify the AggregatedRoot (AR) Entity and
> the action's params).
> 2. The Command Bus sends to a Command Handler (could be the same AR).
> 3. The AR is loaded from the repository by its id.
> 4. The AR processes the Command (executes the Action) invoking the proper
> method.
> 5. The changes made on the state of the AR are saved to the EventSourcing
> repository (and all defined Events informing about command execution, AR
> state changes, etc. are published).
> ---
> 6. Other Entities subscribed to those published Events can response by
> dispatching other Commands.
>
>
> The fact here is that ALL the API consists only on:
> 1. Commands.
> 2. Events.
> 3. And an interface to work with the Command Bus (dispatching sync or
> async Commands) and the Event Bus (subscribing/unsubscribing to Events).
>
> Sure there are experts here that can give more details or correct me in
> any of this points.
>
>
>
> On Apache Isis is used the traditional approach to:
> 1. Load the Entity from the repository.
> 2. Invoke a method on that Entity (or on a Service).
>
> On those technical domains we have implemented with Axon, we are going to
> need an "Apache Isis Service" for dispatching Commands to the Axon Command
> Bus, and, probably, another one to handle subscriptions to the Axon's Event
> Bus.
>
> The fact is that we are going to "transform" Service/Entity Actions to the
> proper Axon Commands through those Services.
>
>
> If you want, we can provide them to the Apache Isis community. On that
> way, Apache Isis will also interact with CQRS Bounded Contexts, being (as
> far as I know) the only DDD framework to support it directly.
>
> > Neither am I certain that an EventStore is the best
> > persistence mechanism for the majority of enterprise apps that get built.
>
> Me neither.
>
> Think that with an Event Store, you only save the Event notifying a State
> change in an AR, not the "full state of the AR".
> In order to "reconstruct" the full state of the AR you need to "recreate"
> it from the latest snapshot (or the beginning of the times) and apply over
> it all changes that were saved after that snapshot. Axon can work with SQL
> and noSQL Event Stores, and can automatically create a snapshot each "x"
> events published.
>
> The point here is that you should have Event Handlers subscribed to all
> those Events that would "update" the Query database (one or many) that can
> have each one, for example, de-normalized structures optimized for
> reporting or for OLAP.
>
> All this makes CQRS a really optimized and scalable system for "executing
> commands". And that's its advantage.
>
> For most enterprise apps is just "too much" engineering (one specialized
> database for storing events, one or more specialized databases for querying
> - generating the user interfaces, reports, etc.). If they are directed
> towards "Business Users" they cannot send Commands at the speeds where CQRS
> makes sense. But those "Business Users" have strong query requirements. So
> simply the "traditional approach" is just better for me.
>
>
> Hope this helps,
>
> Oscar
>
>
>
>
>
>
> El 30/06/2013, a las 15:55, Dan Haywood <da...@haywood-associates.co.uk>
> escribió:
>
> > Hi Oscar,
> > Thanks for these references.
> >
> > The key thing you said that's helped me was:
> >
> >> All our Event Handlers are located on previously subscribed Services, so
> > they will be in memory. If they need any Domain Object, they query the
> > repositories on the event handler. Obviously, multiple Event Handlers can
> > be registered for one kind of Event.
> >
> > That to me seems like the correct solution... don't have individual
> > entities subscribing to events, instead have the domain service(s) act as
> > the subscriber.  As you say, when an event is received, have the service
> > identify the impacted domain entities and then call them.  That's such an
> > obvious approach I feel a bit embarrassed for going down the wrong path.
> >
> > Anyway... I'm going to refactor the EventBusService and take out that
> > subscriber loading/hint stuff.  And, then I'll implement a simplified
> > version of the @PostsEvent annotation, also without the hint/loading
> stuff.
> >
> > ~~~
> > With respect to Axon, I know you mentioned it before, and I took a look
> > through its getting started guide.  There's rather a lot of boilerplate
> in
> > there, which - I've always argued - is liable to slow down / inhibit the
> > development of a ubiquitous language.  Since you use Axon, you can tell
> me
> > if I'm mistaken in this or not.
> >
> > I don't know that the CommandHandler stuff in Axon makes much sense from
> an
> > Isis standpoint; our RO viewer gives us something like that for free, I
> > would've though.  Neither am I certain that an EventStore is the best
> > persistence mechanism for the majority of enterprise apps that get built.
> > But being able to raise events *does* make sense to me as a way of
> > decoupling chunks of business logic; hence the EventBusService.
> >
> > Cheers
> > Dan
> >
> > ~~~~
> > On 30 June 2013 11:38, GESCONSULTOR - Óscar Bou <o.bou@gesconsultor.com
> >wrote:
> >
> >> Opss!!! Let me resend it. The previous one did not contained the proper
> >> links.
> >>
> >> Just to clarify, when a Command has the @TargetAggregateIdentifier
> >> annotation on one of its fields, the Command Bus will previously load
> that
> >> Entity from the Repository and, after that, will invoke the command on
> that
> >> Entity. More details on [2].
> >>
> >> On the default implementation, the Domain Entity "identifier" field
> (which
> >> must be compared against the @TargetAggregateIdentifier) is also
> annotated
> >> with @AggregateIdentifier. The used Repository only needs a "findById"
> >> method for locating it and dispatch the command (it's also possible to
> >> query specifying also the expected "version", but this is out of scope).
> >>
> >>
> >> Hope this helps again,
> >>
> >> Oscar
> >>
> >>
> >>
> >> ----
> >>
> >> Hi, Dan.
> >>
> >> I'm going to adopt your style of not mixing links with the post.
> >>
> >> We are currently using as our Domain Event Bus one of the
> implementations
> >> available on the Axon Framework [1].
> >>
> >> As it's a CQRS framework, there is a difference between Command Handlers
> >> and Event Handlers.
> >>
> >> All our Event Handlers are located on previously subscribed Services, so
> >> they will be in memory. If they need any Domain Object, they query the
> >> repositories on the event handler. Obviously, multiple Event Handlers
> can
> >> be registered for one kind of Event.
> >>
> >> For Command Handlers, it's possible to pass a field which contains the
> >> Aggregate Identifier (annotated with @TargetAggregateIdentifier), and
> also
> >> to annotate as a @CommandHandler a constructor method (if the command's
> >> responsibility is to create a Domain Entity). Note that only one Command
> >> Handler can be registered for each kind of command. If more than one is
> >> present, only the last one found will be notified by the Command Bus
> about
> >> the Command dispatched (detailed info on [2]).
> >>
> >> There is detailed documentation about Command Handlers [2] (including
> the
> >> interface for sending Commands) and Event Handlers [3] (they cannot be
> >> sent, just received) available.
> >>
> >> There's a new quickstart tutorial on Axon with a small example based
> also
> >> on a ToDo domain entity [4].
> >>
> >> Hope this helps,
> >>
> >> Oscar
> >>
> >>
> >>
> >> [1] http://www.axonframework.org/
> >> [2] http://www.axonframework.org/docs/2.0/command-handling.html
> >> [3] http://www.axonframework.org/docs/2.0/event-processing.html
> >> [4] http://www.axonframework.org/axon-2-quickstart-guide/
> >>
> >>
> >>
> >> El 30/06/2013, a las 10:38, Dan Haywood <da...@haywood-associates.co.uk>
> >> escribió:
> >>
> >>> Folks,
> >>> Looking for opinions here.
> >>>
> >>> I recently committed an EventBusService, so that one can
> programmatically
> >>> post an event via Guava's EventBus:
> >>>
> >>> public void setStartDate(LocalDate dt) {
> >>>  this.setStartDate = dt;
> >>>  eventBusService.post(new StartDateChangedEvent(this, oldValue,
> >>> newValue), getFoos(), getBars(), ...)
> >>> }
> >>>
> >>> Guava then invokes any object that has a method annotated @Subscribe
> >>> accepting the event type:
> >>>
> >>> @Subscribe
> >>> public void handle(StartDateChangedEvent ev) { ... }
> >>>
> >>> It's trivially easy for domain objects to register themselves with the
> >>> event bus.  In their injectXxx method, just do the register:
> >>>
> >>> public void injectEventBusService(EventBusService ebs) {
> >>>  this.eventBusService = ebs;
> >>>  ebs.register(this);
> >>> }
> >>>
> >>>
> >>> I'm reasonably happy with all of this, I think, though the downside is
> >> that
> >>> the publisher needs to ensure that any potential subscribers are
> >> in-memory
> >>> so that they get notified.  This is the purpose of the getFoos() and
> >>> getBars() calls passed in to post(...); it's a hint for Isis to bring
> the
> >>> objects in these collections into memory.
> >>>
> >>> Also, strictly speaking, the publication of the event should be in
> >>> modifyStartDate(...) rather than setStartDate(...) to avoid unintended
> >>> side-effects with JDO when it calls setStartDate to recreate or delete
> >> the
> >>> object.  In fact, the JDO objectstore does protect against this, but
> it's
> >>> all somewhat hacky.
> >>>
> >>>
> >>> ~~~
> >>>
> >>> I'm now thinking about introducing an annotation to publish the event,
> >> eg:
> >>>
> >>> @PostsEvent(type=StartDateChangedEvent.class, subscribers={"foos",
> >> "bars"})
> >>> public LocalDate getStartDate() { ... }
> >>> public void setStartDate(LocalDate dt) { ... }
> >>>
> >>>
> >>> where the "foos" and "bars" are - again - the collections of the
> >> publishing
> >>> object to be loaded into memory first.
> >>>
> >>> Or, as a refinement:
> >>>
> >>> @PostsEvent(type=StartDateChangedEvent.class,
> >>> subscribersPolicy=StartDateSubscribersPolicy.class)
> >>> public LocalDate getStartDate() { ... }
> >>> public void setStartDate(LocalDate dt) { ... }
> >>>
> >>> would allow a strategy object to be specified to allow arbitrary
> >> subscriber
> >>> objects to be loaded.
> >>>
> >>> ~~~
> >>>
> >>> I don't think any of this is too difficult to implement, but is it
> worth
> >>> it?  Or is this subscriber loading hint basically telling me that the
> >>> approach is fundamentally flawed?
> >>>
> >>> Opinions welcome
> >>>
> >>> Thx
> >>> Dan
> >>
> >>
>
>