From 11:00 PM CDT Friday, May 10 – 02:30 PM CDT Saturday, May 11 (04:00 AM UTC – 07:30 PM UTC), ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

Actor Framework Discussions

cancel
Showing results for 
Search instead for 
Did you mean: 

Classifying Actor Messages by their Intent -- Still a good idea?

Recently David Staab posted a Data Broadcasting Library for the Actor Framework.  In the document explaining how to use it he describes the three classes of messages:

  1. Command (or Request): A message sent to a callee actor to tell it to do something. Because actor-oriented design allows the recipient of this message to ignore it, cache it for later processing, or act on it at will; it may also be called a Request. In AF, Commands are implemented as simple concrete classes with both data and a method that executes an action on the recipient.
  2. Status (or Event): A message sent to a parent actor to notify it that something happened. Note the past-tense language! Actors aren't allowed to control their parents, so they can't send Commands up the chain; they can only notify their parents of the occurrence of something and let the parent decide how (and even whether) to handle it. In AF, these messages should be designed as loosely-coupled pairs, with an oubound class in the child actor that holds the message data and an inbound message in the parent actor that holds the message method. The parent actor's concrete message inherits from the child actor's abstract message.
  3. Data: A message sent anywhere that only carries data; it does not dictate what should be done with the data, nor does it imply any state information along with the data. (In contrast, Commands dictate action and Events notify state changes.) This kind of message can be safely sent to any other actor, given the recipient's unique identifier, and it can be sent with any multiplicity. In AF, that means the sender needs to have a copy of the Enqueuer for every recipient of the message. If the sender wants to broadcast the message to multiple listeners, it just needs those listeners to register their Enqueuers with him. The implementation of a Data message in AF is highly dependent on minimizing coupling between otherwise unrelated actors, so it also uses a loosely-coupled message pair like the Event message.

Since the classifications are based on a post I made in Nov. 2011, I would like to take the opportunity to describe some of the issues I've run into with these classifications, how my thinking has changed since then, and get feedback from the community (especially people new to AOD) on how to categorize them in a way that helps people understand what the consequences are of various messaging decisions.

Problems with existing terminology

One frequent problem I've run into with using the term "command message" is people interpret that to mean a message that is implemented using the command pattern.  It actually has nothing to do with the command pattern.  As the title says, what is important is the intent of the message, not the implementation.  The other major problem I've seen is "command" is taken too literally.  In AOD actors never give commands to other actors; they always ask it to do something.  Hewitt calls thems "requests," which more accurately describes what they are supposed to be, but the difference is often missed by people who are learning the actor model.

"Event" messages have a similar problem.  People tend to automatically associate event messages with user events.  As described above event messages are a message classificaton meaning some event has occurred.  Users events are a message transport.  Referring to them as "status messages" is better, but I'm still not completely satisfied with it.  Furthermore, while status messages are frequently announcements of an event that has occurred in the past, they can refer to future events as well.  An actor can send out a status message saying, "I will shut down in 30 seconds."

Finally, one of the benefits of classifying messages in this way is it that it helps identify dependencies.  Generally speaking, sending a command message makes the sending actor dependent on the receiving actor.  Sending status messages does not make the sender dependent on any other actors.  This advantage is kind of lost in the current terminology.

Current thinking and proposed terminology

My current thinking is messages are defined by a 2x2 grid.  The x-axis lists the message subject, You and Me.  The y-axis is the message's role in the system's overall behavior, either Control or Benign.  All messages fit into one of the four boxes.

Considering messages from the perspective of the subject helps manage and understand dependencies.  You messages are messages an actor sends that are about the receiver.  We give these messages simple names, like SetVoltage and StartTest, but there is an implied "you" in front of each of them.  These are the messages I used to refer to as "command" messages, and it seems intuitive to me that sending a you messages means I need to know something about the receiver.  You messages are defined by the receiver.  If a message definition mismatch occurs typically the sender needs to adapt to the receiver. 

Me messages are messages an actor sends that are about itself.  We also give them simple names, like VoltageChanged and ShutdownPending.  The message name makes it apparent the subject of the message is the actor sending it, and it seems equally intuitive to me the sender doesn't need to know anything about receivers to send a me message.  Me messages are defined by the sender and a definiton mismatch puts the onus on the receiver to adapt to the sender.

The nice thing about this categorization is it clearly defines the relationships between two actors exchanging a message by identifying the subject.  The actor who is the subject of the message has the responsibility for defining the message format and parameters, and it is also the depended upon actor in the relationship.  (The strength of the dependency will vary according to implementation details.)

Thinking about messages in terms of their role in the system's behavior helps us understand where we can safely send any given message.  Control messages are those that have a significant effect on the system's functional operation.  InitiateMissileLaunch would probably be a control message.  So would LaunchTubeDoorClosed.  Both of these messages are likely to trigger a host of other activity within the system.  My current practice is to tightly manage control message routing and sequences.  (A hierarchical messaging topology works well for this.)

Benign messages are those that do not have a direct impact on the functional behavior.  LogError and TurnOnLED might be examples of benign messages.  DAQDataUpdated could also be a benign message if the collect data is simply being logged and no decisions are made based on it.  My theory is benign messages can safely violate the hierarchical message tree without risking race conditions, deadlocks, or any of the other bugaboos that make concurrency hard (since no important functional decisions are made based upon the message.)

Considering messages in a 2x2 grid like this is a new way I have started thinking about them.  There may be additional dimensions that provide more insight into how we can use a message or how it will affect the system.  If you've managed to read this far, my question is, how hard is it to grasp the ideas I'm trying to present here and does it help explain how to create and use messages in a way that meets other project requirements?  This is one of those things that is very clear in my head, but my inability to get out of my head means I don't know how well it resonates with other people.

Message 1 of 27
(21,787 Views)

Perhaps, Benign would better be termed Passive? The opposite of benign is most nearly malignant, and I hope that Control messages are not Malignant. 🙂

Dave, would you give feedback on my understanding of the semantics of your quadrants?

Me/Control: Request (to myself)

You/Control: Request (to you)

Me/Passive: Inform/Notify (of something that happened to me, including state changes)

You/Passive: ??? (how would an actor send a message informing of another actor's state change?)

Does a Response to a Request have a first-class badge, or is it a subset of Me/Passive?

0 Kudos
Message 2 of 27
(4,699 Views)

Dave:

I like it, particularly the me/you part. I have been classifying my messages like this for a while and it really helps. I use the message name to specify the subject of the message... something like this:

  • Lower case names for subjects, dot-model for hierarchy.
  • Capitalised names for actions

So, example message names might be "ui.RefreshGraph", "hw.camera.AcquireImage". This makes it clear to me exactly who the message is about.

Jack:

My understanding of the y-axis is a little different. I interpreted it more generally than "Inform/Notify", but rather that these messages could encompass anything that is not critical to the operation of the system. In this way, your "You/Passive" category could include things like "hey dude, refresh your graph!"... the subject is another actor, but the action is just cosmetic.

0 Kudos
Message 3 of 27
(4,699 Views)

fabric wrote:

My understanding of the y-axis is a little different. I interpreted it more generally than "Inform/Notify", but rather that these messages could encompass anything that is not critical to the operation of the system. In this way, your "You/Passive" category could include things like "hey dude, refresh your graph!"... the subject is another actor, but the action is just cosmetic.

This is strikes me as a leaky abstraction, if the message is "ui.RefreshGraph". I see RefreshGraph as a private, encapsulated action (conditionally, optionally, but most likely) performed when the UI actor receives a NewData notification (an incoming Passive/Me) ... for an external actor to have a "passive command interface" into the actor is sorta leaky... no?

For instance, I'm used to treating UI refreshes as essential and crucial, not cosmetic -- the You/Passive seems to place a value judgment on the criticality of the action performed by the subject to which the request is sent... no?

0 Kudos
Message 4 of 27
(4,699 Views)

JackDunaway wrote:

Perhaps, Benign would better be termed Passive?

I've struggled trying to think an appropriately descriptive word for it.  I considered passive, but it's not quite right.  Fabric identified the gist of it--a benign message isn't necessarily passive, it's just that any actions that result aren't critical to the actor's [system's] behavior.  Purely cosmetic actions are benign, but I don't think an action has to be purely cosmetic for it to be benign.  I think any action that doesn't change the actor's [system's] behavioral state could be benign.  (There's a lot of wiggle room between a cosmetic action and an action that doesn't change behavioral state.  I'm not sure where the line dividing control and benign messages is.  All I've come up with so far is a control message must be able of causing a "significant" change in the overall system.)

[Edited for clarity]

JackDunaway wrote:

Me/Control: Request (to myself)

You/Control: Request (to you)

Me/Passive: Inform/Notify (of something that happened to me, including state changes)

You/Passive: ??? (how would an actor send a message informing of another actor's state change?)

Does a Response to a Request have a first-class badge, or is it a subset of Me/Passive?

Me/Control - I suppose this could be a request to myself, but I almost never have actors send messages to themself so I didn't think of it in those terms.  I was thinking more along the lines of sending a notification about myself that triggers significant changes.  For example, if a missile were seconds away from ignition and the LaunchTubeHatchActor sent a LaunchTubeHatchClosed messsage, the MissileLaunchActor should probably drop out of the Launching state and enter some sort of Error state.

You/Control - Correct, this is a request to you that has a significant effect on the overall behavior.

Me/Benign - Any message about me that does not trigger a significant change in the overall behavior.  It can include a state change, if me changing state doesn't impact the rest of the system.

You/Benign - Fabric's example is good.  "RefreshUI" is a message I often use that I would classify as a You/Benign message.

Given that a request requiring a response is asking for information from the actor receiving the request, the response is categorized as a Me message.  Once again, Control/Benign depends on the effect of the message on the system.

-----

Me/You message categorization can be figured out by looking at each actor in isolation.  I don't think you can do that with Control/Benign categorization.  You really need to look at your design from the system level and understand how the actors interact with each other and what the messages do. 

0 Kudos
Message 5 of 27
(4,699 Views)

So you're saying "ui.Refresh" was a bad example?

I agree that the Refresh action is almost certainly performed by the UI itself, but I disagree that it is necessarily private. Consider a very large data set that we do not want to redraw every time a new point arrives. The UI may perform a scheduled Refresh every minute, but an external actor may also request a Refresh any arbitrary time.

Irrespective of who requests it, the Refresh itself is benign in this case since no other actor depends on it... It is purely a user convenience.

0 Kudos
Message 6 of 27
(4,699 Views)

JackDunaway wrote:

This is strikes me as a leaky abstraction, if the message is "ui.RefreshGraph". I see RefreshGraph as a private, encapsulated action (conditionally, optionally, but most likely) performed when the UI actor receives a NewData notification (an incoming Passive/Me) ... for an external actor to have a "passive command interface" into the actor is sorta leaky... no?

It all depend on how you divvy up the responsibilities of your actors.  I commonly have 2-4 actors working together on a UI.  One handles the inputs from the user, one or two to handle display updates, and one to coordinate their activities and interact with external actors.  I personally probably wouldn't expose UI.RefreshGraph message somewhere outside of the UI component, but an actor can still expose that message to other actors within the UI component.

0 Kudos
Message 7 of 27
(4,699 Views)

fabric wrote:

So, example message names might be "ui.RefreshGraph", "hw.camera.AcquireImage".

That's an interesting idea.  I commonly use dot notation to identify the sender of the message rather than the subject.

How do you handle situations where you have multiple instances of the same class sending Me messages?  For example, if you have two identical cameras and they both send hw.camera.ImageAcquired messages to the same receiver.  How does the receiver know which camera the message came from?

I ran into this problem with LapDog and (thanks to some insightful suggestions from James) the Prefix Queue came out of it.  It's not a perfect solution, but it's workable and helps clarify the messaging topology.

0 Kudos
Message 8 of 27
(4,699 Views)

Daklu wrote:

fabric wrote:

So, example message names might be "ui.RefreshGraph", "hw.camera.AcquireImage".

How do you handle situations where you have multiple instances of the same class sending Me messages?  For example, if you have two identical cameras and they both send hw.camera.ImageAcquired messages to the same receiver.  How does the receiver know which camera the message came from?

I have never parsed the name of the message class to determine the identity of the its subject (although I suppose I could do that for single-instance actors)... Rather, I use the terminology to help me understand the intent of my messages at a glance.

Ahh - I think I just realised something. In LapDog each message is given a "name" as part of the message data, right? That is not the "name" I was talking about... I was referring to the name of the message class itself, e.g. "hw.camera.AcquireImage.lvclass".

0 Kudos
Message 9 of 27
(4,699 Views)

Two comments:

  1. You could try "neutral" or "inaction" instead of "benign". I would suggest "parve", but I get the feeling the number of people who would have an instinctual understanding of it would be somewhat limited.
  2. Do you even need the distinction? I see that you're struggling with defining the line between control and benign, and that's probably because there is no such hard line. Why not just treat all messages the same and let the reciever decide what the importance of each message is?

___________________
Try to take over the world!
0 Kudos
Message 10 of 27
(4,699 Views)