Jump to content

Labview anti-pattern: Action Engines


Recommended Posts

Recently there have been a few discussions about action engines as they relate to specific applications (here and here) but the topic is broad enough that I felt it deserves it's own thread.

AE= Action Engine >>> loosly a Functional Global Variable.

Ben, you left out part of the definition...

AE= Action Engine >>> loosly a Functional Global Variable and a commonly used Labview anti-pattern. biggrin.gif

<---Disclaimer--->

Ben, these comments are not directed at you. I know you're a CLA and already understand much of what I say below. I'm simply using your comment as a springboard to jump on my soapbox. wink.gif

For those that like to use AE's, please don't take this as a personal attack; I'm referring to the AE as a programming construct and not passing judgement on anyone who uses them. Also, this is very much an opinion and is based on my own observations. My Labview experience is somewhat narrow, centering around single computer desktop applications, so there may be situations where an AE is the best solution. I don't claim to know all...

</---Disclaimer--->

Simple functional globals have a place. Any time a functional global crosses the line into an action engine I'm looking to replace it with a class. Using an AE may solve the immediate problem sooner, but it also imposes more constraints on the unknown, future modifications. You are painting yourself into a corner and the longer you stick with it the harder it is to get out.

To expand a bit on what I said about layering api's here, when you create an action engine you are creating a chunk of data with associated actions that apply only to that chunk of data. Those actions define the api your AE supports. Now suppose the AE grows to the point where you want to shift some internal behavior off to a sub vi. Like it or not, that sub vi has just become part of the public api. You cannot change that sub vi without considering how it will affect code in countless other places.

"But," you say, "I know that sub vi isn't supposed to be used anywhere but in the AE!" Easy to say now. What will you do when, in order to fill a change request, you have the choice between a quick fix by using the sub vi someplace you didn't intend 'just this once,' or a more time consuming fix by changing the behavior of the AE itself? Furthermore, when somebody else works on that code, how do you convey to them the difference between, and enforce the correct usage of, the public api versus the private api?

Every VI we write is essentially a mini api. Every action a public api exposes places constraints on how you can change that api in the future. AQ recently talked about the problems associated with publicly accessable vis in vi.lib. Those VIs are part of the public api even though they were not intended to be used by the public simply because they can be used anywhere. Trying to add functionality to the intended public api without changing the behavior of the unintended public api is extremely difficult, and sometimes impossible. Good api design involves exposing, or making available to the public, only what is necessary and no more.

Applications that don't use the classes or libraries are programmed with, in effect, one giant public api. Any vi can (and probably will) be used anywhere, which often results in a very complex vi hierarchy and interactions that are difficult to disentangle. We try to manage that complexity by organzing our projects into subfolders and using naming conventions. Unfortunately naming conventions and disk hierarchies cannot enforce the intended usage. For that we need classes and libraries.

</soapbox>

Link to comment

Recently there have been a few discussions about action engines as they relate to specific applications (here and here) but the topic is broad enough that I felt it deserves it's own thread.

Ben, you left out part of the definition...

AE= Action Engine >>> loosly a Functional Global Variable and a commonly used Labview anti-pattern. biggrin.gif

<---Disclaimer--->

Ben, these comments are not directed at you. I know you're a CLA and already understand much of what I say below. I'm simply using your comment as a springboard to jump on my soapbox. wink.gif

For those that like to use AE's, please don't take this as a personal attack; I'm referring to the AE as a programming construct and not passing judgement on anyone who uses them. Also, this is very much an opinion and is based on my own observations. My Labview experience is somewhat narrow, centering around single computer desktop applications, so there may be situations where an AE is the best solution. I don't claim to know all...

</---Disclaimer--->

Simple functional globals have a place. Any time a functional global crosses the line into an action engine I'm looking to replace it with a class. Using an AE may solve the immediate problem sooner, but it also imposes more constraints on the unknown, future modifications. You are painting yourself into a corner and the longer you stick with it the harder it is to get out.

To expand a bit on what I said about layering api's here, when you create an action engine you are creating a chunk of data with associated actions that apply only to that chunk of data. Those actions define the api your AE supports. Now suppose the AE grows to the point where you want to shift some internal behavior off to a sub vi. Like it or not, that sub vi has just become part of the public api. You cannot change that sub vi without considering how it will affect code in countless other places.

"But," you say, "I know that sub vi isn't supposed to be used anywhere but in the AE!" Easy to say now. What will you do when, in order to fill a change request, you have the choice between a quick fix by using the sub vi someplace you didn't intend 'just this once,' or a more time consuming fix by changing the behavior of the AE itself? Furthermore, when somebody else works on that code, how do you convey to them the difference between, and enforce the correct usage of, the public api versus the private api?

Every VI we write is essentially a mini api. Every action a public api exposes places constraints on how you can change that api in the future. AQ recently talked about the problems associated with publicly accessable vis in vi.lib. Those VIs are part of the public api even though they were not intended to be used by the public simply because they can be used anywhere. Trying to add functionality to the intended public api without changing the behavior of the unintended public api is extremely difficult, and sometimes impossible. Good api design involves exposing, or making available to the public, only what is necessary and no more.

Applications that don't use the classes or libraries are programmed with, in effect, one giant public api. Any vi can (and probably will) be used anywhere, which often results in a very complex vi hierarchy and interactions that are difficult to disentangle. We try to manage that complexity by organzing our projects into subfolders and using naming conventions. Unfortunately naming conventions and disk hierarchies cannot enforce the intended usage. For that we need classes and libraries.

</soapbox>

Nice spaech that I'll think about more, but unitl then let me add to this thrad by throwing out a Q.

I am the only person at my company (about 7 CLA's depending on what day it is) that has taken the plunge into LVOOP. There are four others that are familiar with OOP or LVOOP. Alomost everyone of of our applications is different! Aside from a DAQ board or two I have never (seldom, I re-use my Dew-Point Hygrometer AE in a bunch of apps going back to LV 6.1) worked with the same widget twice.

So as we kick-off new projects we turn to each other and say "we could use LVOOP on that part..." but then we look at the time limitations and say "but we don't have the time to do a LVOOP version" so we use the AE pattern.

So my management and coworkers don't want to take the chance on LVOOP because many of the pay-offs are not for us, pay-offs.

So I am looking for others to comment on how I can help my co-workers to take the plunge.

BTW:

I have started to collect some reusable classes but it just seems to take longer to to a brand new LVOOP class to support a one off interface.

WEll I was thinking while typing so let me reply that wrapping the AE's methods and putting them all in a library go a long way toward a proper API. Set public and private and it get close to what LVOOP can do.

Take care!

Ben

THe "Dictionary Challenge" was won by those who used AEs.

See here.

http://zone.ni.com/devzone/cda/tut/p/id/5305

Ben

Link to comment

As always, there is a middle ground (IMHO): Create a lvlib, make the AE VI private and create public "Accessor" VIs for each of the actions. This has the advantage of keeping the "simple" AE paradigm whist restricting uses of the internal VIs. In addition, the accessor VIs can have the proper connections for the action involved (named, typed, and with appropriate required statuses), making them a little easier to use (and to avoid having to remember what inputs are needed for what actions).

Note: I personally am not such a huge fan of action engines everywhere for the simple reason that they are global structures which means that you cannot easily modify your system to deal with a second "thing", and your "thing" can be used absolutely anywhere, not just in the part of your program that does use it.

Edited by Shaun Hayward
  • Like 1
Link to comment

The "anti-pattern" topic is a good one if LVOOP is concidered a Pattern since the two approach are alomst the other inside-out. It takes a bit of a pradigm shift to move from one form to the other since in the AE the data is right thre is the SR staring at you. THe LVOOP version is touching data that is not here (at least as it appears from the diagram view of the method).

Ben

Link to comment

I'd say, that the AE is superseded by LVOOP. We shouldn't blame them as Anti-Patterns yet for reasons Ben mentioned (we got used to them) as well as issues we will face when we rewrite legacy code to be OOP.

The main reason IMO for AEs is encapsulation. So I have a configuration data TD and a set of methods (load, save) and each of these methods (they might be SubVIs or inlined code) goes in one case of the AE.

When you have a wide variety of parameters for the set of methods on the AE, you will get a messy interface, either due to a big cluster or a huge number of terminals or both... But we managed to deal with that by exposing the relevant parameters only with a set of Wrapper VIs (especially to mark the required inputs). So we have a hierarchy like this:

n Wrapper VIs

1 AE with data in shift register

m SubVis

Using LVOOP we eliminate the AE layer having only the accessor methods (which is the level of the wrapper).

n Public Accessor Methods

1 Private Data Cluster

m SubVis

OOP gives as some more benifites:

* interface, so we have public and private (ok, we can do it also for AEs as suggested above, recently I was thinking of just postfixing VIs to mark it as public/private)

* inheritance

But there are differences between both designs, and these will still give the AE a place in our templates folder. Even more, these differences should warn us not to blindly replace AEs by OOP:

* AEs are effectivily serializing the access to the data (or whatever we encapsulate). And it works even on a network scope as Bens experience tells. And all those 100s of posts about singelton design pattern (and I think no satisfying solution evolved yet) are a clear sign that the time of the AE is not yet over. Either we still think in AE serialization or this is a serious drawback that comes with OOP. My personal thinking is, that the singeltone debate will be solved by employing an AE (either encapsulating the Object or implementing the locking mechanism inside our class.

* AEs transport the data wireless (that makes a good marketing slogan: 'transmitt your data wireless with Action Engines'). As such they are a good choice for passing data between parallel loops and between states in a SM when we don't want to sacrifice a shift register for that). This implies that an object replacing them must be based on a by-ref design, which still is evolving with the introduction of the DVR last summer. Current designs still suffer from the serialization we get for free with an AE, leading to race conditions and deadlocks.

I'd conclude, AEs will become a less important design pattern as LV transforms into LVOOP. Maybe in some years, we will look at this design pattern like we look at stacked sequences today (legacy, but still rare/exotic use cases exist where they are correct to use). And as the rise of scripting languages (such as lua) in the text programmers world showed, the AEs might even come back as a way to 'Express program', which of course we all will reject publicly (LAVA shirts on NI week: 'No AEs required') and all will use for things like prototyping, QD-bugfixes (QD != quickdrop, QD=quick-and-dirty, hint: Darren, change the name for the sake of the marketing guys, they will all go crazy if the read this; if not, remind them that microsoft went big with Q-DOS when just removing the 'quick').

Felix

  • Like 1
Link to comment

WEll I was thinking while typing so let me reply that wrapping the AE's methods and putting them all in a library go a long way toward a proper API. Set public and private and it get close to what LVOOP can do.

Create a lvlib, make the AE VI private and create public "Accessor" VIs for each of the actions. This has the advantage of keeping the "simple" AE paradigm whist restricting uses of the internal VIs. In addition, the accessor VIs can have the proper connections for the action involved (named, typed, and with appropriate required statuses), making them a little easier to use (and to avoid having to remember what inputs are needed for what actions).

This is an excellent idea... I had not thought of that.

I believe OOP in and of itself is not hard. Most people understand the concepts pretty quickly. What's hard is figuring how to design it correctly. As I review the OO mistakes I've made over the past several years what it almost always boils down to is that my api was wrong. (Usually by trying to make a class do more than it should.) OOP forces you to make api decisions that could have long term consequences. It's making good api decisions that is hard, not anything inherent in OOP.

By wrapping all your AE's in their own libraries and only exposing certain methods (this is the 'encapsulation' part of OOP) you get practice developing api's without the stress/stigma of using OOP. You can present it to your coworkers simply as "bringing a little more structure and organization to our applications." Hopefully over time the thinking will shift from,

"I need to do <something> and this AE has that data, so I'll just add another action to it."

to

"I need to do <something> and this AE has that data, but does this new action make sense in the context of it's api?"

Alomost everyone of of our applications is different! Aside from a DAQ board or two I have never (seldom, I re-use my Dew-Point Hygrometer AE in a bunch of apps going back to LV 6.1) worked with the same widget twice.

I wouldn't advise anyone to start learning OOP by designing a large reuse library. You certainly can (I did) and you'll learn a lot, but don't expect to be successful (I wasn't.) I wouldn't even advise anyone to start learning OOP by designing classes they expect to reuse in another application. Try it on a single application. Forget about inheritance, focus on encapsulation. If you are in an environment where you have multiple developers working on the same application, the most immediate payoff is more structured code that is easier to understand and easier to predict how it will react to changes.

Don't get me wrong, inheritance is important and useful. Sometimes it can make an otherwise difficult change a piece of cake. I've seen programmers implement some really cool things using inheritance. For those who are venturing down the OOP path on their own, I think they'll get more bang for their buck by concentrating on encapsulation and good api development. On the other hand, if you have an experienced OOP developer handy who can help guide the design, jump on the bus and enjoy the ride.

THe "Dictionary Challenge" was won by those who used AEs.

That's very cool. I hadn't seen it. I know FG's are very fast so if raw speed is a concern that might be a better route to go than holding the data in the class cluster. I do wonder what the performance change would be if the AE (but not the FG) were refactored into a class.

  • Like 1
Link to comment

This is an excellent idea... I had not thought of that.

...

That's very cool. I hadn't seen it. I know FG's are very fast so if raw speed is a concern that might be a better route to go than holding the data in the class cluster. I do wonder what the performance change would be if the AE (but not the FG) were refactored into a class.

Re: Excellent idea

All credit goes to Jim Kring for teaching me that. thumbup1.gif

Re:speed

I have a wall full of customer thank you letters that read like "... you have done what NI said could not be done!". Most of that was earned on the back of AE's.

I have devloped two shipped LVOOP apps, both of which met the customer needs and the second actually gave me some re-use fodder (the first was a "Create Controls on the Fly" app so I have to wait for the next time wants that functionality to re-use it). From what I can tell, LVOOP could certainly rival most AE implementations. I don't know about those apps that have a large RT data set and just that one value needs decremented... provided we don't use accessors to read it and write it back (Q about if can work inplace in the original class buffer). I guess if i wait long enough I'll answer Q for myself.

Sorry but I used up my quota of pluses for today.

Ben

Link to comment

As always, there is a middle ground (IMHO): Create a lvlib, make the AE VI private and create public "Accessor" VIs for each of the actions.

Funny, this reminds me of a framework I used.

I posted a blog about it on the old LAVA framework, if someone has it please post.

In short it's this way.

An active engine with several 'set methods'

  • Set Data
  • Set Start
  • ...

However I created an accessor VI for each of these methods.

Then i wrapped all these methods inside one polymorphic VI.

Ton

  • Like 2
Link to comment

However I created an accessor VI for each of these methods.

Then i wrapped all these methods inside one polymorphic VI.

Ton

I have actually done that many times - it makes coding up the application much quicker than having to go and find each VI separately (and can be very neat when you use ":" characters in the menu names to create nested selections) :)

Edited by Shaun Hayward
Link to comment
I am the only person at my company (about 7 CLA's depending on what day it is) that has taken the plunge into LVOOP. There are four others that are familiar with OOP or LVOOP...

So as we kick-off new projects we turn to each other and say "we could use LVOOP on that part..." but then we look at the time limitations and say "but we don't have the time to do a LVOOP version" so we use the AE pattern.

A couple of points - sure, creating LVOOP classes is time consuming, but so are AEs if you're not used to doing them - plan them out and they'll be easy to implement. Also (and this is not an attack on your colleagues), I know a few CLAs that I wouldn't consider LabVIEW architects per se - just LabVIEW developers that have passed the CLA exam :) I would be a bit surprised if you had engineers in architect roles that didn't know how to architect OO patterns...

I believe OOP in and of itself is not hard. Most people understand the concepts pretty quickly. What's hard is figuring how to design it correctly. As I review the OO mistakes I've made over the past several years what it almost always boils down to is that my api was wrong. (Usually by trying to make a class do more than it should.) OOP forces you to make api decisions that could have long term consequences. It's making good api decisions that is hard, not anything inherent in OOP.

I couldn't agree more thumbup1.gif ...and it's the up-front design time that a lot of people don't want to (or don't know that they should) spend that turns them away from OO. That said, like everything, once you get used to doing it, it becomes much easier!

Link to comment

... I would be a bit surprised if you had engineers in architect roles that didn't know how to architect OO patterns...

If LV architects have to be familiar with the OO paterns then I don't qualify.

That would suit me just fine because then I would be able to charge off my time at half the rate and have twice as long to do the work. thumbup1.gif

Besides, is would save me the trouble of breaking out my buisness card everytime I have to spell the word "architect".

Back to the topic of AE vs LVOOP

One difference we did not touch on is that LVOOP places a requirement on the code that uses it that it must carry the LVOOP wires around. Yes the wire is flexible, but it still has to be there. AE encapsulate the wire so ripping an AE out of an app just requires deleting the AE or its wqrapper. To toss a LVOOP wire you have to run the track ball farther.

Ben

Edited by neBulus
  • Like 1
Link to comment

for me, the wireless transmission of data using AEs is the biggest paradigm shift holding me back from going to LVOOP.

Having to bundle all the classes I want to use onto my main shift register just seems weird, especially as its ByVal and not ByRef so just in my mind seems not efficient.

re: public / private methods of AEs, isn't everyone doing this?

re: polymorhphic method VIs - this is a great idea!

Also, earlier in the thread:

* AEs transport the data wireless (that makes a good marketing slogan: 'transmitt your data wireless with Action Engines'). As such they are a good choice for passing data between parallel loops and between states in a SM when we don't want to sacrifice a shift register for that). This implies that an object replacing them must be based on a by-ref design, which still is evolving with the introduction of the DVR last summer. Current designs still suffer from the serialization we get for free with an AE, leading to race conditions and deadlocks.

(Black Pearl)

One difference we did not touch on is that LVOOP places a requirement on the code that uses it that it must carry the LVOOP wires around. Yes the wire is flexible, but it still has to be there. AE encapsulate the wire so ripping an AE out of an app just requires deleting the AE or its wqrapper. To toss a LVOOP wire you have to run the track ball farther.

(neBulus)

First, it is possible to transmit objects "wirelessly." We do this here when we implement the Command Pattern. We flatten the (by-value!) objects to strings, send them using a String-typed networked shared variable (you could use the communications protocol of your choice), and unflatten them on the other end. This works quite well. [Technical note: In our designs to date we don't have to worry about race conditions. Each shared variable has a single writer, and the recipient responds to the data received in the fashion appropriate for its current state. I don't think we will ever have a case here when we will need to do otherwise.]

Within a single loop, however, yes, we typically pass around a single wire of the Model class (and wire this to a shift register). This results in code that is both efficient and in our assessment easy to read. Just extract the data you need when you need it.

Link to comment

for me, the wireless transmission of data using AEs is the biggest paradigm shift holding me back from going to LVOOP.

Having to bundle all the classes I want to use onto my main shift register just seems weird, especially as its ByVal and not ByRef so just in my mind seems not efficient.

re: public / private methods of AEs, isn't everyone doing this?

re: polymorhphic method VIs - this is a great idea!

If you really don't like wires there's always C++ (ducking for cover now).....................:lightbulb:

Link to comment

Lots of good comments! Too many for me to quote and reply so I'll respond in general...

First, I'm not sure I made it clear in my original post. I believe there is a clear difference between function globals and action engines. Functional globals are okay as far as I'm concerned. It's the action engine part that I believe is a problem. Also, there are two different questions here: 1. Should AE's be exposed as part of an api, and 2. Is it okay to use AE's inside a lvlib? My original intent was to address exposing AE's as part of the public api, though I do address both questions below. Predictably, my answer to both questions is no. (With the possible exception of wrapping AE's in libraries as a way to transition the programmers from public AE's to classes.)

Two thing are required for something to be considered an anti-pattern:

  • Some repeated pattern of action, process or structure that initially appears to be beneficial, but ultimately produces more bad consequences than beneficial results, and
  • A refactored solution exists that is clearly documented, proven in actual practice and repeatable.

From my point of view, AE's have not always been anti-patterns since it was the only way to create the necessary behavior. It's the recent development of classes that relegate AE's to the anti-pattern category. To address the idea of embedding AE's in libraries and exposing public methods, you can get many, but not all, of the benefits of classes by doing that. My question is, if you're going to go to all that effort, why didn't you just make it a class in the first place? That's what it's for.

The two main differences between libraries and classes are inheritance and state information. Classes are designed and intended to maintain state information. When I'm using a class I expect it to maintain appropriate state information. Libraries do not have an inherent ability to maintain state information. When I'm using one I expect it to not maintain state information. I expect every call to be independent of every other call. By maintaining state information in a library you are creating a construct that behaves counter-intuitively to common programming paradigms, plus you forever lose the advantage of inheritance.

You can easily create a class in a way that allows you to "wirelessly" pass data around if that's important to you, and although personally I find myself moving away from those implementations, it's available if you want it. If you implement a class using a private action engine, that's your business. As a class user I don't care about how you implement the behavior, I only care that the behavior remains consistent. (Though I do think by using an AE internally you are making it harder to maintain the class.)

Getting back to publicly available AE's, there are other reasons why they are in general a bad idea. One of the prinicples of OOP is the "Open-Closed Principle." This prinicple says that code should be "open to extension, but closed to change," meaning it's okay to extend a class by adding new data and methods, but you should avoid changing code and data that already exists. Any time you change pre-existing code you are creating an opportunity to introduce bugs in code that has already been debugged and validated. Now you have to debug and validate that same code again. In the best case scenario you have a complete set of unit tests that you can run to verify correct behavior. In the worst case you unwittingly break important code someplace else and don't discover it until sometime later when correcting the mistake is much harder.

You are severely limited in your ability to add functionality to an AE without violating the intent of the open-closed principle. The only circumstances in which you can is if your function selector is a string, integer, or some other native data type AND you either have an open con pane connector to accept the new data or the new data matches the format of an already existing con pane connector. Do you use an typedef'd enum to select the AE function or a super cluster to encapsulate all the data inputs? Out of luck. Those types are part of the api the AE exposes. Changing those types is just as unpredictable as, say, changing an I32 to a STR.

Link to comment

Still willing to play along...

I have some re-use code that I have been re-using since LV 6 that provides Event logging services that can used to track system start-up shut-down and any errors that may have happened. It is based on an AE. All my developers have to do is drop this widget in their error chains and they always have a way to track back an error. It is so simple it isn't worth showing.

It has three actions

Start (Open log file write start-up time and create queue for new messages)

Log if error (post to queue if an error)

Stop (close log and kill queue)

So with three wrapper (one for each) that gives us three VI's the developer has to use.

So how would I write a LVOOP replacement that would actually be a one-to-one replacement?

From what I understand of LVOOP, I'm either going to hide an AE in a LVOOP method, or my developers are going to start running more wires to use the LVOOP version.

Take care,

Ben

Link to comment
If LV architects have to be familiar with the OO paterns then I don't qualify.

Sorry - I didn't mean to make that look like I was belittling anyone there. I know that there are plenty of damn good LV developers that design architectures out there that don't have OO experience.

Link to comment

Sorry - I didn't mean to make that look like I was belittling anyone there. I know that there are plenty of damn good LV developers that design architectures out there that don't have OO experience.

No problem Chris!

I'm a little uncomforatble with the title " Senior Architect". All I ever wanted to be was an engineer. Since I came up thru the world of computers starting with a print set and an o'scope, I never recieved any formal software training and picked-up what I know by talking to people and reading the forums. I'm not really sure what makes an Architect an architect. This reminds me of of my wifes grandfather and his books. He was an engieer and I got his books when he passed. They are a real gem for me since he studied engineering via mail-order. There were adds in the book to "make $10 a week!", but I digress. The highest level of math that he had to master was trigonometry. So this highlighted how far engineering has come in his life time but it illustrates one of my beliefs. Just because the schools started teaching calc, it did not invalidate him being an engineer.

So why would being an Architect be something that can slip away when new whistles and bells get released?

Done thinking out loud.

Ben

Link to comment
I never recieved any formal software training and picked-up what I know by talking to people and reading the forums.

Ditto - as one of the many physicists-by-trade on this board :)

So why would being an Architect be something that can slip away when new whistles and bells get released?

I don't think it does, but I do think it's important to keep up with those bells and whistles, especially if they have the potential to make your life more fulfilling ;) In fact, I'd go as far as to say that you can't really put OO in the same basket as bells and whistles - like the old saying goes: if all you have is a hammer, everything looks like a nail. The AE design pattern is one tool (let's call it a hammer), OO is another (let's call it a wrench). You can probably work out how to tighten a bolt with a hammer, but the wrench will make it a much easier and stable solution.

Link to comment

Paul, suggesting to use a variable (shared, global, whatever) to someone who is using AEs might result in a response like: 'Didn't we agree to use AE's instead of variables' or they will call the exorcist ('globals are evil').

Felix

I was just pointing out that the use of objects doesn't always require wires. (So such an argument, alone, is not a reason not to use objects.)

There are times (for sharing data between concurrent, legitimately independent components running in parallel, in particular) when wires won't work and so some kind of communication mechanism is necessary for the components to share data. There are various methods (queues, TCP/IP messaging, shared variables, functional global variables, even global variables) that one can apply for this purpose.

There are a couple points I have been pondering on this topic. Here is what I think:

1) We should use unwired communication when it is appropriate (which means when it is necessary--i.e., for interfaces between concurrent components) and not otherwise (not to avoid using a wire where we should have one--that just makes the code harder to read).

2) I am talking about methods of communication. In particular, we are talking about sharing data. We have to be careful when we start adding in other things.

I like networked shared variables for data communication because they work over a network, they follow a publish-subscribe paradigm, I (generally) like the API (there is room for improvement here), and I don't have to worry about the details of implementation (whether functionality or performance) but I still get things like logging and alarming (optionally).

I do think other communication methods are fine for use when appropriate.

I will confess I don't use functional global variables anymore, not because I think they are bad (they have their place--in fact, I'll bet they are part of the shared variable implementation), but because I like the APIs of other available solutions better. It is easier for me to read my code (or someone else's), in my experience, if it uses shared variables and object methods than if it uses functional global variables. There is probably some aspect of how well one uses each technology that impacts this, but still I think shared variables and classes are, used properly, more readable, more flexible, and more powerful.

Link to comment

Still willing to play along...

I have some re-use code that I have been re-using since LV 6 that provides Event logging services that can used to track system start-up shut-down and any errors that may have happened. It is based on an AE. All my developers have to do is drop this widget in their error chains and they always have a way to track back an error. It is so simple it isn't worth showing.

It has three actions

Start (Open log file write start-up time and create queue for new messages)

Log if error (post to queue if an error)

Stop (close log and kill queue)

So with three wrapper (one for each) that gives us three VI's the developer has to use.

So how would I write a LVOOP replacement that would actually be a one-to-one replacement?

From what I understand of LVOOP, I'm either going to hide an AE in a LVOOP method, or my developers are going to start running more wires to use the LVOOP version.

Take care,

Ben

OK, I'm intrigued. What data does each of these methods need to operate? If there is no special data needed or if it comes from the caller (which is very likely the case), then you can just write three methods (e.g., start, logIfError, stop) for a single class (e.g., EventLogger). (Note that the class input terminal does not have to be required!)

I'm guessing the start and stop methods need to know a logFilename and a queueName, and the logIfError method additionally has an error input.

Paul

Link to comment

OK, I'm intrigued. What data does each of these methods need to operate? If there is no special data needed or if it comes from the caller (which is very likely the case), then you can just write three methods (e.g., start, logIfError, stop) for a single class (e.g., EventLogger). (Note that the class input terminal does not have to be required!)

I'm guessing the start and stop methods need to know a logFilename and a queueName, and the logIfError method additionally has an error input.

Paul

Start - Starts a logger running in the background. Create a queue and shove it an AE.

LogIf - checks error cluster if set use the AE to queue up the error cluster. Meanwhile background process find error in queue and logs it to file.

Stop - Submit a queue message with the word Exit in the source field of the error cluster.

So the AE (once initialized) is only used to hold the queue ref used by the background logger and to do the enqueue.

I suspose a named queue could be used and use that name in the LVOOP and let LV do the lookup of the queue ref instead of caching the ref in the AE, I I guess your wireless class could do it.

Ben

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.