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