In Shakespeare's Hamlet, "to be or not to be" reflects on a choice between two fundamentally different paths. In object-oriented programming, we often face a similar existential dilemma:
To object or not to object?
That is the question.
Here we’re talking about the decision to objectify a concept in your code—or not. It’s a question (and a very important one) that comes up frequently, especially as you build more complex applications with more advanced architectures.
In LabVIEW, you can technically turn anything into an object, even simple types like integers, timestamps, or booleans. But here’s the catch:
Both under-objectifying and over-objectifying your code will increase the complexity of your application.
If you underuse objects, your architecture can become:
Rigid
Repetitive
Difficult to scale
However, if you overuse objects, your codebase can become:
Bloated
Hard to read
Frustrating to debug
The good news is that there’s a sweet spot in the middle, where the right use of objects makes your code cleaner, more flexible, and easier to maintain.
This article explores how to find that balance, and explains how the Workers framework uses OOP to make your applications more modular, scalable, and easier to develop.
🔍 What Does “Objectifying” Something Mean?
In LabVIEW, objectifying something means encapsulating it inside a class, giving it:
Private state (data)
Associated behavior (methods)
Optional inheritance structure
This enables powerful design patterns, including:
✅ Encapsulation – Keeping data and logic together
✅ Polymorphism – Swapping out different implementations with a common interface
✅ Inheritance – Sharing and reusing behavior between related components
But these benefits come with trade-offs. Objectifying too much—or too early—can introduce overhead, abstraction layers, and unnecessary indirection.
So while you can objectify everything, it’s often better to objectify only what adds real structure or value.
âś… When Should You Use an Object?
Use an object when the thing you’re modeling:
Has behavior, not just data
Represents a conceptual entity (e.g. a device, task, or module)
May have multiple implementations (e.g. real vs. simulated)
Requires reuse, extension, or protection of internal state
Benefits from being accessed through a defined interface
Examples of good candidates for objects:
A hardware device with IO and configuration
A service process like logging, messaging, or control
A Worker that encapsulates a modular, stateful thread of execution
❌ When Not to Use an Object
Avoid objectifying when:
You're working with simple types (scalars, booleans, strings)
There's no behavior or internal logic to encapsulate
You only need fast, lightweight data passing
The object would add no clarity, reuse, or abstraction benefit
Over-objectifying these types often leads to:
More code and file overhead
Slower development
Frustrating debugging sessions
Unnecessary complexity in small applications
đź§± How Workers for LabVIEW Uses Objects
In multi-process applications, the most architecturally obvious use of objects would be to turn each process into an object—and that’s exactly what the Workers framework does—by encapsulating each process in a class called a Worker. This design choice improves the structure, modularity, and scalability of multi-process applications, and significantly improves code reuse.
✔️ What is objectified:
The only thing that is objectified in the Workers framework are the Workers themselves. This alone provides the framework with the following benefits:
Workers (the processes themselves): Each Worker is a stand-alone modular process that provides a stateful thread of execution, whose methods act on its own private encapsulated data.
Worker base classes: Each Worker inherits from the ancestor class Worker.lvclass providing common functionality to all Workers. Developers can further extend this common functionality by adding their own base classes into a Worker's inheritance hierarchy.
Dynamic Abstraction: Workers can be dynamically loaded at runtime and interacted with through API abstractions. This allows applications to run entirely on abstract interfaces, enabling simulation swapping, hardware abstraction, and plug-in extensibility, all without touching the business logic.
❌ What is not objectified:
Public API Methods: Worker methods are contained within the Message Handling Loop (MHL) cases of a Worker's Queued Message Handler (QMH). They are invoked by the use of a Worker's (or Worker base class's) Local API or Public API VIs. This keeps the logic simple, direct, and intuitive.
Message queue data: Message data sent between Workers is wrapped in a message-specific typedef stored in variants—not message objects—preserving the simplicity of the QMH pattern that many LabVIEW developers are familiar with.
Data structures and state: Runtime data used by a Worker is stored as simple typedefs, scalars, or clusters within the class’s private data. These are not objectified unless there's a clear reason to encapsulate additional behavior (and is left up to the user).
🛠️ Example: Creating a Hardware Abstraction Layer (HAL) using Workers
Let’s say you're developing a system to control a power supply, and you want the flexibility to swap between a real device and a simulation.
The fact that Workers are objects allows for the easy creation of HALs in the framework. Using Workers 5.0, this is how you would achieve this:
Step 1: Create a Worker Base Class (scripted)
Create PowerSupply_Base.lvclass that contains the following Public API Requests:
Set Voltage
Get Voltage
Power On/Off
These are method declarations only, no behavior yet.
Step 2: Create Two Workers (scripted)
RealPowerSupply.lvclass : Communicates with the physical device
SimulatedPowerSupply.lvclass : Returns mock values and logs actions
Both classes inherit from the base class and implement the Public API behavior in their own Message Handling Loop (MHL) cases.
Step 3: Load a Worker via Factory Pattern at Runtime (scripted)
At startup, load either the real or simulated Worker based on a config file.
The rest of your application talks only to the base class Public API, and remains unaware of which implementation is active.
Without objects, this HAL implementation would require:
Duplicated logic
Scattered conditional code
A brittle architecture that’s hard to maintain or extend
đź’¬ Final Thoughts
Object-oriented programming is a powerful tool, but with great power comes great responsibility.
Whether you're just starting out with LVOOP or developing an enterprise-scale application, remember:
Good architecture isn’t about turning everything into an object, it’s about objectifying what makes sense.
And by objectifying the right things—and avoiding it where it's not needed—you get:
âś… Cleaner code
âś… Faster development
âś… Easier debugging
âś… Happier developers
The Workers for LabVIEW framework follows this philosophy, providing you with the power of LVOOP where it makes sense, while keeping the rest of your application lean, readable and efficient.
📚 What's next?
If you want to learn more about how to put the OOP features of the framework into practice, the best place to start is with the Workers for LabVIEW Training Course. This free course walks you through the core concepts, API design, debugging tools, and real-world exercises to help you build scalable applications with confidence
📖 Download the training course here: 👉 https://community.workersforlabview.io/training-course