Pergunta

Are events which are intended to tell listeners to carry out explicit actions an anti-pattern?

Imagine a worker service which raises the event WorkStarted at its beginning and the event WorkFinised at its end.

These events convey information about what that worker service did and they are not inherently imperative to any of the potential subscribers of that event.

Consider that it may be the intention of the application to use this event to show or hide a loading icon. Is it an anti-pattern for the worker service to raise a ShowLoadingIcon and HideLoadingIcon event instead?

In this case no information about what the worker service did is conveyed, only an instructive request is made.

In what cases, if any, are either these approaches inappropriate or preferred?

EDIT: To clarify, I'm asking about the existence of standards for event-driven programming. All standardization questions include some amount of opinion, and yet the site is littered with them because there is a different between a question of personal preference and one of generally accepted good practice.

Foi útil?

Solução

The way to decide what an event should represent is the good old Single Responsibility Principle.

If, for instance, you have a long-running tax computation process and an incremental GUI visualization that displays its progress, then the tax processor should raise "started", "progress" or "finish" events. A GUI class should listen to these events and do whatever is appropriate GUI-wise, e.g. show or hide the "wait..." icon.

That way, the tax processor processes taxes, and the GUI class renders a GUI. If you defined a "HideWaitIcon" Event, then the tax processor would have to know about GUI details, which isn't it's job (and which would make it harder to write a different front-end for the same back-end). That's why our first solution is superior.

Outras dicas

It is none of your business what I intend to do when your API raises an event. Maybe I will show an icon, maybe I will order coffee for the lead developer, start a music video, whatever I do, it's my business not yours. The point of the event is to notify those that are interested that something has happened, after that, it's no longer your conceern.

As a developer, it's your job to determine what events are usefully reported -- CompletedFirstStepOfSecondLoopInMethodA probably isn't of interest to anyone. But once you have determined that something should be reported, your part is done. What is done on the other end of the event isn't up to you.

In every well-behaving event-driven architecture, there must be some rules that specify some partial ordering (timeline) for the events that will occur in response to some operations.

Example:

If these orderings are violated, even by just a little bit, the event-driven world falls apart. This gives rises to non-deterministic or hilariously triggerable bugs such as "application crashes when I mouse over the menu bar when the application is doing (something)".

Events come from a source, and are dispatched to one or more listeners.

There is no requirement that the framework must perform this dispatching in a strictly deterministic and imperative manner. In other words, although the following is a very popular mental model among programmers, the framework is not necessarily implemented in that way.

  • New event - push a new message into a queue.
  • Framework - for every message that has one or more listeners, distribute (replicate) it to its listeners.
  • Each listener waits for a new message from the queue.
  • Each listener takes and processes the new message.

Notice that event types might be defined based on either the source (e.g. Work can have events WorkStarted and WorkFinished), or on actions (affordances) it can perform (e.g. ProgressIcon can receive ShowLoadingIcon, ShowFinishedIcon, or ShowFailureIcon.)

In some frameworks, the source-defined events and action events are separate types and given separate terminologies (such that the latter are not called "events" at all.) In some other frameworks they are both called events, because of the framework's choice to implement events using a unifying concept called delegates, which has a programmer's mental model that is very similar to callback functions.

You should be able to see where your confusion comes from: because the framework you're using makes everything looks like function calls, you have the temporary illusion that everything you can do with function calls, you can also do with delegates, and by extension also do anything with events. However, this is not the original intention of event-driven architecture.

In addition, programmers that use different frameworks will never face this confusion, and will have a hard time understand why this question arises.

Licenciado em: CC-BY-SA com atribuição
scroll top