2

I recently developed an application in LabVIEW, but although I'm pretty happy with its design I realised that I might be able to improve one part of it by making the various components of this particular subsystem collaborate with each other using a publisher/subscriber model.

If I do go down this road, I think it's best to develop a "Message Bus" LabVIEW library that I can reuse in various projects including the one I've just made. To get a good idea of how to design this, I've been looking at message-oriented middleware solutions like RabbitMQ and reading through Gregor Hohpe's Enterprise Integration Patterns which focuses on this sort of area.

All of these things keep talking about how MOMs should be used to integrate separate applications (that may or may not be running on the same machine). It just irks me a little that I can't seem to find any discussion about MOMs being used just as simple mediator classes that exist purely within the scope of one instance of a running application and only serve to facilitate communication between objects within that running instance.

Essentially my question is whether it's sensible to develop a message bus for this sort of thing. Can (and should) middleware like RabbitMQ be used for mediating between objects running within the same application?

  • I do not know what message oriented middleware is but the way you describe it it reminds me of the actor model. – Giorgio Jul 1 '15 at 19:26
  • @Giorgio Actually the design I have in mind for the LabVIEW implementation of a message bus will be heavily based on the Actor Framework, which is the LabVIEW implementation of the actor model - the message bus will be an actor that forms aggregate relationships with subscribers, which will also run as actors. – Tagc Jul 1 '15 at 19:36
1

There's a few things to consider. If you're talking about "Communicating" inside of a single application, the usual route is to create an object or data structure that holds the data you want to communicate, and simply giving it to the class/method that will use it.

It's fairly common to want to share information between different threads, in which case all threads need to have access to the variable somehow, and you need to deal with concurrency issues.

MOMs usually don't work on the intra-process level, because passing objects/data is far more convenient when considering just one process. A MOM will simplify communication in the case where information has to be shared amongst various processes.

It's sort of like this: You and I use the same language. If you tell me to go refill your cup of coffee, I know how to do it. I might do it begrudgingly, but I know what to do. This kind of communication is what you have inside your own process - everyone understands each other. You just need to figure out a way of getting the right data from one entity to another.

A MOM comes into play when you want to talk to someone who won't understand you(another process). There's a lot of work that goes into transmitting information. You might think it's simple to send a Boolean or an array of integers, but it can get very involved. What is a Boolean? A bit? A byte? An integer? What's an Integer(let alone an integer array)? Are they 8 bits, 16 bits, 32 bits, 64 bits? The MOM on one end will basically take care of the hassle of sending a message that says "I'm sending you an array with 20 values which are 32-bit integers" followed by said array. The receiving MOM understands the message and can process it. The reason you don't use a MOM inside a process is because these kinds of messages take up more space than what's necessary.

If I'm one subroutine and you're another, all I need to do is write the array to an agreed-upon location in memory(a variable), and you'll be able to see the array. We may have agreed upon the size of the array ahead of time(ie pre-compilation) but even that doesn't need to be communicated in some cases. You're effectively using the language, compilation, and typing system as your MOM in this case, because those are the things that give meaning to "The array starts at address 0xDEADBEEF and uses 512 bytes of memory".

Now, you could still use a MOM to send things inside the same process, by pointing the sender and receiver at the loopback address, but this is a lot of overhead when simply passing variables/parameters is what you're really doing.

Edit: A concrete example with Java

Per OP's coupling concerns, I'd like to present a concrete example of sharing messages in Java that has minimal coupling between components. I've used this on several projects and it's fairly straight forward.

The base of it is to use an object like a BlockingQueue. If you don't want to read the documentation the take-away is that this is a thread-safe queue that allows multiple threads to put things in, and take them out without you having to worry about concurrency. So you'd end up with something like BlockingQueue<Message>. The next step is to get this object in the hands of the threads that will use it. That means you either pass the reference to the object to each thread, or you can wrap the queue itself in a singleton.

A simple implementation where you can pass the reference to a thread:

public class Producer implements Runnable {
    BlockingQueue<Message> queue;
    @Override
    public void run() {
        // TODO : Produce messages
    }
    public void initialize(BlockingQueue<Message> q) {
        queue = q;
    }
}

And the calling code:

// Just a compile-able example of initializing such a queue:
BlockingQueue<Message> queue = new ArrayBlockingQueue<Message>(200); 

// ...

Producer producer = new Producer();
producer.initialize(queue); 
Thread t = new Thread(producer);
t.start();

Consumers of these messages would look very similar. But you can already see that it becomes very simple to make multiple types of producers(and consumers), and all of these producers/consumers are merely coupled to a queue. Whether it's a MockProducer, DemoProducer, RealProducer, RealConsumer, etc, the only coupling between them is the queue. The 'communication' between producers and consumers is basically whether the queue is full, empty, or somewhere in between. (And what you would do in each of these states is another discussion entirely)

Of course there are other options besides queues - you can utilize any data structure you want, with any messaging protocol you can implement. You just need to be concerned about the thread-safety of your reads/writes to the data structure. I chose the queue though because it closely resembles my experience with reading/writing from a MOM - Is there a Message? Then I'll consume it. Can I put something there? Then I'll produce a message.

  • Thanks for the reply. "If you're talking about "Communicating" inside of a single application, the usual route is to create an object or data structure that holds the data you want to communicate, and simply giving it to the class/method that will use it." That's true, but then you have to take into account how tightly you're coupling components within the system. In order for one object to invoke a method on another object, it has to be aware of its existence. In many cases it would be preferable for objects to be able to communicate with each other indirectly by passing around messages... – Tagc Jul 1 '15 at 19:53
  • ...without knowing where those messages sent from. That makes it easier to substitute different components in the system - even ones that expose a different interface or that act as "mocks" within a test environment - so long as they're generating the same kind of messages. Even though you're right that MOM's are great for integrating applications that might "speak different languages", you also get a load of other benefits like low coupling, asynchronous processing, improved code testability, improved scalability, etc. So that still leaves me wondering why they aren't used even in cases... – Tagc Jul 1 '15 at 19:57
  • ...where all the components are speaking "the same language". Apologies for the long run-on comments! – Tagc Jul 1 '15 at 19:57
  • @Tagc I edited my response with an example of what I'm talking about. For scalability, I'd say this kind of approach is best when you're talking about a single program. Once you enter multi-process or multi-machine then a MOM would be more scalable. Testability I feel is fairly equivalent. Asynchronous processing is possible(and the example I gave is a type of asynchronous processing), and the coupling is about as minimal as you can possible get - it's the size of a pointer, essentially. – Shaz Jul 5 '15 at 14:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.