3

This is a theoretical question about the introduction of new BCs in a system we use ES and CQRS with DDD. So there won't be concrete examples.

There can be interesting problems by introducing new BC-s, which communicate with the old ones by receiving and publishing domain events. The root of these problems that we already have domain events in the event storage. When the new BC reacts on those old domain events it will do that in a way which is out of sync and/or out of sequence.

For example we have an old BC A and we introduce a new BC B. Both publish domain events which we call a and b. In the new system the order matters for example b1 must always come after a1, but before a2. What can we do, when we already have the a1, a2, a3 sequence in the event storage? Should we inject b1 after a1 and so on? Is this a viable solution by a huge event storage? It will certainly take a long time to replay all the old events one by one and react on them. How can we prevent sending an email to the customer by handling the newly created b1 event, which reacts on a 5 years old topic? Is there a pattern to prevent these kind of problems?

inf3rno
  • 24,976
  • 11
  • 115
  • 197
  • 1
    Are you deploying your components(bounded-contexts) as separate applications, as you should? They don't sound as 'bounded' as they should. – abuzittin gillifirca Nov 25 '15 at 14:29
  • @abuzittingillifirca As I already wrote, this is a theoretical question. I am learning DDD currently from books. I won't start any project before I fully understand it. – inf3rno Nov 25 '15 at 14:31
  • @abuzittingillifirca I think my misunderstanding about BC-s and event sourcing is deeper than I though. Your question in this comment is really good. I'll ask another question in the topic. – inf3rno Jan 08 '16 at 23:47

2 Answers2

3

Problem Analysis

The root of these problems that we already have domain events in the event storage.

If you introduce a new BC B to an existing system, that means the system was functional without B. This is clear by the above statement and has the following consequences:

  • Events that B would have produced in response to events from A do not need to be published. No other system should take action based on these events, because they are artificial.
  • You can go live with B at any time you choose. The only thing that you need to do beforehand is getting B in sync with the current state of the system.

Getting B in Sync

This is not difficult if you design B accordingly.

  1. First, you need a replay mode mechanism to import all domain events into B without publishing events from B in response. You need to keep Bs events internally of course if you use event sourcing, but do not publish them. Also, make sure B does not modify the state of the world while in replay mode by other means, e.g. don't send emails.
  2. Then, switch B over to live mode. Now B consumes the new events from the system and also publishes its own.

The problem you mention with event ordering is only a problem when you use a unified event store for all domain events, and also use that store to publish events from. If this is the case, then you need to mark Bs events as "internal" during the replay phase and hide them from the publishing mechanism.

Note: If B is a purely reactive BC (this could be the case for a very simple BC), then you don't even need the replay stuff. But most BC's probably do.

theDmi
  • 17,546
  • 6
  • 71
  • 138
  • Makes sense. :-) I'll wait a few days before accepting, maybe others will answer too. Btw. do you think it is acceptable to rewrite history in some cases, for example if you add a new property to an existing event class? – inf3rno Nov 25 '15 at 11:42
  • 1
    Yes, that's the ES-variant of migrations. I try to avoid it, but sometimes its just the cleanest solution. Testing the migration in a QA env is a good idea though :-) – theDmi Nov 25 '15 at 12:05
  • @inf3rno *if you add a new property to an existing event* That should be a non-breaking change, such that no migration would be necessary. – abuzittin gillifirca Nov 25 '15 at 14:25
  • @abuzittingillifirca What if the new code requires that property? Should we version the event classes instead? – inf3rno Nov 25 '15 at 14:29
  • @inf3rno You could. But if you can fill a property post hoc, then you are looking up that value from somewhere, maybe you should duplicate the source you are looking it up – abuzittin gillifirca Nov 25 '15 at 14:59
  • 1
    FWIW, I would never change history except as an *absolute* last resort. – Phil Sandler Nov 25 '15 at 16:02
1

First of all DDD does not require Event sourcing.

we have an old BC A and we introduce a new BC B. Both publish domain events which we call a and b. In the new system the order matters for example b1 must always come after a1, but before a2.

Events can be out of order, even in the same component(bounded-context). Transactional integrity is only guaranteed within aggregates.

when we already have the a1, a2, a3 sequence in the event storage?

Doesn't matter. By the way you don't have this guarantee with SQL databases unless you work in SERIALIZABLE isolation (or its vendor specific equivalent). Protip: It's so taxing on performance that it's never enabled by default; therefore you are not using it.

Pay special attention to this part in the above link:

Other transactions cannot insert new rows with key values that would fall in the range of keys read by any statements in the current transaction until the current transaction completes.

Furthermore, though an event store shouldn't have multiple copies of an event, events (and other messages such as commands) may arrive multiple times between components.

Should we inject b1 after a1 and so on?

Since your components should be able to handle out of order (and duplicate events) no

What can we do,

Depending on the technology used to integrate components, and the semantics of the messages:

  • If you are reading events from a web service, feed, DB table; such that it never goes away; you might be able to ignore an event until it is relevant.

  • Equivalently, you might be able to put an event back to the message queue it came from until it is relevant.

  • You may use the pattern known as Saga/Process Manager.

  • Is there a real race condition, at all?