Live data from Hacker News

Events: Fat or Thin?

codesimple.blog

31–40 of 61 posts

Re: Events: Fat or Thin?

#31
I'll bite. Neither. Both. Depending on system.

When the "state" is large, or changes often, obviously you can't send full state every time - that would be too much for end-nodes to process on every event. Both cpu - deserialization, and bandwidth. Delta is the answer.

Delta though is hard, since there always is an inherent race between getting the first full snapshot, and subscribing to updates.

On the other hand doing delta is hard. Therefore, for simple small updated not-often things, fat events carrying all state might be okay.

There is a linear tradeoff on the "data delivery" component:

- worse latency saves cpu and bandwidth (think: batching updates)

- better latency burns more cpu and bandwidth

Finally, the receiver system always requires some domain specific API. In some cases passing delta to application is fine, in some cases passing a full object is better. For example, sometimes you can save a re-draw by just updating some value, in other cases the receiver will need to redraw everything so changing the full object is totally fine.

I would like to see a pub/sub messaging system that solves these issues. That you can "publish" and object, select latency goal, and "subscribe" to the event on the receiver and allow the system to choose the correct delivery method. For example, the system might choose pull vs push, or appropriate delta algorithm. As a programmer, I really just want to get access to the "synchronized" object on multiple systems.

Re: Events: Fat or Thin?

#32

Earlier quoted context omitted.

> thin events reduce coupling. Sure, the receiver might call an API and that creates coupling with the API. You make a statement in the first sentence, and in the next sentence produce evidence ... that the statement is wrong. And, YMMV. It is my experience that thin events add coupling. If service B receives an event, and wants to process it ASAP (i.e. near real time) and so calls back over http to Service A for the…

b) You're asking for occasional "eventual consistency" trouble when A's state lags or has moved on ahead of the event If you allow A's state to lag behind it's own events, then how are you ever going to create a sane system? Surely A either has to be ahead or at the state that caused the event to emit, or events are pointless.

If you allow A's state to lag behind it's own events

That's a mischaracterization. A's state is not lagging its emitted events; instead, A's state may have been changed at the time A's event is processed.

Re: Events: Fat or Thin?

#34

> Thin Events add coupling That’s not my experience. In fact I’d say fat events add coupling because they create an invisible (from the emitter) dependency on the event body, which becomes ossified. So I’d say the opposite: thin events reduce coupling. Sure, the receiver might call an API and that creates coupling with the API. But receivers are also free to call or not call any other API they want. What if they don’…

I also disagree with the article - thin events don't always result in more coupling, and I'll add that thin events can remove temporal or state coupling as illustrated below. However, the caveat is: as with many things I think choosing one team or the other has nuance and depends on the specific scenario.

An example: I'm using thin events in a master data application integration scenario to send a 'sync this record' type of command message into a queue. The message body does not have the record details, only the basic information to uniquely identify the record. It also doesn't identify the type of change except for a flag to identify deletes. The 'sync' message is generalized to work for all entities and systems, so routing, logging, and other functions preceding the mapping and target operation have no coupling to any system or entity and can expect a fixed message format that will probably never change. Thus versioning isn't a concern.

Choosing team 'thin event' does result in an extra read of the target system, but that is a feature for this scenario and what I want to enforce. I can't assume a target system is in any particular state, and the operation to be performed will be determined from the target system at whatever point in time a message is processed, which could be more than once. If the message ended up in a dead letter queue, it can be reprocessed later without issue. If one production system's data is cloned down to a lower environment, the integrations continue to work even if the source and target environment data is mismatched. No state is stored or depended upon from either system and the design is idempotent (ignoring a target system's business rules that may constrain valid operations over time).

In contrast, other scenarios may benefit from or require a fat event. I've never used event sourcing, but as others mention, if current state can be built from all previous events 'rolled forward' or 'replayed', then each event must be a stand-alone immutable record with all information - thin events cannot be used. Or, if a scenario requires high performance we might need to use a fat event to eliminate the extra read, and then compensate for the other consequences that arise.

Re: Events: Fat or Thin?

#35
post #31

I'll bite. Neither. Both. Depending on system. When the "state" is large, or changes often, obviously you can't send full state every time - that would be too much for end-nodes to process on every event. Both cpu - deserialization, and bandwidth. Delta is the answer. Delta though is hard, since there always is an inherent race between getting the first full snapshot, and subscribing to updates. On the other hand doi…

This omits the issues with "thin events" - it may be fine most of the time, but as it usually involves a "get more details" call over http or of some other kind, it has more moving parts, is therefor more prone to failures and slowdowns due to the extra coupling. This can kick in when load goes up or some other issue affects reliability, and cause cascading failure.

Re: Events: Fat or Thin?

#36
post #33

When will people settle on the fact that there is no silver bullet? It's always a matter of trade offs according to the system needs.

Because the very real downsides of thin events are not simple or obvious. It may be fine most of the time, but as it usually involves a "get more details" call over http or of some other kind, it has more moving parts, is therefor more prone to failures and slowdowns due to the extra coupling. This can kick in when load goes up or some other issue affects reliability, and cause cascading failure.

Re: Events: Fat or Thin?

#37

Earlier quoted context omitted.

Sure, but in a thin events model someone would "own" the events since otherwise the subscriber wouldn't know where to query the actual data. What would you even do with an event saying a customer changes address if querying that address then produces the old one. I'm genuinely curious how such an architecture would work. You don't have to respond directly here, but if you have any reference to further reading, I'd ap…

> I'm genuinely curious how such an architecture would work. Complex systems are the way that they are because they got that way over time. It is not my goal to defend or even characterise a system that I did not create. I am here telling you the issue that I saw: one event consumer, at an edge case, ran substantially behind another, and when they attempted to co-ordinate over http, this failed. And how it was succes…

Ah, so A and C where both subscribed to B, but during A's processing of the event it assumed C had already processed it and tried to look up some state. Is that correctly understood?

This sounds more like an architectural deficiency (as you say probably from architectural decay) than a systematic design edge case. I can't quite understand what information A would need to get from C that could be included in the fat event but not simply queried from B.

Re: Events: Fat or Thin?

#38
For me, this depends on the semantics of the system. Is the sender commanding the receiver to carry out the rest of the process, or is the sender broadcasting information to a dynamic set of interested parties? In other words, are you building a pipeline or a pub-sub?

If the former, there is inherently tight coupling between sender and receiver, and the sender should send all necessary context to simplify the system design.

If the latter, then we talking about a decoupled system, where the sender cannot make assumptions about what info the receiver does or doesn't need to take further action. A thin event is called for to keep the contract simple.

One of my frustrations with the event-driven trend is that people don't always seem to think through what they're designing. It's easy to end up with a much more complex system than a transactional architecture.

Generally, I favor modeling as much of my system as possible as pipelines, and use pub-subs sparingly, as places where you have fan out to parallel pipelines.

Raw events are like GOTOs. They are extremely powerful, but also very difficult to reason about.

Re: Events: Fat or Thin?

#39
post #32

Earlier quoted context omitted.

b) You're asking for occasional "eventual consistency" trouble when A's state lags or has moved on ahead of the event If you allow A's state to lag behind it's own events, then how are you ever going to create a sane system? Surely A either has to be ahead or at the state that caused the event to emit, or events are pointless.

If you allow A's state to lag behind it's own events That's a mischaracterization. A's state is not lagging its emitted events; instead, A's state may have been changed at the time A's event is processed.

The comment I quoted says:

> when A's state lags or has moved on ahead of the event

That sounds like it can EITHER be ahead or behind. Specifically, I do not understand it as A's state can either lag OR be ahead, not that "lags" is a synonym for "moved ahead"

Re: Events: Fat or Thin?

#40
post #31

I'll bite. Neither. Both. Depending on system. When the "state" is large, or changes often, obviously you can't send full state every time - that would be too much for end-nodes to process on every event. Both cpu - deserialization, and bandwidth. Delta is the answer. Delta though is hard, since there always is an inherent race between getting the first full snapshot, and subscribing to updates. On the other hand doi…

>Delta though is hard, since there always is an inherent race between getting the first full snapshot, and subscribing to updates.

Since the deltas include a version identifier for what they should be applied on top of, then you should always be able to safely start by requesting the deltas, then ask for the object. Buffer the deltas till your full copy is received, then discard deltas for previous versions until the stream applies to yours, applying them thereafter to keep it up to date.

Post reply on HN