03-09-2020 07:00 AM
@AristosQueue (NI) wrote:
Also, proving that there isn't a cycle is a hard thing. Why not start with an infrastructure that pushes back on that ever existing in the first place?
That I can strongly agree with, though I'm using a different infrastructure that uses different methods to discourage cycles.
03-09-2020 08:39 AM
@drjdpowell wrote:
That I can strongly agree with, though I'm using a different infrastructure that uses different methods to discourage cycles.
For anyone else reading this, a bit of AF history:
jdpowell and I have largely the same goals in creating messaging systems... we were working on the same problem of "too many people build aysnch systems that are unreliable." Ne* was one of the key people helping me create the Actor Framework. Ne has nir own framework for messaging because ne opted to optimize for a different set of requirements than I did.
I do not insist that everyone needing async messaging use the Actor Framework. I do insist that anyone needing async messaging understand why the Actor Framework works the way it does before attempting their own! 🙂
* As gender is not relevant to business operations, and frequently I do not know the gender
of employees and customers that I meet online, I use these neutral pronouns for all people.
ne=he/she nem=him/her nir=his/her nirs=his/hers nemself=himself/herself
03-09-2020 10:04 AM
Encouraging a tree dependency structure in an application's architecture is a topic that is independent of the framework being used. I wish there were more presentations about this rather than all the presentations that exist about a specific framework. The more general subject of architecture is often times independent of the framework being used.
I want to see a presentation that illustrates a few before/after case studies where an initial architecture with graph dependency relationships was improved by refactoring to have a tree dependency structure. If I had the examples, I'd create this presentation myself. I think it would be tremendously useful to the community.
I'm working on a project that uses another framework (not Actor) and I started with a tree dependency structure before I gave in and added some dependencies to reduce the number of messages bouncing back and forth in the application. DCAF exists at the low level, which isn't necessarily relevant because it's wrapped by a class called IO_Manager that acts as a gatekeeper for all hardware IO. I attached a simplified version of the UML diagram. I highlighted the two dependencies I added that broke the tree hierarchy. I resisted doing this until the frequency of hardware IO reads/writes became significant enough to warrant it.
If I'm understanding Steven correctly, his premise seems to be that most applications would be better designed if the dependency hierarchy was a tree structure. One of the reasons I find this so interesting is because sometimes I work with very experienced developers who make no effort to adhere to this guideline. If the guideline is so beneficial, why does it seem so few follow it?
Eric
03-09-2020 10:25 AM
> If the guideline is so beneficial, why does it seem so few follow it?
Lots of reasons, many of which are reflected in this conversation already.
03-09-2020 10:37 AM
@drjdpowell wrote:
@AristosQueue (NI) wrote:
Also, proving that there isn't a cycle is a hard thing. Why not start with an infrastructure that pushes back on that ever existing in the first place?
That I can strongly agree with, though I'm using a different infrastructure that uses different methods to discourage cycles.
Since cycles can have an arbitrary number of participants ie A->B-C->D->...->A, the only way to possibly avoid coding them is to know exactly who each participant is observing and keep track of all that. That is a daunting task in a program of any real size. Not to mention that dynamic loading makes it impossible to tell who is observing who at edit time.
03-09-2020 11:20 AM
I agree with you, AQ, but at the same time I sympathize with the people that break form for the reasons outlined below:
@AristosQueue (NI) wrote:
3. "I have to write a lot of message-translation code that way." Fails to recognize that they probably should be writing that code already for their module to be reusable and their application to be maintainable in the future.
I think this is the biggest hump, honestly. Doing things the "right" way is seldom easy. Writing robust, reusable code requires far more thought and foresight than just grabbing a queue or making everything public (A similar pitfall in the OOP world), and when it comes to a robust, reusable, modular messaging system? That's tantamount to reinventing the DNS server or mailer daemon (I exaggerate, but only a little.) I'm honestly surprised there wasn't more inbuilt support for message management in the Actor Framework itself, a la C#'s LINQ. This ties in nicely to point 2:
2 ."Going through the tree is too expensive in terms of performance." People first make false assumptions about how expensive messaging is up and down a tree. Then they make false assumptions about what percent of their app's time is taken in message sending. Even if up-and-down-tree is 100x the time to direct send, if the time to direct send is microseconds, 100x is irrelevant to most applications because the time is spent in the data processing loops
And how would one go about profiling the two approaches? By writing a lot of message-translation code. It's a catch-22, in order to decide if putting in the time to write the code needed to send a message all the way up and down the tree, you have to write the code needed to send a message all the way up and down the tree. Again, having some sort of inbuilt class or interface (interfaces combined with an "addressed message" message child class would be amazing for this) you could just slap on the actor framework to test things, even if it doesn't support everything or support it perfectly, would make it a lot easier to win people over to the light.
And, seriously, how many programmers sit around and question whether the fundamental underpinnings of computer science are weak and need fixing?
Who has the time to when there's so much code to be written and work to be done? That's what it boils down to, isn't it? Planning good code takes time. Writing good code takes time. Fully commenting and profiling your code--say it with me now!--takes time. I'm thankful for what we have already, the actor framework has saved me so much time, but that third pillar of the framework, Message Transport, could definitely use more support to match its message and actor brethren.
03-09-2020 11:30 AM
@m3chtroid wrote:
Again, having some sort of inbuilt class or interface (interfaces combined with an "addressed message" message child class would be amazing for this) you could just slap on the actor framework to test things, even if it doesn't support everything or support it perfectly, would make it a lot easier to win people over to the light.
What would this look like? In case it's obvious from your previous post, please assume I'm not familiar with LINQ.
03-09-2020 12:24 PM - edited 03-09-2020 12:26 PM
Granted, it's been a while since I've used actor framework and I'm not sure if this violates any tenents, but let's follow the postal service metaphor. I'm imagining a child of message.lvclass named "Message Envelope" that contains a single message object and metadata about the contained message and its recipient. (The full extent of which I'm unsure on right now. At the very least some sort of GUID-like "postal address" string for sending to a specific actor, maybe a class identifier so that you could say "Send this to all members of the tree of this actor type or its children. If you want to go deeper, include info about the sender so you can "bounce" messages that failed to send back to them)
The interface would define a few VIs that would allow its members to route these messages correctly, namely:
...That's it, I think? Yeah, it's open to abuse, (Self stamped return messages slightly reek of the Observer pattern) but it'd be a start, and definitely be enough to do profiling on arbitrary messages, and it's easily extensible to solve problems of the root actor being spammed like @egraham mentioned by modifying the topology of the index instead of changing the inheritance of the actors!
03-09-2020 01:26 PM
> I'm imagining a child of message.lvclass named "Message Envelope" that contains
> a single message object and metadata about the contained message and its
> recipient.
You violated a tenant already. 🙂
How does the sender know the message recipient in order to address the message.
This is a key question.
In the default AF, the actor knows only about its one direct caller and its direct callees. You literally cannot write code to have anyone other than that as a recipient, and there's no need for the metadata because sender puts the message directly into the queue for the recipient.
In other observer/subscription systems, there's a naming system or a dynamic pattern matching system that hooks actors together or there's a common message bus and receivers check all messages that appear on the bus to claim the ones they know how to handle. And in extreme versions of this, there's some sort of path routing specification or some sort of broadcast system where you have to have metadata.
But the whole point of the AF design is that an actor ONLY gets messages that are meant for it. You don't write messages that are intended for some actor further than 1 step away because an actor doesn't know about those actors even existing.
The AF has a different postal service (queue) for every receiver. There's no metadata.
03-09-2020 02:04 PM - edited 03-09-2020 02:12 PM
@AristosQueue (NI) wrote:
You violated a tenant already. 🙂
How does the sender know the message recipient in order to address the message.
This is a key question.
You've activated my trap card! (I kid, I kid)
I was actually coming back to the thread specifically to point out that I very purposefully didn't mention anything about how the sender would know this message recipient, nor did I (mean to) imply that any member in the chain had any queue other than their caller and callees. In fact, the base proposal only had recipient metadata, meaning there was no way to know if the message was sent to anybody, in keeping with the principle that messages are requests, not commands.
I want to reiterate, this would be a structure that would easily let a developer profile transit times and message overhead for any arbitrary form of message propagation, allowing them to quantify the (likely minimal) impact the message framework has on the program's performance! In fact, the original aside that led to me outlining this idea on the figurative back of a napkin was about how useful it'd be for profiling. Something like that would be an invaluable tool in correcting those unfounded assumptions how "scalable" sending messages up and down the tree really is, which was what led us down this rabbit hole in your original reply! Principles and best practices are great, but I find cold, hard, (hopefully easy to implement and test) facts are what best persuade people.
That said, it is a common pattern in the framework that an actor wants to send a message to its caller with the express purpose of the caller relaying that message elsewhere. In fact, one of these is so common and important that it's already built into the framework: the Last Ack. Oftentimes, status reports like "the temperature is 75" percolate upwards as each actor acts on that information and then reports "the temperature is 75" to its caller. My purpose with the suggestion was not to imply that this was the correct (though often necessary) behavior, but it definitely would be able to ease the busywork of implementing "go tell your dad" messages into a framework that would at least be able to minimize the damage done by people misusing it. Better the devil you know, and all that jazz.