I've spent the last few posts talking about decoupling actors using event driven architecture (EDA). Now that we have a common vocabulary I want to show some code that practices what I've been preaching. So I decided to take the CLD ATM sample exam twice, writing one solution as a queue driven producer consumer and the other as an EDA actor system using event streams to drive the application. Let's take a look at both.
A few thoughts before we dive in. Thought one; if you are preparing to the CLD exam then please do take a look at my queue driven producer consumer solution as I believe that it is what NI is looking for, please do not try to reproduce the event-driven actor system solution as you will not have time to write all the pieces from scratch (if you can do all of that coding from scratch in 4 hours then I'd like to hire you). Thought two; a lot of the ideas I've written about over the last few posts come from microservice architectures. I chose not use the term microservices because my actor implementation doesn't strictly fit the definition of a microservice. Thought three; the idea of event streams comes from reactive programming and I did a lot of reading up on ReactiveX to learn about them. I think that my implementation could be extended in order to implement a functional-esque style of programming in LabVIEW based on ReactiveX, but I haven't tried to do it yet.
Let's start by taking a look at what I will call my standard solution. I decided to try something different and post a video walk through of the code instead of typing out a description. I will also be posting the source code so that you can download and inspect it yourself. Feel free to skip over this section if you are already familiar with the queue driven producer consumer approach used in my solution to the ATM sample exam.
In summary I call this a standard approach because it uses the queued message handler project template that ships with LabVIEW to implement a two loop producer-consumer architecture. I think that this solution would pass the CLD exam and that this solution is a good fit for the problem space.
Now let's take a look at the reactive solution, I call it this because it uses an event driven architecture composed of actors using event streams. As I mentioned previously I am not advocating that people should apply this style of coding to a CLD exam, doing so will not help you pass the exam.
As I discussed in this post on event driven architectures I have created reactive actors that subscribe to event streams through the mediated message bus. In this implementation each topic that the mediator creates maps to an event stream and each event uses the String Data Object built into the framework, which means that I did not need to create a single event object for the CLD solution.
Each actors Initialize Actor.vi handles creating and/or registering for event streams. This means that once the Assembler objects Bring Up.vi method executes all event streams have been created and each actor has registered as publisher/subscriber to the streams that it cares about.
Event streams can be visualized through the use of marble diagrams like the one above, where the gray arrow represents the event stream and the shapes represent the events. I have a feeling that a tool for creating marble diagrams could be used to design a reactive actor system, and a scripting tool could be created to script a lot of the stream creation and registration based on the marble diagram, but I haven't dug into this yet. I also think that the marble diagram could be treated as a directed graph and a tool could be created to build metrics providing feedback on the design at the event stream level.
The fact that much of the high level design is done at the event stream level impacts how reactive actor systems are debugged and refactored. The majority of my debugging and refactoring of my CLD solution involved recognizing that I had created redundant event streams and merging them, which trickled down to the Actors by changing their Initialize Actor.vi method and their Run.vi method to reflect the event stream changes. As an example, my first design had extra event streams to handle Account Login Request, Account Logged In, and Account Login Failed events. As I started writing the code I realized that all of these event streams could be replaced with the already existing Account Action Requested and Account Action Completed event streams. Refactoring was pretty simple as the majority of changes involved changing the event streams in Class Data, Initialize Actor.vi, and Run.vi for the actors involved.
Because my system of actors are choreographed using event streams, and I have the ability built into the framework to record events being published to streams and subscribed from streams I was able to pretty quickly build an actor that allowed me to replay an instance of my application running from the event log file. All that I had to do was write the Replay actor, register it as a publisher on all streams, and write some code that allowed it to parse the event log and push events on to the correct event stream at the correct time. Here is a video of it working.
My guess is that the complexity of the Replay actor may scale up with the complexity of the system, but in that case it may be beneficial to limit the replay to targeted components. The Replay actor I wrote for the CLD exam solution was just a proof of concept that I put together in 30 minutes over lunch.
So in summary reactive actors in an event driven architecture seem like an interesting way to solve problems. Reactive programming helps to enforce looser coupling between actors while minimizing the class count in the LabVIEW project. Reactive programming also tends to shift my design approach away from code first to data/event first, which I believe results in code that better fits the problem domain. There is more work to be done to make this framework easier to use in the context of reactive actors and so I will be posting the source on the Composed Systems GitHub page. I will be putting a link up soon, so if you want to participate please join us.
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