Search code examples
eventsarchitecturesoaevent-driveneda

Event-driven architecture and structure of events


I'm new to EDA and I've read a lot about benefits and would probably be interested to apply it during my next project but still haven't understood something.

When raising an event, which pattern is the most suited:

  1. Name the event "CustomerUpdate" and include all information (updated or not) about the customer
  2. Name the event "CustomerUpdate" and include only information that have really been updated
  3. Name the event "CustomerUpdate" and include minimum information (Identifier) and/or a URI to let the consumer retrieves information about this Customer.

I ask the question because some of our events could be heavy and frequent.

Thx for your answers and time.


Solution

  • Name the event "CustomerUpdate"

    First let's start with your event name. The purpose of an event is to describe something which has already happenned. This is different from a command, which is to issue an instruction for something yet to happen.

    Your event name "CustomerUpdate" sounds ambiguous in this respect, as it could be describing something in the past or something in the future.

    CustomerUpdated would be better, but even then, Updated is another ambiguous term, and is nonspecific in a business context. Why was the customer updated in this instance? Was it because they changed their payment details? Moved home? Were they upgraded from silver to gold status? Events can be made as specific as needed.

    This may seem at first to be overthinking, but event naming becomes especially relevant as you remove data and context from the event payload, moving more toward skinny events (the "option 3" from your question, which I discuss below).

    That is not to suggest that it is always appropriate to define events at this level of granularity, only that it is an avenue which is open to you early on in the project which may pay dividends later on (or may swamp you with thousands of event types).

    Going back to your actual question, let's take each of your options in turn:

    Name the event "CustomerUpdate" and include all information (updated or not) about the customer

    Let's call this "pattern" the Snapshot message.

    Snapshot messages represent the state of the described entity at a given point in time with all the event context present in the payload. They are interesting because the message itself represents the contract between service and consumer. They can be used for communicating changes of state between business domains, where it may be preferred that all event context be present during message processing by the consumer.

    Advantages:

    • Self consistent - can be consumed entirely without knowledge of other systems.
    • Simple (relatively) to generate and consume.

    Disadvantages:

    • Brittle - the contract between service and consumer is the message itself, so if the message structure changes over time this can cause issues.
    • Easy to overwrite current data with old data if messages arrive in the wrong order (hint: you can mitigate this by using the event sourcing pattern)
    • Can be large.

    Name the event "CustomerUpdate" and include only information that have really been updated

    Let's call this pattern the Delta message.

    Deltas are similar to snapshot messages in many ways, though they are usually more complex to generate and consume.

    Because they are only a partial description of the event entity, deltas also come with a built-in assumption that the consumer knows something about the event being described. For this reason they may be less suitable for sending outside a business domain, where the event entity may not be well known.

    Deltas really shine when synchronising data between systems sharing the same entity model, especially when the message is based on a diff standard like JSONPatch or JSON merge patch, and the entity is persisted in non-relational (no-SQL) storage. With this setup, an entity can be retrieved, the delta applied, and the entity then persisted again without any serialisation overhead.

    Advantages:

    • Smaller than snapshot messages
    • Excels in use cases involving shared entity models in a no-SQL storage environment.
    • Portable, if based on a diff standard such as json patch or json merge patch.

    Disadvantages:

    • Assumes consumer has prior knowledge of the data entity.
    • Easy to overwrite current data with old data.
    • Complex to generate and consume, except where there is library support (e.g. if a diff standard is used).

    Name the event "CustomerUpdate" and include minimum information (Identifier) and/or a URI to let the consumer retrieves information about this Customer.

    Let's call this the Skinny message.

    Skinny messages are different from the other message patterns you have defined, in that the service/consumer contract is no longer explicit in the message, but implied in that at some later time the consumer will retrieve the event context. This decouples the contract and the actual message exchange.

    Because the event payload is so small (usually an ID with some headers), there is no context other than the name of the event on which the consumer can base processing decisions; therefore it becomes more important to make sure the event is named appropriately, especially if there are multiple ways a consumer could handle a CustomerUpdated message.

    Additionally, it isn't good practice to include an actual resource address in the event because event messages are generally immutable, and therefore any information in the event should be true forever. In this instance a resource location address could easily become obsolete and events would not be re-playable.

    Advantages:

    • Decouples service contract from message.
    • Information about the event contained in the event name.
    • Naturally idempotent (with time-stamp).
    • Generally tiny.
    • Simple to generate and consume.

    Disadvantages:

    • Consumer must make additional call to retrieve event context - requires explicit knowledge of other systems.
    • Event context may have become obsolete at the point where the consumer retrieves it, making this approach generally unsuitable for some real-time applications.

    When raising an event, which pattern is the most suited?

    I think the answer to this is: it depends on lots of things, and there is probably no one right answer.

    Update from comments: Also worth reading, a very old, classic, blog post on messaging: https://learn.microsoft.com/en-gb/archive/blogs/nickmalik/killing-the-command-message-should-we-use-events-or-documents (also here: http://vanguardea.com/killing-the-command-message-should-we-use-events-or-documents/)