Last week I attended the NI Architect Summit, and I saw some patterns emerge while sitting in on the frameworks track. All of the framework content was related to challenges in LabVIEW Object Oriented Programming (LVOOP). LabVIEW is sold as a software tool for scientists and engineers, yet also provides features including LVOOP for advanced users. The takeaways below speak to the challenge of transitioning from a procedural single-threaded dataflow design to a parallel messaging architecture using LVOOP.
Transition from thinking in dataflow to thinking in message flow
In larger applications with parallel modules in multiple threads, dataflow is insufficient to describe the interaction. Instead, think of the flow of the messages (methods plus data) exchanged between those modules. Dataflow makes sense for single processes with shorter lifetimes inside self-contained components. In large complex applications, the messaging may be such that a dedicated message broker would be needed. Dataflow will still govern the self-contained code pieces inside the components.
I like this way of thinking. For years now, data-flow diagrams have been part of my design process. Here I define the messages and lay out the data that each cluster contains and who will own it. I’ve found that my applications result in cleaner more efficient code even though I haven’t been doing object oriented development.
In an actor framework:
- The actors should be self-governed as this favors determinism.
- The actors should filter the message when it is received—not when it is sent.
- Messages should be requests not commands—actors are self-governing.
- Messages should travel hierarchically. This reduces confusion and traffic as well as helps enforce cohesive helper loops.
- Messages should be single methods. This avoids race conditions. Imagine two nodes sending multiple sequential messages to a third node for processing. Do you know what you will get back?
Zero Coupling & Dependency Injection
This is a style that should result in more reusable, modular, and scalable code. Consider the following guidelines:
- High-level modules should not depend on lower-level modules. Both should depend on abstractions.
- Abstractions should not depend upon details. Details should depend on abstractions.
The implementation involves defining and scoping correctly the interface between an abstract method belonging to a parent and accessed by its child that implements the concrete method. I’m still working on fully wrapping my head around this one.
Note, the links above are not to summit content directly.
And remember…The Dude Abides
Simplicity and using the right tools were also common themes. It is unfortunate that The Dude was never invoked. I think he would appreciate Occam’s Razor and using tools appropriate for the problem. Or put another way, let the problem tell you the tools to use.