First of all: this particular handler is just an example of
implementation of certain class of problems.
Other handlers presents approach to other problem classes - they
covers problems You have mentioned.
So let's explain problems and decisions that are behind this particular class:
> Hi,
> the following questions trouble me after analysing code of
> SubmitOrderCommandHandler
>
> 1) The handler contains business logic:
>
> Specification<Order> orderSpecification =
> generateSpecification(systemUser);
> if (! orderSpecification.isSatisfiedBy(order))
> throw new OrderOperationException("Order does not meet
> specification", order.getEntityId());
First we must agree about definition of business vs application logic.
My understanding of the app. logic is: domain orchestration in the
meaning of Use Case/User story modeling. App logic contains also
technical stuff like security and transactions which are Aspect
Advices in this impl.
So this class models the following Use Case:
If Order meets Specification than submit it and issue and Invoice.
We must consider 3 important aspects (not AOP:)
1. "shape" of the Specification tree may depend on not only Business
logic, but also application stuff (logged user, system preferences
etc). So I don't want this concept to be hidden inside domain. I want
to manifest it *explicitly* in Use Case model (app. layer classes)
2. Issuing an Invoice may also depend on application (not domain)
stuff, ex: if system in in PremumMode that automatically issue an
Invoice. Of course this application logic could be implemented in
different way, for example registering or not listeners. But if it
depends on User System Prefernces (user checked "i would like to
generate invoices") that it is problematic.
3. Submitting Order may be one separate Use Case but submitting Order
and issuing Invoice can be another totally separated Use Case. So
let's assume that this class models second Use Case.
And I mean Use Case not just for example checking checbkox on gui and
sending boolean in command:P
> Why this code is not part of Aggregate Root (Order.submit method)?
Actually acceptable could be:
Order.submit(Validator)
there Specification is a validator.
This model would explicitly express that there is a validation
involved in this process.
I don't want to be misunderstood. The best case would be Order.submit
and hiding validation - as You suggest. If case is simple I would
definitely go this way.
But in this particular example We wanted to present something not so
simple and obvious. Considering that Specification creation is
Application (not only Domain) specific we need to go this compromise.
> 2) The same handler (SubmitOrderCommandHandler) after invoking submit method
> on Order AR invokes InvoicingService:
>
> order.submit();
> invoicingService.issuance(order, taxPolicy);
>
> This invocation sequence is also business logic concept and therefore should
> not be part of CommandHandler.
Wrong assumption about level of the logic:P
As explained before. In this example this is not a business but
application (Use Case) logic.
I assume that requirements are not so simple. Sometimes (certain UC)
when submitting Order we need an Invoice, sometimes (another UC) we
don't.
> Why submitting Order and invoicing is
> executed in the same transaction? Those business activities should rather be
> decoupled and the whole process should be eventually consistent instead of
> atomicaly. Possibly both activities should be composed into business process
> (saga). Going further, invoicing might be part of different bounded context
> than ordering (?).
1. Assumption about consistency in this particular example was different.
Let's assume that requirement is "whole process should be consistent".
Let's assume that client says: "If invoicing crashes than rollback
order submission; I demand that and I now what I'm talking about
because I pay".
2. Assumption about BC in this particular example was different.
We can assume that It's all about sales, so one Domain Expert can
grasp it easily.
> My assumption is that DDD/CQRS Leaven project should promote architecture
> and patterns that help handle complex business scenarios and build scalable
> systems.
You are right.
I don't want to be misunderstood.
This particular class presents a very specific Use Case: we must
operate on several Aggregates from the same BC in the consistent way.
All stuff You are writing about (different BCs, Sagas, eventually
consistency) are presented in another places in the code.
We just wanted do go beyond mainstream (mainstream in the CqRS scope;)
buzz and face real problems.
I know that in some domains (trading maybe?) there is at max dozen
aggregate types and millions of events per each instance.
But for example in Hospital Information Systems (kind of ERP for
medical market) there are hundreds of aggregate types and at max dozen
of events per each instance.
But in HIS class systems I want to: 'apply radiation treatment' AND
'apply specific medicine' in consistent way. Doing only one will kill
a human being so nobody cares about "enormous" complexity (2
aggregates in 1 tx;) or scalability (so much).
But as mentioned before: issues You have mentioned may be extremely
important in other contexts, therefore we provided more samples.
First we must agree about definition of business vs application logic.
My understanding of the app. logic is: domain orchestration in the
meaning of Use Case/User story modeling.
App logic contains also
technical stuff like security and transactions which are Aspect
Advices in this impl.
So this class models the following Use Case:
If Order meets Specification than submit it and issue and Invoice.We must consider 3 important aspects (not AOP:)
1. "shape" of the Specification tree may depend on not only Business
logic, but also application stuff (logged user, system preferences
etc). So I don't want this concept to be hidden inside domain. I want
to manifest it *explicitly* in Use Case model (app. layer classes)
2. Issuing an Invoice may also depend on application (not domain)
stuff, ex: if system in in PremumMode that automatically issue an
Invoice. Of course this application logic could be implemented in
different way, for example registering or not listeners.
But if it
depends on User System Prefernces (user checked "i would like to
generate invoices") that it is problematic.
3. Submitting Order may be one separate Use Case but submitting Order
and issuing Invoice can be another totally separated Use Case.
I don't want to be misunderstood. The best case would be Order.submit
and hiding validation - as You suggest. If case is simple I would
definitely go this way.
But in this particular example We wanted to present something not so
simple and obvious. Considering that Specification creation is
Application (not only Domain) specific we need to go this compromise.
> Why submitting Order and invoicing is
> executed in the same transaction? Those business activities should rather be
> decoupled and the whole process should be eventually consistent instead of
> atomicaly. Possibly both activities should be composed into business process
> (saga). Going further, invoicing might be part of different bounded context
> than ordering (?).1. Assumption about consistency in this particular example was different.
Let's assume that requirement is "whole process should be consistent".
Let's assume that client says: "If invoicing crashes than rollback
order submission; I demand that and I now what I'm talking about
because I pay".
But in HIS class systems I want to: 'apply radiation treatment' AND
'apply specific medicine' in consistent way. Doing only one will kill
a human being so nobody cares about "enormous" complexity (2
aggregates in 1 tx;) or scalability (so much).
I'll remind just to not confuse other readers, that We dare discussing
here specific case.
>> First we must agree about definition of business vs application logic.
>> My understanding of the app. logic is: domain orchestration in the
>> meaning of Use Case/User story modeling.
>
> In my opinion what you are describing as application logic is in fact
> description of business process.
> Business processes should be modeled explicitily (as Sagas)
Yes, in general we can say that we are dealing with Business Process -
lets define it for purpose of this sample as something that
orchestrates Use Cases.
I agree that BP (same as UC) should be modeled explicitly, somehow.
//If not modeling something that should be modeled we are asking for troubles:)
So how to model BP? We have BP engines, we can do it "by hand" or use
Saga (which is very cool, but people have created tons of software
before even knowing about Sagas, so it should be possible without
using Saga - which is cool).
And indeed there is sample of the long process modeled by saga that
involves payment and shipping.
As mentioned before: submitting Order and issuing an Invoice is just a
sample of the UC (lets say step in BC) that need to be atomic. I guess
that in reap ERP this two activities does not have to be atomic, but
this is just a sample of the technical stuff.
So if invoicing focuses our mind on real world, that lets move to
abstract space: requirement is: Aggregate A and B need to be modified
in consistent way; and someone may ask how to implement this.
>> App logic contains also
>> technical stuff like security and transactions which are Aspect
>> Advices in this impl.
>
> Right.
> But saga could handle special requirements for transactions (if necessary) ,
> I suppose..
hmmm
Saga is event driven. If event is handled asynchronously that
listeners need to call some fixing procedure on the event originator
in case of error.
Could be easier when evens are handler synchronously, but than we
loose scalability (still having decoupling).
The simplest working solution in this case is classic "domain script":
do something with Aggregate A and B.
What could we gain when introducing Sagas? Many sexi things... do we
need them? Depends...
Once again: just a sample of specific class of the problem.
>>
>> So this class models the following Use Case:
>> If Order meets Specification than submit it and issue and Invoice.
>>
>> We must consider 3 important aspects (not AOP:)
>> 1. "shape" of the Specification tree may depend on not only Business
>> logic, but also application stuff (logged user, system preferences
>> etc). So I don't want this concept to be hidden inside domain. I want
>> to manifest it *explicitly* in Use Case model (app. layer classes)
>
> Logged User is an actor in the process. It is the user that is associated
> with the business process instance (saga instance).
> If business process definition varies depending on system environment (like
> premium mode) than different process definitions (saga classes) should be
> deployed on each system.
Ok I agree. In this scenarios needed information about whether issue
an invoice or not can be fetched in Saga or while creating special
Saga.
Problem would be in even simpler case:
User clicks button "submit order" xor "submit order and issue an invoice".
Client tier generates command (command can have boolean switcher or we
can have 2 commands).
Handler submits Order. Order generates event. Where to pass an
information that user wants or not to issue an invoice? Only place is
OrderSubmittedEvent.
So Order.submit need to have parameter that pass this intention. But
we don't want Order to know about Invoice:P
Don't get me wrong. I think Sagas are great and eyes-opening models,
but in this particular sample there is still one requirement:
consistency.
>> I don't want to be misunderstood. The best case would be Order.submit
>> and hiding validation - as You suggest. If case is simple I would
>> definitely go this way.
>> But in this particular example We wanted to present something not so
>> simple and obvious. Considering that Specification creation is
>> Application (not only Domain) specific we need to go this compromise.
>>
>>
> I would say that this logic (specification creation and validation) should
> be placed inside business process (saga). The process is started with
> Order creation. Before order enters Submitted state, validation must be
> performed. Order.submit(specification) makes sense to me.
I'm not sure if I grasp idea, but do You suggest that validation
should be performed in Saga "event listener" method? Therefore in
asynchronous way?
But what if in this special case we need to validate synchronously -
when users performs action, not few minutes later and in case of error
send email (as some rock star conference speakers suggest);P
Just in this particular case sending email "sorry for killing You by
applying radiation treatment and not applying chemical recovery pills"
is not acceptable.
>>
>> > Why submitting Order and invoicing is
>> > executed in the same transaction? Those business activities should
>> > rather be
>> > decoupled and the whole process should be eventually consistent instead
>> > of
>> > atomicaly. Possibly both activities should be composed into business
>> > process
>> > (saga). Going further, invoicing might be part of different bounded
>> > context
>> > than ordering (?).
>>
>> 1. Assumption about consistency in this particular example was different.
>> Let's assume that requirement is "whole process should be consistent".
>> Let's assume that client says: "If invoicing crashes than rollback
>> order submission; I demand that and I now what I'm talking about
>> because I pay".
>
> If so, we should talk more with the client about what he really wants :)
Yea... The Udi's Way:)
I like this way, but engineering is not about liking:P
Ok, I agree that this consideration should be made, this kind of
questions should be asked.
But this sample presents implementation of the case when client claims
he needs consistency.
>> But in HIS class systems I want to: 'apply radiation treatment' AND
>> 'apply specific medicine' in consistent way. Doing only one will kill
>> a human being so nobody cares about "enormous" complexity (2
>> aggregates in 1 tx;) or scalability (so much).
>
> So maybe CQRS is not suitable for those kind of systems :P
Separating responsibility of the code into two parts suits this kind
of systems and imho most of the business systems in general.
But Events, Sagas, Event Sourcing, eventual consistency - cool tools
that solves hard problems (may introduce other) suits some context
more, some contexts less - that's all about this sample handler is.
> I would say that this logic (specification creation and validation) should
> be placed inside business process (saga). The process is started with
> Order creation. Before order enters Submitted state, validation must be
> performed. Order.submit(specification) makes sense to me.I'm not sure if I grasp idea, but do You suggest that validation
should be performed in Saga "event listener" method? Therefore in
asynchronous way?
This needs clarification...
1. Saga sends commands. Ok. We have API somewhere (set of possible
Commands) and saga can send it. Those commands are API so they can be
potentially sent also by GUI. I think thats ok in general. But
sometimes we would like to reserve some commands to be sent only by
Sagas (but its technical problem of visibility).
But in general is saga need to do sht on the model is should be
encapsulated in app. layer and called via commands.
2. Sega need to decide when to sends commands. For example if certain
events come to Saga, that Saga decides it need to send a command.
So we have some process logic.
More: Saga may send different command depending of events data.
So I don't exactly know what do You mean by "only send commands". Just
a Router that maps events to new commands? If so than it is not
needed. It would be sufficient to install more listeners and skip this
"layer".
What I mean that Saga need to contain some process logic which may be
very heavy business logic - to be able to decide that and hen should
be done.
So If command models Use Case step, than Saga models Business Process
- we agreed about that before. But process definition may require some
logic.
> Let me present possible solution
> (just for fun:), I understand your points about specific requirements that
> original solution addresses).
> OK, so we have to model Order submission and validation and we are allowed
> to do it asynchronously.
> What we need is to enrich Order lifecycle with following states: CREATED,
> SUBMITTED, REJECTED, APPROVED. Than we can build the following process:
> User -> CreateOrderCommand -> Order (status = CREATED) -> OrderCreatedEvent
> -> OrderSaga started
> User -> SubmitOrderCommand -> Order (status = SUBMITTED) ->
> OrderSubmittedEvent
> OrderSaga -> ValidateOrderCommand -> just rough idea (OrderValidationService
> is called, it creates Specification and invokes
> Order.validate(specification)) (status = APPROVED or REJECTED) ->
> Order(Approved|Rejected)Event
That process looks ok, but we must be aware of the very special
approach/style of modeling.
Change of the mindset is to introduce more granular lifecycle:
Actor expressed an intention that he want to submit Order (status = SUBMITTED)
We simply accept that fact, note it in the system and... done:)
This style of modeling is must have if next step is for example long
running activity (needs human action or long computations or
delayed/batch computations)
But I can bet that it would be possible to validate Order immediately
(relatively fast), client would choose synchronous impl and
"smaller"/more automated lifecycle:P
Bout on the other hand, form the architectural point of view: we may
want to build set of "components", "driven" by commands (keep them as
general as possible, so for example validation can be optional) and
than add value by building Sagas on the top of those "components".
> Communicating failed validation inside domain (REJECTED/APPROVED state)
> solves problem with handling exception as discussed here:
> https://groups.google.com/forum/#!topic/dddcqrs/hDpttk4wNuk/discussion
>
> To be honest, I have no experience with modelling business processes with
> Sagas. I would like to see some more complex processes designed as Sagas.
> There are only trivial examples on the web.
Yes, thats the basic problem with all new "toys". We struggle to
understand how and when to use them. On the web there are mostly
"hello world" masturbation samples;)
I think that proper Saga usage can be inspired by Business Process
modeling discipline which (as some claims) can be generalized to
events sending and handling.
> Thanks for discussion!
I would like to thank a lot also. Very productive discussion.
This needs clarification...
What I mean that Saga need to contain some process logic which may be
very heavy business logic - to be able to decide that and hen should
be done.
So I don't exactly know what do You mean by "only send commands". Just
a Router that maps events to new commands? If so than it is not
needed. It would be sufficient to install more listeners and skip this
"layer".
>
> OrderSaga -> ValidateOrderCommand -> just rough idea (OrderValidationService
> is called, it creates Specification and invokes
> Order.validate(specification)) (status = APPROVED or REJECTED) ->
> Order(Approved|Rejected)Event
This style of modeling is must have if next step is for example longrunning activity (needs human action or long computations or
delayed/batch computations)
I think that proper Saga usage can be inspired by Business Processmodeling discipline which (as some claims) can be generalized to
events sending and handling.
In general I can agree with that.
But because in personal I don't like fascist statements I must ask: "why".
Lets Image that we have 3 "components" driven by commands: A, B, C.
Now I want to "add new value" by building few Sagas above them.
Not one, but few Sagas that differ in details of orchestration
(conditions of the flow).
So I can do it in 2 completely different "styles":
1. Keep components' API as general as possible, therefore I need to
have some logic inside Saga
2. Keep Saga clean, therefore I need to make component's API more
specialized to be able to fulfill
First approach lets You (theoretically;) to add many new Sagas without
touching API.
So if we decide what we want to achieve - or what is possible (is API
modification always possible?) - that we can make architectural
assumptions about responsibility of each Building Block.
> - Sagas should not have logic inside of them (business part of the logic).
> What they have is more like routing logic. What they are doing is they are
> routing information so the information ends up in the right place at the
> right time so the right person can make the decision. Choreographing or
> Orchestrating information instead of 'Command and Control man' in the
> middle. Much of the logic should not belong to saga but to the other places.
OK, that exactly how I understand Saga.
But
how to determine when is the "right time" and what is the "right place"?
Lets assume that in our example the right time to command Warehouse
to send a Package is when all Payments (may be few) plus current
Overpaid is higher than total cost of the Order.
How to model that?
1. We can model some "cashier" component, Saga could send him events,
and cashier could send in proper time an event "AllIsPaid"
Thats possible if we can introduce new components each time we model new Saga.
but...
what is the sens of having such a anemic/routing Saga which just
translates events to commands?
In general what is the purpose of introducing new layer? Introducing
new mental value. But if its just about routing that Events Engine
does the job. If routing in Saga is so simple that each event causes
new Command with no IFs, than proper Listeners would be sufficient and
we don't need to introduce all this sophisticated Sagas machinery.
> - Ideally we don't want our Saga to have any form of memory. We can move
> state out of the saga. (one solution Greg presents is to use memento pattern
Yes, if Saga need to make decision about "when is the proper time"
than it needs state (Memento is very smart way of doing it).
> the state of the process (if required) could be derived from associated domain entity (Order) in this case
nah, I don't like the idea of polluting domain model by process model
- domain should be independent of process, because there may be many
processes that involves the same domain model.
but...
I think now I get Your point... point of all this discussion. At all
makes perfect sense if we assume that process is just a imperative
code, but no sate - process sate is natural property of the domain.
I makes sense as a coherent way of thinking but as mentioned above - I
just don't like it:P
>> This style of modeling is must have if next step is for example long
>>
>> running activity (needs human action or long computations or
>> delayed/batch computations)
>
> or (if building distributed system) you want to be able accept Orders even
> is they can not be validated immediately (because validation service is
> down)
I thing that now we have touched a real context where this
approach/style is simply a killer:)
Distribution is the force that drives design in some way and we are
ready to make come compromises/devotion.
>> I think that proper Saga usage can be inspired by Business Process
>>
>> modeling discipline which (as some claims) can be generalized to
>> events sending and handling.
>
> Yes, I think the missing puzzle is to realize that Sagas can be modeled as
> state machines, similarly as we model processes using
> bpm engines (see:
> http://processdevelopments.blogspot.com/2007/05/therapy-for-bpm.html)
>
> Example of using state machine with Saga can be found here:
> http://blog.jonathanoliver.com/2010/09/cqrs-sagas-with-event-sourcing-part-i-of-ii/
> and here:
> http://blog.jonathanoliver.com/2010/09/cqrs-sagas-with-event-sourcing-part-i-of-ii/
>
> IMHO even this simple saga:
> http://code.google.com/p/ddd-cqrs-sample/source/browse/trunk/ddd_cqrs-sample/src/main/java/pl/com/bottega/erp/sales/saga/OrderShipmentStatusTrackerSaga.java
> could benefit from applying state machine in the background (I'm thinking of
> implementing alternative version :) ) Only then you can avoid writing IF
> statements in the saga code :)
>
> And thanks once more for stimulating me to think more about all of this :)
>
Thanks for Your thought and for links.
Udi's way: http://www.udidahan.com/2009/04/20/saga-persistence-and-event-driven-architectures/
In general we have based our sample on his model.
Only difference is that we have introduced this abject handler that
manipulates 2 Aggregates:)