My last post discussed the different types of coupling between actors in a data-centric event-driven application. This post will follow up with a deeper look at semantic coupling in these data-centric event-driven applications and I will propose a way to loosen this type of coupling. Before diving into how I am loosening the semantic coupling between my actors I want to give a little context on how the data is passed between actors and where the semantic coupling exists. This discussion will be centered on the implementation of the mediated message bus that I have talked about in other posts and that you can download on the Tools page. (The VIP for download on the Tools page is now two major revs behind, I am planning on making this project open source and hosting it through the Composed Systems github. Contact me if you are using this code and would like to get the most up to date version.) The image above shows an example of an actor registering as a publisher and a subscriber of data. Area 1 is pointing out the yellow object wire, this yellow object wire is the message broker object. It is actually a cool by-ref implementation of the message broker object, but I will leave the details to this. Area 2 is showing the actor registering as a publisher for "Ellipsometer Data" using a method of the message broker class. Area 3 is showing a Queue Message Transport object wire that is an output of the publisher registration method. The actor will use this object wire to publish data. Area 4 is showing the actor registering as a subscriber for "Ellipsometer Recipe" data using a method of the message broker class. Area 5 is showing the creation of the Event Message Transport object, which is passed into the publisher regsitration method as an input. Lets anthropomorphize the parts of code to make their interactions easier to understand. Meet Sam the Subscriber, Phil the Publisher, Bob the Broker, and Tannin the Topic Actor. You can find Sam in Area 4 above, Phil in Area 2 above, and Bob in Area 1 above, but you won't find Tannin because he is an asynchronous actor running headless that you didn't even know was being launched. Lets walk through their interactions. Area 1 is simple, it just shows that we have a message broker object. For our purposes all that we care about is that Bob exists. When the actor registers as a publisher of data the message broker object checks to see if a topic of that name exists already. You can see this in Area 2 above. If Bob doesn't find a topic with that name then he will create a new topic actor to handle that topic. After Bob creates the Tannin that will handle the "Ellipsometer Data" topic, said Tannin will give bob a Queue Message Transport Object that Bob can then pass back to an actor. You can see the queue message transport in Area 3 above. The actor will use this message tranpsort to send data to the topic actor for broadcasting. If the topic actor for "Ellipsometer Data" had existed already then Bob would not have needed to create one, he would have simply retrieved its message transport and passed it back out. Now let's supose that Sam wants to subscribe to Ellipsometer Data, Sam will register with Bob the message broker as a subscriber and as part of the registration Sam will dictate how he wants to receive data. In this case Sam has passed in a User Event Message Transport Object. You can see the creation of this object in Area 5 above, and the subscriber registration in Area 4. Note that it does not matter if the publisher or the subscriber registers first, the topic actor will be created for the first one to execute. This example just shows the publisher registering first so that it matched the block diagram above. In the last post we looked at space, time, and synchronization as types of coupling between actors. These three types of coupling can be called syntactic coupling as they all have to do with how the actors interact with each other. Semantic coupling is different because semantic coupling refers to the behavioral dependencies between actors. Every actor implements some tangible behavior. Actor A calls actor B, which couples the actors both at a syntactic and semantic level. At the syntactic level, actor A must use actor B's address, send a message to actor B while it is live, or be blocked waiting for actor B to respond - all of which are forms of coupling that we can alleviate through data-centric event driven architectures. But actor A also expects some specific behavior from actor B – which is a form of semantic coupling. This semantic coupling could be related to expectations of data types being published on the producer side and subscribed to on the consumer side, as an example. So where does the semantic coupling come in with our example? Notice that nowhere in the subscriber/publisher registration process is a data type defined. There is an assumption being made that the publishing actor and the subscribing actor will use the same data type for a given named message in a given named topic. On the subscriber side, when data comes in from a topic actor we typecast it to the type we expect and we have to handle the error coming out of the "To More Specific Class" node because there is no guarantee that we will get the type that we expect. It is this reason that we say that the publishing actor and subscribing actor are semantically coupled together. The actors are semantically coupled because to the expectation of a certain data type for a named message in a named topic. Before moving forward I wanted to mention one thought, it may seem powerful to be able to put multiple data types in a topic and have the subscribing actors use the error output of the to more specific class typecast act as a filter on what data it can handle. I can definitely see the flexibility here but I think that it comes at the cost of readability. I believe that our software's readability directly correlates to our software's simplicity. So how can I loosen the semantic coupling between my actors? My idea is to change the registration process so that instead of having publishers and subscribers register by topic name without restriction on data type, they will register by data type without restriction on topic name. Registering by type will ensure that subscribers only ever get the type of data that they registered for. This idea does not fully remove the semantic coupling between actors as they both have to be using the same data types. Interestingly enough this restriction seems to actually be a core feature of the data-centric approach to software development. When I write my software I find that I begin by defining a global data-space and then writing actors that use those data definitions. Anyhow, I am curious to get people's thoughts on this, so if you are interested leave a comment below. Jon McBee is the Founder and Managing Partner at Composed Systems and is a Certified LabVIEW Architect, Certified LabVIEW Embedded Developer, Certified TestStand Developer, an NI Certified Professional Instructor, a LabVIEW Champion, and a Certified ScrumMaster
11 Comments
Ryan Vallieres
1/20/2017 10:56:55 am
Hey Jon! Nice article on semantic decoupling. I almost always favor on the side of type-safety when writing my data interfaces/abstractions. Definitely helps the readability of the code when you're debugging and developing. This particular flavor of semantic decoupling reminds me of abstract typed messaging in the base AF, where an interface between actor messaging guarantees the data capable of being transacted.
Reply
Jon McBee
1/20/2017 11:05:52 am
Hey Ryan, good to hear from you and good questions. The multi data classes for multi data type support issue persists here, but I am working on a solution to this problem (I don't want to say too much before I've had a chance to make it work, but if it works it will be very powerful). I do allow for inheritance in the data classes present in the topics, I do not allow for inheritance in the topics themselves (but I'd like to hear a use case for it you have something in mind). I don't love the idea of inheritance in the data classes, I see its utility but am hoping to solve the problem with composition of meta data. We can talk more about this offline if you are interested.
Reply
James Powell
3/13/2017 09:57:38 am
Be careful on using (more than one, at least) asynchronous actors to handle your Topic notifications. This makes the order of arrival uncertain; a message sent second can arrive first occasionally.
Reply
Jon McBee
3/16/2017 07:54:12 am
Hi James, I want to make sure I understand your comment as I know you have a lot of experience with these types of software systems. Are you saying to be sure that there is only one topic actor per topic or are you saying that only one asynchronous subscriber should handle each topic notification?
Reply
James Powell
3/16/2017 03:29:28 pm
I’m saying that if an actor makes an X notification followed by a Y notification, then it is valuable if a subscriber to X and Y always receives those messages in that order. If the notifications go via two different “topic” actors, then there is a chance of them arriving in opposite order.
Jon McBee
3/16/2017 04:52:48 pm
Hi James, replying to your last message but had to do it here due to nested message limit. We are on the same page. The mediator class prevents more than one topic Actor being spun up per topic. If X and Y notifications are made to two different topics then there is no longer a guarantee in order of delivery.
James Powell
3/16/2017 06:12:51 pm
Why are you using a separate "Topic actor" for each topic? Are you worried about message throughput? I use a Variant lookup table to host many topics and subscriptions in one place.
Jon McBee
3/16/2017 06:54:05 pm
Hi James, I feel bad for anyone from the future who tries to follow this thread, this three nested reply thing is becoming good enough reason to switch blog platforms.
James Powell
3/17/2017 08:25:15 am
You might consider changing your “Topics” from async actors, to synchronous by-ref objects (such as using a DVR). That is what I did with my similar “ObserverRegistry”, which was originally an actor but was changed to a DVR to avoid message-ordering uncertainty. With a DVR solution, publishers send notifications directly to subscribers.
James Powell
3/14/2017 07:12:29 pm
>>"My idea is to change the registration process so that instead of having publishers and subscribers register by topic name without restriction on data type, they will register by data type without restriction on topic name."
Reply
Jon McBee
3/16/2017 08:03:58 am
Hi James, currently when I use Stream in a customer project I use it with the string message identifiers. I wrote the data type driven identifier as an extension to the core framework, really as a proof of concept to see if I liked it. I am currently working on a few scripting tools with Jarobit to make it easier to use data type driven message identifiers, and to improve the extension to handle the data typing more cleanly. This effort may end up being an academic exercise or it may end up being something I (or another developer) ends up liking enough to use on projects, not sure yet. Always good to hear your thoughts and perspective.
Reply
Leave a Reply. |
Tags
All
Archives
October 2019
LabVIEW Blogs |