To Object or Not to Object, That Is the Question 🎭

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