3 ms·
> Choose event-driven communication wherever you can. When designing a new system, start with events. This article advocates for event-driven systems, but elid
by pphysch 3y ago
> Choose event-driven communication wherever you can. When designing a new system, start with events.
This article advocates for event-driven systems, but elides their subtle but major downside over request-response: they make your control flow "non-linear" and very difficult to reason about and analyze statically. That is, when an event fires, what happens in response? Well, any bit of code in the entire system could be triggered by it.
Events are powerful, but very much a double-edged sword, similar to GOTO.
- erhaetherth 3y agoWe have this problem at my work. Some components listen for events, but where did they come from? I have no idea, I didn't write the entire stack, and there isn't an easy way to trace it. Similarly, if I send an event (and this may be JS/DOM specific), who is going to catch it, and are they going to prevent it from bubbling up to other listeners (potentially breaking them)?
- hinkley 3y agoI had a logic bug in some new code this week and was reminded that in JavaScript, if you emit an Error and there are no handlers, it bubbles back up to the emitter as an exception. Someone’s notion that they didn’t want errors to go unhandled. So I had to rewrite the logic so the conditional for reporting the error was inside the listener instead of around it.
- lutzh 3y agoThanks for your feedback! Of course we all have our "bubble", we make our own experiences, and if we share our learnings, they might not always match what other people have experienced. In practice, I feel a statement like "any event could trigger any bit of code in the entire system" a bit exaggerated. When I think of event driven systems, I think of business applications, where a large number of microservices interoperates mainly over Kafka. So the services that are triggered by an event are already limited to those subscribing to a specific Kafka topic. Of course if you follow the chain of subsequent events (i.e. service A emits an event, with leads to service B emitting events, with lead to service C and D emitting events..), you might not be aware for every event what'll happen way downstream. But you can turn this into an architectural strength, as it leads to better decoupling and separation of concerns. On another note, as you describe GOTO as a double sided sword, now I really wonder what the positive side of GOTO is..
- pphysch 3y agoEvent-driven communication is appropriate for implementing hooks for external consumers. "Firing an event" is roughly equivalent to "running an undefined set of procedures in an undefined order". That's useful, because consumer behavior is usually undefined, or at least far outside the scope of a single software system. Your system firing the events should assume the size of that set is 0. That is, it should not rely on its own events for its internal control flow, why introduce what is essentially UB? That would be like a webserver querying its own HTTP endpoints instead of its local database for the same data. Abusing external interfaces for internal purposes. Wasteful and difficult to trace.
- roeles 3y agoI guess erlang is an example of keeping your flow linear, albeit at the cost of searching through the incoming event queue and thus reordering of events.
- iudqnolq 3y agoCan you clarify? I haven't seen people peek at messages without consuming them in Erlang. Even so I don't see how this gets you reordering.
- toast0 3y agoI'm not quite sure, but I think what they're getting at is that when you send a message and immediately wait for the reply, that's generally a selective receive: in the optimized case, it inspects all inbound messages from after you created your outbound message; in the non optimized case, it looks through the whole process mailbox before waiting for new messages. Either way, it's processing some inbound messages before others for a process that is getting messages for requests as well as responses. Personally, I have seen ocassional attempts to prioritize inbound queues, but it gets unwieldy quickly: you end up either reading nearly the whole mailbox on each iteration, or having to queue non-priority messages yourself, or do terrible things in erts code to add the ability to send to the front of a mailbox.
- roeles 3y agoAs far as I understand, the receive[1] call performs pattern matching on messages in the queue. If no match is found, the call blocks until any of the patterns match. If a match is found, the first match is returned. Since you perform this pattern matching, this means that messages may not be processed in the order they were received. [1] https://www.erlang.org/blog/message-passing/ https://www.erlang.org/blog/message-passing/
- hinkley 3y agoIncluding the bit that fired the original event. Event loops have happened in every event driven system I’ve ever encountered. The original proponents having sworn that nothing like that would happen, and yet it did. Code is a collaboration. Everyone is putting their ideas into it. And some days our best ideas aren’t very good. Systems that require constant vigilance always unravel in the end, and event based systems require constant vigilance. With an event system, if the loop happens infrequently enough, it will only result in a slight decrease in throughput of the system, and so the system will continue to work for hours, days, even weeks. And once a bug has survived for more than a few weeks it becomes difficult to triage.