Communication between bounded contexts

2,543 views
Skip to first unread message

walkthewalk

unread,
Oct 4, 2011, 5:16:58 PM10/4/11
to DDD/CQRS
I'm looking at what options there are for communication between
bounded contexts. The one that springs to mind is to have an event
handler in one bounded context that sends a command to another bounded
context. Any thoughts and pointers appreciated.

Cheers
James

Rinat Abdullin

unread,
Oct 5, 2011, 2:06:50 AM10/5/11
to ddd...@googlegroups.com
You are interested in "Saga".

Rinat

stacy

unread,
Oct 5, 2011, 3:58:44 AM10/5/11
to ddd...@googlegroups.com
Without the element of a time delay, wouldn't this be simply pubsub?

satish venkatakrishnan

unread,
Oct 5, 2011, 5:06:41 AM10/5/11
to ddd...@googlegroups.com
@rinat  how saga can help here... my understanding about saga is its used for long running transactions . for eg: if the PersonnameChanged in Customer BC and it has to update in Security check in BC .. I feel this is Pub/Sub .. Please correct me if i am wrong

Rinat Abdullin

unread,
Oct 5, 2011, 5:34:46 AM10/5/11
to ddd...@googlegroups.com
PubSub is a messaging term.

Saga is a higher-level concept that allows to structure complex interactions between entities (possibly involving time relations).

You can implement a simple saga with just a Pub/Sub and a set of handlers. I would advice against looking at the problem from this perspective, though. It leads to highly fragmented mental model of the system (makes little sense and causes head-ache)

Rinat.

Roundcrisis

unread,
Oct 5, 2011, 12:10:45 PM10/5/11
to ddd...@googlegroups.com
Would this be the only way?
is it possible that a domain can consume the events resulting from a differnt BC as commands?


Andrea

Rinat Abdullin

unread,
Oct 5, 2011, 12:29:34 PM10/5/11
to ddd...@googlegroups.com
Domain can't consume events directly, since it is not aware of it's surroundings (neither should it be).
But you can have saga, which will subscribe to events, transforming them to the commands directed to specific aggregates. The code is dead-simple (actually almost all sagas tend to be simple and boring like this, even the ones that use time):

public void Consume(PaypalPaymentReceived e)
{
    _sender.Send(new SettleInvoiceWithPayment(e.InvoiceId, e.GrossAmount, e.PaymentId, e.Id));
}

Rinat

Sharas

unread,
Oct 5, 2011, 1:05:51 PM10/5/11
to ddd...@googlegroups.com
In your example Saga is a kind of anti corruption layer. Why can't this be done by event handler subscribed to event from a buss? I thought Sagas are there to correlate events.

Sharas

stacy

unread,
Oct 5, 2011, 3:21:09 PM10/5/11
to ddd...@googlegroups.com
This is not a saga, but rather a simple event handler. Sagas orchestrate a bunch of these, along with timeouts, and saga state.

However it seems like everything is being redefined these days anyway to fit whatever.

Rinat Abdullin

unread,
Oct 5, 2011, 4:46:30 PM10/5/11
to ddd...@googlegroups.com
Saga is just a logical concept that helps to decouple and structure distributed systems systems in heads of people. While doing that, they:

* serve as anticorruption layer between BCs (taking away not only coupling between them, but also coupling to time)
* implement workflows (long-running and short-running) that span multiple BCs
* serve as "building glue" between elements in distributed systems (esp. in cloud computing environments or any other cases of with elastic scalability)

Technical implementations are less relevant. However, if you add state persistence to an event handler, coupled with ability to send messages, you already have enough to run a saga. Bringing in a timer service (or just subscribing to MinutePassed) already gives full support for all things that might be required from sagas. If really needed, technically all this could be even be implemented as native plugins to your favorite messaging middleware.

Obviously, all this is arguable, since there is no "the ultimate book on sagas". However the ultimate purpose of Sagas is just to provide some logical concept that will make life simpler for people that build interesting software. 

Ok, this turned into a blog post already. Sorry for a long answer :)

Rinat

stacy

unread,
Oct 5, 2011, 6:27:03 PM10/5/11
to ddd...@googlegroups.com
Technical implementations are less relevant.

This is exactly where I got tripped up. In the end, it helped me a lot to just think in terms of event handlers that do different things. One of those things is to handle sagas (they way I described them above). With saga specifically defined, it's the simplest logical concept that keeps me organized and is extensible in my mind and code:

Event Handlers that uses evt data and:
- calls an AR command.
- calls a saga to act on saga state and issue an AR cmd and/or timeout
- calls a denormalizer

I'm sure things will evolve as I run into more problems.

Sebastian Burgstaller

unread,
Oct 6, 2011, 2:31:32 AM10/6/11
to DDD/CQRS
Sorry to interrupt, but I have questions directly related:

Where exactly are sagas started? I would guess that an AR is
responsible for that?

As Rinat stated above, sagas consume events and create commands. So
what happens if I've got to replay all of my events to feed new read
models?
Is it right to assume that in this case no sagas will be created? The
commands of a saga will have resulted in events earlier (which will be
in the event store), so there should be no need to start sagas in the
rehydration process again. Am I right?

Thanks!



On Oct 6, 12:27 am, stacy <stak...@gmail.com> wrote:
> *Technical implementations are less relevant.*

Rinat Abdullin

unread,
Oct 6, 2011, 2:50:20 AM10/6/11
to ddd...@googlegroups.com
Here's my current take. Please be warned, that it might slightly differ from viewpoints in this group.

1. We don't use the same messaging pipe in order to replay the events. Instead either of these is used:

a. Events are replayed locally. Resulting views are transferred directly to the view persistence.
b. Events are replayed on server by sending messages directly to projections (so they don't even trigger anything else)

This is possible, because we are using a few conventions to simplify plugging everything in various combinations as needed. In fact, in order to call (a) on a production system, just a few mouse clicks are needed. And in the scenario with (b) it's done by the server on every start-up.

2. Saga process is started from the event. In classical approach (i.e. coming from NSB, MT etc), saga is really started - it is some entity with an ID (derived from correlation id) that is really created when the required event comes in.

However (not that I have a lot of experience) I find it much easier to have absolutely stateless sagas, thinking of them as of secretary with completely no long-term memory. Sagas are just responsible for routing messages around, given the information in the documents. Just like in the real world - secretaries never make any decisions, they just send messages and forms, according to the rules. 

If you check out Greg's videos there is a part, where he talks about Document Sagas (or something like this).

Time interactions are supported by using a simple timer service (as in "send me this message back when time is X")


Does this help?

Best,
Rinat

stacy

unread,
Oct 6, 2011, 7:18:59 AM10/6/11
to ddd...@googlegroups.com
My current setup.

A saga gets started, and keeps going, because it's subscribed to one or more events. A timer can also wake-up a saga to check "saga state" and issue a cmd if necessary, go back to sleep, or end. My sagas "usually" need a tiny bit of state to do routing. Helps to avoid unnecessary chatter if there's no work to do at that moment.

Similar to Rinalt, to populate a read model I play all events but they ONLY hit the denormalizer (and not all 3 handler types I listed above). So yes, like you say - no need to start sagas in the 
rehydration process again. I'm sure you agree that would really screw things up.

That's why I love event sourcing. You have so much control and it takes little effort to run your events to generate any kind of project you need - today, or a year from today. Events are non-depreciating  business assets, IMHO.

Hope this helps :)

Udi Dahan

unread,
Oct 6, 2011, 7:28:05 AM10/6/11
to DDD/CQRS
Rinat,

The example you gave is not a saga. That is just a regular event
handler.

Cheers,

Udi


On Oct 5, 7:29 pm, Rinat Abdullin <rinat.abdul...@gmail.com> wrote:
> The code is dead-simple
> (actually almost all sagas tend to be simple and boring like this, even the
> ones that use time):
>
> public void Consume(PaypalPaymentReceived e)
> {
>     _sender.Send(new SettleInvoiceWithPayment(e.InvoiceId, e.GrossAmount,
> e.PaymentId, e.Id));
>
> }
>
> Rinat
>
>
>
>
>
>
>
> On Wed, Oct 5, 2011 at 10:10 PM, Roundcrisis <roundcri...@gmail.com> wrote:
> > Would this be the only way?
> > is it possible that a domain can consume the events resulting from a
> > differnt BC as commands?
>
> > Andrea
>
> > On Wed, Oct 5, 2011 at 7:06 AM, Rinat Abdullin <rinat.abdul...@gmail.com>wrote:
>
> >> You are interested in "Saga".
>
> >> Rinat
>

Udi Dahan

unread,
Oct 6, 2011, 7:31:22 AM10/6/11
to DDD/CQRS
The term saga was defined by the relational database community to
handle long-lived transactions - it is well defined:

http://dl.acm.org/citation.cfm?id=38742&dl=GUIDE&coll=GUIDE

Cheers,

Udi

Greg Young

unread,
Oct 6, 2011, 7:36:36 AM10/6/11
to ddd...@googlegroups.com

Yes not a new thing

Rinat Abdullin

unread,
Oct 6, 2011, 7:42:51 AM10/6/11
to ddd...@googlegroups.com
Udi,

I agree with the definition. 

FYI, here are a few more event handlers from the same class. Does this class start looking more like a conventional saga now? :)

public void Consume(InvoicePrepared e)
{
    _sender.Send(new DeliverInvoiceToCustomer(e.Definition.CustomerId, e.Definition));
}

public void Consume(ElectronicPaymentRequestedFromCustomer e)
{
    var id = new PaymentId(e.InvoiceId.Id);
    
    _sender.Send(new RequestPaypalPayment(id, e.Definition, e.BillingEmail));
    var when = DateTime.UtcNow + TimeSpan.FromDays(10);
    _sender.Alert(new RemindAboutInvoice(e.Id, e.InvoiceId), when);
}

public void Consume(PaypalPaymentReceived e)
{
    _sender.Send(new SettleInvoiceWithPayment(e.InvoiceId, e.GrossAmount, e.PaymentId, e.Id));
}

Best,
Rinat

Damian Hickey

unread,
Oct 6, 2011, 9:07:51 AM10/6/11
to ddd...@googlegroups.com
There is something about an event handler in a one BC that knows of commands from another BC that doesn't sit will with me. It would seem that the boundaries are leaky and have undesirable coupling?

If it's just a case that "one man's event is another man's command", then instead of your event handler in your first BC issuing a command, the event handler actually lives in the second BC where the event published by the first BC is converted to a command. The risk with this approach is that you may inadvertently end up creating 'conversations' between the two BCs where the conversation 'state' is somehow stored in both BCs, so watch out for that.

If you require distributed consensus, i.e. say the command fails in the second BC and you need to issue a compensating command to the first BC, then it looks like a Saga is the way to go.

My 2 cents... I reserve the right to be wrong :)

Rinat Abdullin

unread,
Oct 6, 2011, 9:25:47 AM10/6/11
to ddd...@googlegroups.com
Damian,

Not sure, if you your post refers to my code snippets. If it does not, then my apologies for misunderstanding. If it does refer, then:

What Udi called "event handlers" in snippets, are just technical implementation of sagas in my system. At the architectural level these handlers are still combined into a saga. At the code level these handlers are a member of a single saga class as well. These classes:

* help to structure bounded contexts and orchestrate workflows
* bring in time and timeout events in order to run long lived transactions
* help bounded contexts to stay decoupled and unaware of each other
* simplify message routing in load-balanced distributed scenarios

I believe, that's what sagas do "by the book". Please, correct me if I'm being wrong here.

I understand, that the code of my sagas might look like different, when compared to accepted coding practices in NSB/MT/RQ etc. But that's just the implementation being consciously chosen for a number of benefits.

What do you think?

Best regards,
Rinat

Rinat Abdullin

unread,
Oct 6, 2011, 9:27:06 AM10/6/11
to ddd...@googlegroups.com
PS: and these saga implementations, obviously, live outside of any bounded context at the logical level.

Sarunas Mazylis

unread,
Oct 6, 2011, 10:00:06 AM10/6/11
to ddd...@googlegroups.com
I had a feeling that sagas are more like what Helland calls activities and live inside a BC serving as conversation memory with other BCs. No?

Rinat Abdullin

unread,
Oct 6, 2011, 11:16:11 AM10/6/11
to ddd...@googlegroups.com
Sarunas,

Activities and sagas are quite different in my opinion. They are both extremely useful in building distributed systems in a simple way, but serve different purposes.

However, there is a collision between current CQRS development practices and Helland's ideas. It comes from the fact that it is allowed and encouraged to have state (essentially conversation memory) inside sagas. This makes sagas look like Activities that were somehow pushed out of BCs. The latter does not make a lot of sense, since activities must be within the consistency boundary (in Helland's terminology, they have to be within the transactional scope with the entities they help to manage).

However, if we (wildly) assume that sagas should not have any state and be "dumbed" down to simple messaging conversion and routing, then everything becomes more straightforward. Essentially we push conversation memory (and related actions) back to the Activities inside the BCs (even though there might be no actual "activity" class in there).

There are advantages of this approach:
  • Since conversation memory is inside an AR now, it's much easier to develop and test everything (well, as long as CQRS+ES is used)
  • No need to worry about load-balancing and partitioning saga persistence (or synchronizing state), since sagas are stateless and inherently idempotent.
  • Testing sagas becomes much easier (not sure if you even need to test that).
The biggest drawback - that workflow starts feeling a bit fragmented if we talk about actual "normalized" messages passing around (where message contains absolute minimum of information). If, however, we step back from purist development approach and closer to the real world (where there are various redundant documents passing between organizational entities) and allow a little bit more duplication, then suddenly everything becomes simpler.

This works fine for me, since I already allow quite a bit of data duplication in terms of event sourcing and expendable read models. 

BTW, the second drawback of this approach is that implementing Helland's activities in relational world can be quite expensive (due to inherent friction and object-relational impedance mismatch). +ES is totally different story.

However, I understand, that this is just one of many approaches. And my further experience might prove me horribly wrong for "breaking" proper sagas and taking state away from them (or doing a few other really bad things). So far it works though, starting from the code (efficiency of coding) up to architecture (ease of evolving the system according to real world models) and up to maintenance (ease of running systems for years in various deployment scenarios, starting from on-premises and up to hybrid clouds).

Does this help?

Best wishes,
Rinat

Damian Hickey

unread,
Oct 6, 2011, 12:06:11 PM10/6/11
to ddd...@googlegroups.com
Rinat,

I was responding to James (walkthewalk) in Google Groups web UI. Sorry if it was confusing.

With respect to your description and code snipptes my opinions are mostly aligned with yours :)

I think OP could better expand on what exactly he means by 'communicate between domains', perhaps a concrete  / contrived example?

(Going off-topic slightly)

On the 'orchestrate workflows' bit, Arnon states that is not what Saga's are about ( http://www.rgoarchitects.com/nblog/2009/01/16/SagasAndWorkflows.aspx ). What are your thoughts on this? Are people implementing workflows as Sagas?

Cheers,

Damian

Rinat Abdullin

unread,
Oct 6, 2011, 12:49:46 PM10/6/11
to ddd...@googlegroups.com
Damian,

In Arnon's description - he mixes together logical roles (purpose) and technical implementations (presence of state, allowed behaviors). At least that how it looks like to me. It could make much more sense to people working with SOA because of the specifics.

However you are right. It seems that in CQRS/DDD context, the distinction between these too is blurred, and people are implementing [business] Workflows as Sagas. Arnon talks about workflows that use state machines, and in CQRS/DDD world I've heard quite often of Sagas that implement business workflows by using state transitions (i.e.: Greg's Amsterdam, Jonathan's use of Stateless in sagas etc).

I understand, that these terms are quite overloaded with meanings, and it's quite easy to get into a long and confusing argument, because different people would perceive the same word differently.

Having said all that, when I was talking about 'Sagas' in my previous messages I was trying to refer to:

Business Processes that are implemented as stateless message routers (where event handlers are grouped together in a single class according to the BP) In this case actual transaction management is distributed between participating Bounded Contexts (all related behaviors are logically hosted inside these BCs in activities, which have "conversation memory").

Does this help you somehow?

BTW, thanks a lot for raising this question. It caused me to articulate and understand everything better.

Warm regards,
Rinat

Sharas

unread,
Oct 6, 2011, 12:57:20 PM10/6/11
to ddd...@googlegroups.com
If I get you right, Saga is more like a part of middleware. Since it lives outside BCs, does rauting for BCs and also serves as anticorruption layer for BCs (e.g. has message transformers).

Wold that be some kind of a broker?

Sharas

Greg Young

unread,
Oct 6, 2011, 1:02:29 PM10/6/11
to ddd...@googlegroups.com

We should be more precise in our language and distinguish the two concepts even though they tend to have similar implementations intent can be different

Rinat Abdullin

unread,
Oct 6, 2011, 1:07:22 PM10/6/11
to ddd...@googlegroups.com
Middleware and brokers are technical terms (implementation details).
Saga is more a conceptual term (describes the purpose and model, could have many implementations).

Mixing these together (even in one's mind) is possible but dangerous. Just like having business logic in stored SQL procedures :)

Rinat

Sharas

unread,
Oct 6, 2011, 1:13:50 PM10/6/11
to ddd...@googlegroups.com
ahh, so Saga is philosophical:) That fits, even the name is romantic - Saga....

But, in your experience, do you implement them like some hub-and-spoke central router? Just trying to see the clearer picture.


Sharas

Udi Dahan

unread,
Oct 6, 2011, 1:19:36 PM10/6/11
to ddd...@googlegroups.com
Rinat,

If a single class handles multiple events that doesn't make it a saga. It is only if that class manages the state of some process which is triggered by those events that it becomes a saga.

Cheers,

Udi

Sharas

unread,
Oct 6, 2011, 1:21:39 PM10/6/11
to ddd...@googlegroups.com
Udi, So would you say Sagas live inside BCs? How do they compare to Hellands activities?


Sharas

Udi Dahan

unread,
Oct 6, 2011, 1:23:08 PM10/6/11
to ddd...@googlegroups.com
I would strongly disagree with the statement that sagas (or anything) lives outside a bounded context.

Udi Dahan

Rinat Abdullin

unread,
Oct 6, 2011, 1:25:00 PM10/6/11
to ddd...@googlegroups.com
Udi,

Ok. If that's the definition of saga, then my business (domain) processes don't have anything to do with sagas, since they are implemented as stateless event handlers.

Best regards,
Rinat

Rinat Abdullin

unread,
Oct 6, 2011, 1:32:27 PM10/6/11
to ddd...@googlegroups.com
Sharas, 

Technical implementations can be different.

Most of the time, indeed, they are implemented as a set of event handlers subscribed to one queue and sending commands around. This makes infrastructure simpler (you can draw it on a white-board and show flow of messages).

However, the stateless nature of my implementations, makes it possible to do really weird things which work quite well in distributed environments (esp. cloud). You can move code to messages, instead of sending messages to the code :)

All the best,
Riat

Sharas

unread,
Oct 6, 2011, 1:48:06 PM10/6/11
to ddd...@googlegroups.com
Code to the messages sounds intriguing:)

In your experience, those messages usually have some kind of destination in form of required service description and the router resolves them to concrete implementations? Or is it some kind of content based routing? 

Hope you have some more time and patience to answer.


Thanks,

Sharas

Rinat Abdullin

unread,
Oct 6, 2011, 2:05:29 PM10/6/11
to ddd...@googlegroups.com
Sharas,

Re "code to data" - that's nothing new, actually. Apache Hadoop is one of the popular examples.

Re destinations. I'm just using Helland's ideas directly here. 

Each entity has a globally unique identity and resides within some partition. Commands are always addressed to the specific entity and are routed by the environment accordingly. Events being published always have the identity of originator.

Identity information is kept within the messages and is also copied to the transport headers. The latter allows to avoid content-based routing and use topic-based one (if in the specific case we decided to delegate this routing to middleware).

This approach to identities plugs nicely to DDD concepts and is also enforced in the code (commands are strongly-typed with the identities). Aside from introducing better compile-time checks, this improves development experience a bit. For example: http://twitter.com/#!/abdullin/media/slideshow?url=pic.twitter.com%2Ft34HIEaa


BTW, there is an old article of mine about Helland's paper. It's a bit outdated, but might be of interest for you: http://abdullin.com/journal/2010/8/22/space-travel-and-infinitely-scalable-solutions.html

Best,
Rinat

Greg Young

unread,
Oct 6, 2011, 2:09:16 PM10/6/11
to ddd...@googlegroups.com

Code to the message is especially cool with document messages

Sharas

unread,
Oct 6, 2011, 2:37:46 PM10/6/11
to ddd...@googlegroups.com
So basically you can shard by id. And on each partition you have something like message dispatcher that invokes handlers by message id? Or in case of middleware that would be something like event driven consumer subscribed to the topic?

Thanks for links. Could somebody provide a link for a good example of code to message?

Thanks,


Sharas

Rinat Abdullin

unread,
Oct 6, 2011, 3:02:31 PM10/6/11
to ddd...@googlegroups.com
If we are talking about Aggregate Roots, then message dispatcher just loads the Aggregate by the entity-id and then dispatches command there. That would be like calling Execute(ICommand cmd) from this sample:


If we are talking about projections (denormalizers for view handlers), then we can have endpoint subscribed to all events, where actual entity loading (view is also Helland's entity) happens within handler on case-by-case basis:


Re snippet on code to messages. [heresy-inside] Imagine that you have DomainProcesses.dll, which is copied to all 10 of your partitions. Whenever an event is published from AR, you also run it through your stateless ProcessLibrary and dispatch all generated commands right away.[/heresy-inside]

Best,
Rinat

Sarunas Mazylis

unread,
Oct 6, 2011, 3:29:42 PM10/6/11
to ddd...@googlegroups.com
In case of aggregates, do you do something like in Hellands example where all IDs of aggregates are prefixed with entity-key, basically kind of aggregate type identifier. Or some other technique to map to aggregate type? 

Thanks,


Sharas

Rinat Abdullin

unread,
Oct 7, 2011, 12:51:04 AM10/7/11
to ddd...@googlegroups.com
Sarunas,

Yes, my aggregate ids look like this, when passed in transport headers: account-10345.
10345 is a globally unique identifier within the system and account prefix is just a convenience for reading and routing.

In the code, identities (and aggregate references) look like : new AccountId(10345) (big thanks to Jeremie for introducing me to this piece of practical DDD programming).

Best,
Rinat

Sebastian Burgstaller

unread,
Oct 7, 2011, 2:29:51 AM10/7/11
to DDD/CQRS
Thanks for all the answers. I get it that there are many ways to
realize sagas.

But all these ways seem to have the following in common:

- sagas get started directly by events, so outside of BCs (that point
I didn't really get - so they are started by event handlers?)
- sagas consume events and publish commands
- sagas should not be created when replaying events

@Rinat
You said that you have timer services, that return events at the
specified time if needed.
What happens to these events if somebody spilled his coffee over the
server ;-)
So you restart the server later and you replay all your events.

Will the timer service remember it's tasks (persistent queue)?
If yes, will the events that should have been published during the
downtime carry the timestamp of their scheduled publish time, or will
it be the current time?

Thanks again, this group is great!

Sebastian
> > I think OP could better expand on what exactly he means by 'communicate *between
> > *domains', perhaps a concrete  / contrived example?

Rinat Abdullin

unread,
Oct 7, 2011, 2:45:08 AM10/7/11
to ddd...@googlegroups.com
Sebastian,

In Russia spilling coffee over a server is rare. Bucket of water or a shotgun happen more often :) And if you are building for the cloud environment, random reboots and failures are even more frequent. So you have to build systems that are simple and resilient at every level.

Obviously, the timer service is fully persistent, so crashes are never a problem. So if server is killed before moment X, and finished rebooting on X+5, then pending messages will be sent ASAP. Message timestamps rarely play any role in my systems, but for the sake of clarity this message will have CreatedOn time of original creation, and "DeliverBy" of X.

Re replaying events. You don't replay events by sending them into all message queues (and triggering all sorts of interactions). Instead you use events separately, to rebuild some separate state ofter changing the projection logic. So when I'm replaying events on a server, this means that the don't go to the usual message pipe. Instead they are processed only by the projections (denormalizers).

This is similar to Aggregate Roots with event sourcing - when you load aggregate from history by replaying the events you don't resend events all across the system. Instead, you just take persisted ones and reapply them locally.

So replaying events is not about resending them. It's about taking events history and reapplying them locally.

Best,
Rinat

stacy

unread,
Oct 7, 2011, 3:29:45 AM10/7/11
to ddd...@googlegroups.com
@Rinat - That's a really cool ARid! 

Is there a lot of overhead for creating such creatures when sending cmds from several web servers? Seems like you would need a central location for the last number served and maybe watch out for race conditions?  I would love to get away from the ultra convenient GUID if practical.

Thanks,

Stacy

Rinat Abdullin

unread,
Oct 7, 2011, 4:09:24 AM10/7/11
to ddd...@googlegroups.com
Stacy,

Two-fold approach here.

First of all web requests don't actually generate integral identities. They generate guid-based identities. As in RegistrationId : Identity<Guid>. This is not because of the performance issues, but because I want to keep everything decoupled. 

And registration process (as in this example) will create proper customer with CustomerId : Identity<long>.

BTW, while we are on this topic, identity generation is something that lives completely outside of ARs and BCs. Hence, this is something delegated to my sagas.. err.. stateless domain processes (almost stateless, if we consider presence of generator state):

public void Consume(RegistrationCreated e)
{
  var id = _identityGenerator.GetNextId();
  var customer = new CustomerId(id);
  _sender.Send(new CreateCustomerFromRegistration(customer, e.Id, e.Data));  
}
public void Consume(CustomerCreated e)
{
  // complete the original registration
  _sender.Send(new CompleteRegistration(e.RegistrationId, e.Id));
}

This fits perfectly with my interpretation of Hellands concepts. Domain Processes are something that "glue" together BCs (while allowing them to stay decoupled) and also coordinate BCs through transactions and business workflows. In order to do that they know how to address these BCs and how to convert messages. In a sense generating an ID is just addressing a message to an entity that does not exist yet (and in order to do that, we need a new identity provided to us by the environment). This makes a perfect sense especially in distributed cloud environments (although I still use that in on-premise deployments as well).

Second. Generating integral identifiers in a reliable way - is something that can be scaled out linearly (hi-lo strategies mostly). Worst case scenario (random crashes of environment) could lead to gaps in integral sequences (something which I'm perfectly fine with). For identity generation you can use any persistent storage that allows atomic operations, starting from SQL. I use Azure Cloud Blobs/files.

A few life-hacks. My identity generation is configured in such way, that identities are globally unique. For instance, if you have Customer-1, then it is impossible to have Invoice-1. This has two benefits:

1. You can add dashboard for the sales with UI like: "enter ID to show details" (where id can be customer, invoice, payment etc).
2. If I ever have Customer-1 and Security-1, then this means that these are just two different bounded contexts that describe the same entity. They happened to be split just because it was easier to manage complexity this way (kudos to Jeremie for teaching me this practical DDD approach)

Does this help?

Rinat

stacy

unread,
Oct 7, 2011, 5:49:52 AM10/7/11
to ddd...@googlegroups.com
@Rinat - Yes it helps me understand how you do it. Thanks for taking the time to lay it out in such detail! 

The concept of an external identity generator like that is interesting, although it does add complexity. The trade-offs will keep me using GUID's for now. Thanks for sharing! 

Stacy

Damian Hickey

unread,
Oct 7, 2011, 5:53:40 AM10/7/11
to ddd...@googlegroups.com
Rinat,

This entire discussion helps :)

Are your 'activities' ARs in their own right, separate from the ARs that may be 'worked upon' in a Saga? I presume the conversation memory these activities contain is only 'their side' of the conversation?

So, just so I'm clear, Jonathan's Saga implementation, when used with an StateMachine (and is persisted), that doesn't fall into your definition of a Saga? Would you call that a workflow?

(These blurred distinctions are giving me blurry vision!)

Thanks again,

Damian

Damian Hickey

unread,
Oct 7, 2011, 6:10:19 AM10/7/11
to ddd...@googlegroups.com
> - sagas get started directly by events, so outside of BCs

I was wonder about this and thought what is wrong with starting a saga from a command...


> - sagas consume events and publish commands

I'd like some clarification on terminology here: is 'publish' the right word? Are commands usually addressed / targeted and should be handled once? i.e. one doesn't pub/sub commands like one does events? Thus should we say "sagas consume events and post commands"? (sorry if this is nit-picky)


> - sagas should not be created when replaying events

Thinking out loud here: when replying events (i.e. say rebuilding the denormalized store) what could go wrong with having the sagas handle events and posting commands? If you command handling is idempotent, is safe to allow this to happen?

Rinat Abdullin

unread,
Oct 7, 2011, 6:16:08 AM10/7/11
to ddd...@googlegroups.com
Damian,

After thinking about yesterday's conversation, the best neutral term that I could come with is "Domain Process". (Workflow does not fit since it brings with it all the stateful workflow engines).

So we can say, that domain processes coordinate interactions between bounded contexts, while allowing them to stay decoupled from each other and environment around. They also help to manage Long Lived Transactions and can be used to model flows of work that span multiple BCs.

These domain processes can be implemented in various ways: i.e.: using Sagas approach (where conversation memory resides within the handler), Workflows (using some workflow engine). 

I'm using slightly different approach to achieve that - handlers are stateless, reside outside of BCs, while state and conversation memory reside within the Bounded Contexts. Within this approach, ARs are implemented using event sourcing, and it's easy to model  activities (which use conversation memory to handle eventual consistency)  as part of these ARs. Testing is straightforward as well (same specifications approach as usual behaviors)

So from this standpoint Saga approach of Jonathan Oliver (with state machine) is one of multiple ways to implement interactions between BCs

Does this help to clarify the picture?

Best, 
Rinat

Rinat Abdullin

unread,
Oct 7, 2011, 6:27:42 AM10/7/11
to ddd...@googlegroups.com
Demian,

>> - sagas get started directly by events, so outside of BCs 
> I was wonder about this and thought what is wrong with starting a saga from a command..

Commands are addressed to recipient. If you can start domain process with a command, then it means that this is an entity and not a process.

> I'd like some clarification on terminology here: is 'publish' the right word?

You are correct. I prefer to use "Send" or "post"

> Thinking out loud here: when replying events (i.e. say rebuilding the denormalized store) what could go wrong with having the sagas handle events and posting commands? If you command handling is idempotent, is safe to allow this to happen?

There is a catch. In order to achieve that, transformation from event to command must be deterministic, meaning that event(sha1=5d5ae1...) always generates command(sha1=6543fa...), no matter how many times this is replayed. And if you have stateful sagas, this is not always the case. So in order to always have this deterministic transformation, you will need to have conversation memory within the saga as well. And now we are getting into boring code... So it's easier to go with stateless event handlers or just avoid replaying events to sagas :)

Best,
Rinat

Sharas

unread,
Oct 7, 2011, 6:43:09 AM10/7/11
to ddd...@googlegroups.com
So your dispatcher code deployed on each partition given an ID Account-10345 would do something like this?

instantiate an instance of "Account" aggregate.
Load it's state by id 10345 if there is any (might be fresh instance).
Create a command by... message name maybe?
Invoke Execute on aggregate with that command.

Is that remotely correct? Trying to imagine internals of your implementation:)

Judging by response you gave to Stacy, I guess your sagas are in Hellands words stateless services acting as scale agnostic API for upper scale agnostic application layers. Interesting to see how those ideas translate to a concrete implementation.

Thanks,


Sharas

Rinat Abdullin

unread,
Oct 7, 2011, 7:09:37 AM10/7/11
to ddd...@googlegroups.com
Sharas, 

1. Let's make this easier for you :)

A few notes:
(a). No snapshotting here (will add later)
(b). We can have multiple commands in a message (all of them are addressed to the same entity and executed within logical transaction)
(c). Exception are handled in the handler.
(d). Concurrency protection of underlying storage is possible, but I don't need it (an entity can have only one writing thread).

public IEnumerable<IEvent<IIdentity>> Load(ICollection<ICommand<IIdentity>> commands)
{
    var id = commands.First().Id;
    var stream = _factory.GetOrCreateStream(IdentityConvert.ToStream(id));
    var records = stream.ReadRecords(0, int.MaxValue);
    var events = records
        .Select(r => (IEvent<IIdentity>) _streamer.ReadAsEnvelopeData(r.Data))
        .ToArray();
    var then = new List<IEvent<IIdentity>>();

    var customer = id as CustomerId;
    if (customer != null)
    {
        var state = new CustomerAggregateState().With(events);
        var aggregate = new CustomerAggregate(then.Add, state);
        aggregate.ExecuteSafely(commands);
        return then;
    }


2. Yes.

Just to rephrase is slightly more precise terms (as I hope). My stateless event handlers (that implement domain processes) are exactly the part of the scale-agnostic environment for running entities. They help to enforce decoupling and are easy to code and host (since there is almost no state that would need scaling and concurrency management). Aggregate Roots live in their own isolated universes, which are immediately consistent, and have boundaries matching BCs.

Message ordering and idempotency (problems that are common to any distributed environment) are handled by activities within ARs (which rely on the memory of past conversations to fullfil this role). By having our "concurrency logic" (activities) in the same entity with the business logic, we are forced to treat all race conditions within the business context. This reduces amount of negotiations code spread between entities, while providing us with the perfect tool to test everything (CQRS+ES and specifications). 

Helps?

All the best,
Rinat

Sharas

unread,
Oct 7, 2011, 7:34:15 AM10/7/11
to ddd...@googlegroups.com
spasibo,

So you have a map somewhere which maps from customer1234 ID to implementation of Load() by token "customer". 

Sharas

unread,
Oct 7, 2011, 7:53:40 AM10/7/11
to ddd...@googlegroups.com
Just realized I made a statement:) Although I wanted to ask a question

Rinat Abdullin

unread,
Oct 7, 2011, 10:14:48 AM10/7/11
to ddd...@googlegroups.com
Sharas,

Not even a map, but just a bunch of cast statements. From practical standpoint that's more than enough for simple cases that have less than 1 tx per second (majority of deployments).

var customer = id as CustomerId;
if (customer != null)
{
    var state = new CustomerAggregateState().With(events);
    var aggregate = new CustomerAggregate(then.Add, state);
    aggregate.ExecuteSafely(commands);
    return then;
}
var user = id as UserId;
if (user != null)
{
    var state = new UserAggregateState().With(events);
    var agg = new UserAggregate(state, then.Add, new PasswordGenerator());
    agg.ExecuteSafely(commands);
    return then;
}

var reg = id as RegistrationId;
if (reg != null)
{

etc.

In more complicated scenarios, we will start partitioning aggregates based on their aggregate IDs (but this code could still stay the same).

Best,
Rinat

walkthewalk

unread,
Oct 10, 2011, 7:36:23 AM10/10/11
to DDD/CQRS
Thanks to all for contributing to this discussion. Let me applogise
for not including a good example from the off.

Here is some more meat on the bones....

BC1 relates to a client and the posting of accounting related data.
Some example commands are CreateClient, CreateJournal,
PostJournalAmount, ReverseJournalPost, PostJournal.

BC2 relates to the processing and mapping of figures created by BC1
into a different set of figures. Some example commands are
CalculateFigures, CalculateMappedFigures.

Initially the communication is one way (from BC1 to BC2). In the
future it is likely to be two way.

Now there is an argument that BC1 and BC2 are actually a single BC
with many denormalized view models.

Hope you all have some energy left after the discussions on
Sagas! :-)

Cheers
James

On Oct 4, 10:16 pm, walkthewalk <jimsgoodeno...@gmail.com> wrote:
> I'm looking at what options there are for communication between
> bounded contexts.  The one that springs to mind is to have an event
> handler in one bounded context that sends a command to another bounded
> context.  Any thoughts and pointers appreciated.
>
> Cheers
> James

Martin Nilsson

unread,
Oct 14, 2011, 3:27:59 PM10/14/11
to ddd...@googlegroups.com
If your sagas don't have state how do you handle that commands should only be sent if a certain condition is fulfilled. Like in BaristaMessageHandler.DeliverOrder located here

https://github.com/NServiceBus/NServiceBus/blob/master/Samples/Azure/AzureSagas/Barista/BaristaMessageHandler.cs


On Thu, Oct 6, 2011 at 5:16 PM, Rinat Abdullin <rinat.a...@gmail.com> wrote:
Sarunas,

Activities and sagas are quite different in my opinion. They are both extremely useful in building distributed systems in a simple way, but serve different purposes.

However, there is a collision between current CQRS development practices and Helland's ideas. It comes from the fact that it is allowed and encouraged to have state (essentially conversation memory) inside sagas. This makes sagas look like Activities that were somehow pushed out of BCs. The latter does not make a lot of sense, since activities must be within the consistency boundary (in Helland's terminology, they have to be within the transactional scope with the entities they help to manage).

However, if we (wildly) assume that sagas should not have any state and be "dumbed" down to simple messaging conversion and routing, then everything becomes more straightforward. Essentially we push conversation memory (and related actions) back to the Activities inside the BCs (even though there might be no actual "activity" class in there).

There are advantages of this approach:
  • Since conversation memory is inside an AR now, it's much easier to develop and test everything (well, as long as CQRS+ES is used)
  • No need to worry about load-balancing and partitioning saga persistence (or synchronizing state), since sagas are stateless and inherently idempotent.
  • Testing sagas becomes much easier (not sure if you even need to test that).
The biggest drawback - that workflow starts feeling a bit fragmented if we talk about actual "normalized" messages passing around (where message contains absolute minimum of information). If, however, we step back from purist development approach and closer to the real world (where there are various redundant documents passing between organizational entities) and allow a little bit more duplication, then suddenly everything becomes simpler.

This works fine for me, since I already allow quite a bit of data duplication in terms of event sourcing and expendable read models. 

BTW, the second drawback of this approach is that implementing Helland's activities in relational world can be quite expensive (due to inherent friction and object-relational impedance mismatch). +ES is totally different story.

However, I understand, that this is just one of many approaches. And my further experience might prove me horribly wrong for "breaking" proper sagas and taking state away from them (or doing a few other really bad things). So far it works though, starting from the code (efficiency of coding) up to architecture (ease of evolving the system according to real world models) and up to maintenance (ease of running systems for years in various deployment scenarios, starting from on-premises and up to hybrid clouds).

Does this help?

Best wishes,
Rinat

On Thu, Oct 6, 2011 at 8:00 PM, Sarunas Mazylis <apkr...@gmail.com> wrote:
I had a feeling that sagas are more like what Helland calls activities and live inside a BC serving as conversation memory with other BCs. No?

On Thu, Oct 6, 2011 at 4:27 PM, Rinat Abdullin <rinat.a...@gmail.com> wrote:
PS: and these saga implementations, obviously, live outside of any bounded context at the logical level.

On Thu, Oct 6, 2011 at 7:25 PM, Rinat Abdullin <rinat.a...@gmail.com> wrote:
Damian,

Not sure, if you your post refers to my code snippets. If it does not, then my apologies for misunderstanding. If it does refer, then:

What Udi called "event handlers" in snippets, are just technical implementation of sagas in my system. At the architectural level these handlers are still combined into a saga. At the code level these handlers are a member of a single saga class as well. These classes:

* help to structure bounded contexts and orchestrate workflows
* bring in time and timeout events in order to run long lived transactions
* help bounded contexts to stay decoupled and unaware of each other
* simplify message routing in load-balanced distributed scenarios

I believe, that's what sagas do "by the book". Please, correct me if I'm being wrong here.

I understand, that the code of my sagas might look like different, when compared to accepted coding practices in NSB/MT/RQ etc. But that's just the implementation being consciously chosen for a number of benefits.

What do you think?

Best regards,
Rinat


On Thu, Oct 6, 2011 at 7:07 PM, Damian Hickey <dhi...@gmail.com> wrote:
There is something about an event handler in a one BC that knows of commands from another BC that doesn't sit will with me. It would seem that the boundaries are leaky and have undesirable coupling?

If it's just a case that "one man's event is another man's command", then instead of your event handler in your first BC issuing a command, the event handler actually lives in the second BC where the event published by the first BC is converted to a command. The risk with this approach is that you may inadvertently end up creating 'conversations' between the two BCs where the conversation 'state' is somehow stored in both BCs, so watch out for that.

If you require distributed consensus, i.e. say the command fails in the second BC and you need to issue a compensating command to the first BC, then it looks like a Saga is the way to go.

My 2 cents... I reserve the right to be wrong :)





Rinat Abdullin

unread,
Oct 14, 2011, 7:12:16 PM10/14/11
to ddd...@googlegroups.com
Ifs and all conditions are a business behavior. I prefer for that behavior to sit inside aggregate roots, where they are easy to manage, specify and test (AR+ES). So in my case, events would be routed to an aggregate as commands (timeout would be routed there as well). Then, it will be responsibility of AR to determine if "OrderIsReadyToBeDelivered".

Of course, sprinkling decision-making business logic around the system in spaghetti-style is also an option :)

Best,
Rinat

stacy

unread,
Oct 15, 2011, 12:01:52 AM10/15/11
to ddd...@googlegroups.com
I really like the way you leverage all the AR+ES goodness instead of creating something different to do a saga.

Since this "saga AR" is transient, and there is no need to keep all the intermediate events, do you persist the events in a separate "saga event store" so you can easily dump them later? Or do you just keep them like others and post to your domain log too (storage is cheap theory). 

I think the latter can get noisy quickly. So if i tried this, I think i would just persist only the final event to my event store. Thinking out loud.

Rinat Abdullin

unread,
Oct 17, 2011, 5:56:58 AM10/17/11
to ddd...@googlegroups.com
Stacy,

There is no "Saga AR" in my world. Saga is a technical implementation that has state and is designed to manage long-running workflows and transactions.

I have just entities (AR+ES) and stateless event handlers that subscribe to events and convert them to commands (without any decision making). What was a "saga" before, now either is called an entity, and is modelled as such with all the explicit events and specifications. An example of that would be "Registration" it was a saga before, but is an real entity now. Actually, after modeling it as such, I've started seeing and noticing behaviors, that we were not aware of before, and that could be used to make our process better.

The other option is when the state is spread between participating entities (they pass enough information for the other entity to make the decision). 

Obviously, since all the models represent business core competency, I would store all of the events (replicated a couple of times). However, if I encounter a situation, where events are not worth story, this would raise the question: should CQRS/DDD/ES be used here in the first place?


Best,
Rinat

Daniel Yokomizo

unread,
Oct 17, 2011, 6:37:01 AM10/17/11
to ddd...@googlegroups.com

Rinat, are you only using commands that do not fail? If not who deals with failures, retries, etc.?

Rinat Abdullin

unread,
Oct 17, 2011, 6:53:46 AM10/17/11
to ddd...@googlegroups.com
While developing a system I start with handlers that aren't supposed to fail.

1. If any handler fails with an exception - commands are retried 4 times by the infrastructure. This deals with the transient failures (i.e.: network). 

2. Commands that fail more than 4 times are moved to poison and reported immediately to the support.

3. If certain command failure happens too often (sometimes first failure is enough), then it is treated as explicit scenario within the command handlers. Instead of just letting the exception to pop-up, we detect, verify and or/analyze the problem within the code and try to handle it automatically (just to save on the support time). After applying the fix, we redeploy and relaunch the failing command, seeing that it finishes properly. Sometimes this cycle happens so fast, that the customer does not even notice the problem.

At this point we are again stuck with the handlers that aren't supposed to fail. GOTO 1.

Does this answer your question?

Best,
Rinat

Sharas

unread,
Oct 17, 2011, 8:38:20 AM10/17/11
to ddd...@googlegroups.com
Hi Rinat,

I assume you don't process commands routed from your routing services in handlers synchronously. So how does handler notifies about a failed command? Is there some kind of Invalid Message Channel where handler is posting failed commands with correlation id?


Thanks,


Sharas

Rinat Abdullin

unread,
Oct 17, 2011, 9:04:29 AM10/17/11
to ddd...@googlegroups.com
If the failure is possible and a part of scenario (and client expects it), then I'm publishing explicit "BadScenarioAHappenedEvent", which is then routed and handled as a business scenario. This could involve projecting failure information to the view (by request id), where it will be picked up by the client waiting for the result.

For the generic failures (which are not handled explicitly since we don't know how to handle them, yet), I'm just sending a message to support. 

Best,
Rinat

Sarunas Mazylis

unread,
Oct 17, 2011, 9:15:00 AM10/17/11
to ddd...@googlegroups.com
Hmm... So what does 4 times retrial for unknown failures? Support?

Rinat Abdullin

unread,
Oct 17, 2011, 9:19:54 AM10/17/11
to ddd...@googlegroups.com
4-times retrial deals with the transient errors (which we have a lot due to integrations). If retries are not fixed, then support is plugged in automatically.

Rinat

Daniel Yokomizo

unread,
Oct 17, 2011, 5:00:36 PM10/17/11
to ddd...@googlegroups.com

I see, this is very nice and is feasible with external services too. Thanks for the detailed reply.

stacy

unread,
Oct 17, 2011, 9:11:52 PM10/17/11
to ddd...@googlegroups.com
... I've started seeing and noticing behaviors, that we were not aware of before, and that could be used to make our process better.

Even more reason to give it a try! Thanks for the details. 

In my particular case, gonna keep these events in a separate event store. Because once this "thing" finishes, there is no possibility of further  production use. Only offline business intelligence. 

Michael.

unread,
Oct 19, 2011, 12:33:18 PM10/19/11
to DDD/CQRS
This is a side question but I think it's related:

When different bounded contexts need to subscribe to each other's
events, should they share the same event store? does this violate any
sort of segregation between BCs?

Michael.

stacy

unread,
Oct 19, 2011, 1:45:20 PM10/19/11
to ddd...@googlegroups.com
There's never a "requirement" to share event stores to get something done between BC's AFAIK. That would mean unwanted coupling. 

However, I can see how your pubsub system implementation might only permit one eventstore for all BC's. 

Theoretically, you can have one event store for all BC's to start with, and later partition to 1 event store per BC, and later to 1 event store per AR, and later to 1 event store per command, if you want. However your pubsub system implementation must allow such scenarios. 

The decoupling that CQRS-ES enables allows for very flexible ES implementations. That's why I have separate ES for saga's because those events will be archived immediately upon saga completion. 

My 2cents :)

@yreynhout

unread,
Oct 19, 2011, 2:17:39 PM10/19/11
to DDD/CQRS
Y'all may wanna have another look at Published Language in the Blue
Book.

Seif Attar

unread,
Oct 19, 2011, 2:58:27 PM10/19/11
to ddd...@googlegroups.com
What blue book?



Sent from my phone


On 19 Oct 2011 19:18, @yreynhout <yves.r...@gmail.com> wrote:

Peter Bell

unread,
Oct 19, 2011, 3:11:38 PM10/19/11
to ddd...@googlegroups.com
Assuming he's not referencing a publication for ascertaining the price of used motor vehicles, I'm guessing given the context he probably means this:

:)

Best Wishes,
Peter

Sølve Heggem

unread,
Oct 19, 2011, 3:14:07 PM10/19/11
to ddd...@googlegroups.com
This book is blue:
Domain-Driven Design: Tackling Complexity in the Heart of Software by Eric Evans

/Sølve

Sarunas Mazylis

unread,
Oct 19, 2011, 3:20:08 PM10/19/11
to ddd...@googlegroups.com
real hackers call it #3399FF book

Seif Attar

unread,
Oct 19, 2011, 5:10:50 PM10/19/11
to ddd...@googlegroups.com
Hehe, that literally blue book :)

the number of times I heard the term the blue book and thought it had some connotation like 'greenfield'

Glad I asked.

Thanks!



Sent from my phone


Daniel Yokomizo

unread,
Oct 19, 2011, 8:29:26 PM10/19/11
to ddd...@googlegroups.com
In the Smalltalk community the blue book is another:

Smalltalk-80: The Language and its Implementation
http://wiki.squeak.org/squeak/64

Reply all
Reply to author
Forward
0 new messages