Jump to content

Actor Framework - Too much coupling?


Recommended Posts

I've used the AF three times now in delivered applications and I am finding it is "just okay".  I really like the concepts that it embodies, but its implementation of the details is very frustrating.  My biggest gripe is in the coupling between actors.  If I am actor A and want to send actor B a message, I have to call a method on actor B.  Which is fine until I want to send the same message to unrelated actor C.  It seems like actor A needs to “know†too much about the destination to be able to send messages.

 

Next on my list would be how incredibly easy it is to write an unreadable application with AF.  Coming back to code from 6 months ago, I find I am totally lost and have to rely heavily on external documentation to follow even simple operations.  Now I admit it could be my AF programming style is the problem… or maybe it’s the AF.  I’m not sure.  And then trying to follow the flow of events and information through a program built on AF… I don’t have much fun doing that.

 

Which leads into my next gripe: it is quite a complicated process to launch nested actors, generally requiring me to modify the private class data of something to store a message queue refnum.  And then routing messages between actors seems really fussy, requiring me to pass around these queue refnums, usually through modifying more private data to include more queue refnums or adding more messages to ever more actors that just route messages.

 

Finally, I wish it was easier to monitor.  Which actors are running?  Which are sending what messages when?  The AF concept seems so well suited to address all of these problems (reduced coupling, simple message routing, built-in debug/monitor) that I don’t understand why they aren’t present.

 

These are my thoughts on the AF that I have been stewing and chewing on a while.  And now I am really wondering if others have had similar experiences with LabVIEW’s AF or if it’s just me using it “wrong†or having unrealistic expectations.  Feedback, please!  And thanks!

Link to comment

I wrote a small application in it just to see what it was about. I was a utility with AF that would launch multiple actors dynamically, to communicate with multiple Real-time PXI units on a factory floor and push some VIs to them. These VIs would then be executed via VI server is parallel on each unit to do a firmware upgrade on some equipment that was attached to one of PXI's serial ports. Having multiple parallel actors running and keeping track of the upgrade process for each unit, which would take 10-15 minute, was really handy. I would keep the child actor queues in a variant hash and look them up by IP address. I was happy I wrote it with AF.

 

However, other than that one thing, I decided AF was just too heavy for MY purposes. For the kind of applications I write (machine control on cRIO), needing to launch multiple instances of an Actor is just totally unnecessary, because the number of hardware peripherals the machine is controlling is fixed. There is no need for dynamic launching whatsoever. I do make use of LVOOP to make Hardware abstraction Layers fairly frequently, and occasionally use a strategy pattern for some complicated control algorithm things.

 

I too am fascinated by the concept and genius behind its implementation-- but I am not convinced it is the way to go for most of what I do. I have had problems with people inheriting the little bit of code I wrote using AF being unfamiliar with framework and having a very steep learning curve. I have read stories on here about how large projects using it would cause the IDE to grind to halt due to coupling of actors (really not AF's fault but the IDE).

 

That is why I decided to leave it alone for the time being. I don't want to say it's bad by any means, better programmers than I have done great things with it. There is an example application written by Elijah Kerry that is a good demo of AF's potential: https://decibel.ni.com/content/docs/DOC-21441 .

Edited by MarkCG
Link to comment

GeorgeG:

a) Have you read the white paper about the AF that comes with the template projects? The section on high, low and zero coupling is relevant to your question. We are all frustrated by the lack of interfaces in LabVIEW which would simplify the system considerably.

b) For debugging the current AF, check http://ni.com/actorframework for a number of posts on the topic. In particular, check out the Monitor Actor, which adds a debug layer to the AF. Also, the Desktop Execution Trace Toolkit is your friend when debugging the AF. The 2015 version of the AF should be even better in this regard.

Link to comment

needing to launch multiple instances of an Actor is just totally unnecessary, because the number of hardware peripherals the machine is controlling is fixed. There is no need for dynamic launching whatsoever.

Yup this is a big one for me.  Our internal spin on Actor doesn't have the issue of launching and destroying actors.  Just calling all the actors in parallel just like you would any other subVI.  Then debugging tools, and techniques don't need to change.  You always have the same number of actors running, and getting references to them or knowing their state is quite easy from run-time or development.

Link to comment

A previous related conversation:"Decoupling message based systems that communicate across a network"

 

Added later: I'm a strong proponent of message decoupling, even with the string-labelled messages I use instead of the Command pattern.  I never want a component to explicitly contain text commands for anything that isn't a subcomponent of it.  Instead, and command text is injected as part of the "reply address" attached as part of the initial message received from higher-level code.  This has the great advantage of making it easier to follow code, since I don't need to place any actual commands in the low-level actors, and just need to study the high-level actors to understand the app.  The low-level actors are also more simple and reusable.

Link to comment

Thanks for pointing out that white paper.  I hadn’t read it and it was enlightening about why the Actor Framework is the way it is.  The coupling section is interesting, but it seems really quite difficult to get the zero coupling case.  I am wondering if I have been using the Framework in an efficient way.

 

Suppose we have a brain.  The brain has eyes, feet, and a mouth, which itself has a tongue.  The eyes report position and the feet can walk.  The brain starts the feet walking until it is happy with the position reported by eyes.  Maybe the brain wants to do something else while walking:  chew gum, perhaps.  So now the brain is walking and chewing gum until it is happy with the position and until the gum doesn’t taste good anymore (as reported by tongue).

 

c3hxX8a.png

 

When thinking about such a system, the actors seem obvious to me: they are the nouns...  but the relationships (callers and callees) and the messages and routing are not very obvious and seem to impact the flexibility and ease of expansion quite a lot.  It seems like the Actor Framework should really handle this kind of poorly specified, feature creeping situation well, but in practice the experience is frustrating.  Actors can’t talk to each other the way I need.  I end up making messages that just route messages.  I cheat and expose a queue.  The software is really devolving now.

 

For example, I might make the mouth actor, which has a nested tongue actor.  Tongue is periodically reporting what it tastes.  Brain needs to give this information to the chewing task to decide if the gum is still good.  I end up sending a message to mouth that just repackages the information and sends it on to brain.  But this is too much work and doesn’t add anything to clarity (for me anyway).  It gets worse when brain is just repackaging the information to send back down an actor hierarchy to one (or more) subordinate tasks.

 

It makes me want a “Tastes Like†message that tongue can send out to “registered recipientsâ€.  Other actors can route the message through the tree to the destination without knowing anything about the contents (like the post office).  But that white paper claimed that such a messaging philosophy is fraught with perilous race conditions and deadlock.

 

What are the “good†ways to get the “Tastes Like†message to the “chewing†task?  Or have I set the problem up poorly such that the previous question is ill posed?

Link to comment

A previous related conversation:"Decoupling message based systems that communicate across a network"

 

Added later: I'm a strong proponent of message decoupling, even with the string-labelled messages I use instead of the Command pattern.  I never want a component to explicitly contain text commands for anything that isn't a subcomponent of it.  Instead, and command text is injected as part of the "reply address" attached as part of the initial message received from higher-level code.  This has the great advantage of making it easier to follow code, since I don't need to place any actual commands in the low-level actors, and just need to study the high-level actors to understand the app.  The low-level actors are also more simple and reusable.

 

 

Oooh. You are so close. Won't be long now until you're talking about services instead of actors :D

Edited by ShaunR
Link to comment

Oooh. You are so close. Won't be long now until you're talking about services instead of actors :D

My actors are already services.   They’re private, rather than public, services, so access to them needs to be explicitly passed.  Rather like an unnamed Queue is different from a named Queue.

It makes me want a “Tastes Like†message that tongue can send out to “registered recipientsâ€.  Other actors can route the message through the tree to the destination without knowing anything about the contents (like the post office).  

If I were to adopt the AF, such a “Notification†and “Routing†system using “Data Messages†would be the first thing I would do.   Mouth would register for (and re-notify) Tongue’s Data Message.  Brain would register Chew to receive Mouth’s re-notified Data Message (originally from Tongue), contained in a “Command Envelope†that tells Chew what to do with the info (Command Envelopes illustrated here).  

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.