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 <[email protected]>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 <[email protected]>
> 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 <[email protected]
> >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 <[email protected]>
> >> 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
> >>
> >>
>
>

Reply via email to