Jump to content


Photo
- - - - -

Robustness of Functional Global pattern at large scales?


  • Please log in to reply
33 replies to this topic

#21 drjdpowell

drjdpowell

    The 500 club

  • Premium Member
  • 543 posts
  • Location:Oxford, UK
  • Version:LabVIEW 2011
  • Since:1999

Posted 29 December 2011 - 12:51 AM

I'm wondering though if the FG pattern is indeed as robust as it appears, especially for large-scale applications. Are there any known issues with the FG pattern (eg. memory leaks, lost data, crashes, etc) when used with large amounts of data stored in the USRs or operated for long periods of time?

My concern about the robustness of FGs is based on my impression that, although it works well, the pattern seems like an unintended use for a while or for loop (ie running the loop once just to read the current value of previously set USRs).

Regarding the initial post:

John, you don't have to worry about the robustness of using an uninitiallized shift register. Even if this use of a USR was not originally foreseen, it has been a common method of LabVIEW programing for many years, as are other design patterns using shift registers. However, you should carefully consider what Norm said about the possibility of eventually needing more than one copy of the thing you program as a functional global.

-- James

#22 ShaunR

ShaunR

    LabVIEW Archetype

  • Members
  • PipPipPipPipPipPip
  • 2,224 posts
  • Version:LabVIEW 2009
  • Since:1994

Posted 29 December 2011 - 01:48 AM


No, the LV2009 Singleton methods do not need typedef inputs.
In the AE each method should access it's own data - it unbundles it's own inputs and in bundles up it's own outputs. The cluster helps enforce this which leads to more robust code. Additionally it standardises the API (i.e. CP) to the AE main VI.
In the LV2009 Singleton example I don't need to worry about any of that as each method is a VI so it only uses those inputs/outputs.
That is why I consider the examples the same.

OK. I see what you are getting at here (great documentation post, want to write my websocket help files :P ). The thing is though, they are not a fair comparison. and this is why......

In the second example a DVR is used purely because it is the only way for you to create a singleton (maybe I'm still hung up on classes but you wouldn't be able to unbundle so easily without it). Secondly (and more importantly) it allows you to un-type the inputs and outputs to one generic type.

In your first example, you don't "un-type" the inputs and outputs, preferring instead to provide all permutations and combinations of the types for export. This has nothing to do with singletons. Just the strict typing of LabVIEW.

I've attached an "equivalent" classic AE of your 2009 API based on a method I've used in the past (My apologies to John, I think I now understand what he was getting at with variants-without using a poly wrapper, that is). There is very little difference apart from the features that I have outlined previously. Arguably potato, potAto as to variants vs DVRs. But the (major) effect is to push the typing down into the AE thereby making the accessors simpler than equivelent DVR methods (and if those god-dammed variants didn't need to be cast, you wouldn't need the conversion back at all!)

So back to the case in point. I think that the example I have provided is a fairer comparison between the super simple 2009 API and a classic AE. Which is more robust? I don't think there is a difference personally. Which is less coding? Again. I don't think there is much in it except to point out that changes are concentrated into the 1 VI (AE) in the classic method. You could argue that to extend the classic AE you have to add a case and an accessor rather than just an accessor, but you don't actually need accessors in the AE (and they are trivial anyway since they are there just revert to type).
A positive attitude may not solve all your problems, but it will annoy enough people to make it worth the effort. (Herm Albright 1876-1944).

Founder and general mischief maker on www.labview-tools.com.
SQlite aficionado and websocket zealot.
If it 'aint in LabVIEW, then you 'aint got a clue!

#23 jgcode

jgcode

    LabVIEW Renegade

  • OpenG
  • PipPipPipPipPipPip
  • 2,397 posts
  • Location:Australia
  • Version:LabVIEW 2009
  • Since:2005

Posted 29 December 2011 - 02:49 AM

(great documentation post, want to write my websocket help files :P ).

Thanks! And no ;)

The thing is though, they are not a fair comparison. and this is why......In the second example a DVR is used purely because it is the only way for you to create a singleton (maybe I'm still hung up on classes but you wouldn't be able to unbundle so easily without it). Secondly (and more importantly) it allows you to un-type the inputs and outputs to one generic type.


It does not have to be a class, here I changed it to a cluster and updated the DVR refnum and the rest of the code stays the same (in that example).

Cluster.png

Method.png

I've attached an "equivalent" classic AE of your 2009 API based on a method I've used in the past (My apologies to John, I think I now understand what he was getting at with variants-without using a poly wrapper, that is). There is very little difference apart from the features that I have outlined previously. Arguably potato, potAto as to variants vs DVRs. But the (major) effect is to push the typing down into the AE thereby making the accessors simpler than equivelent DVR methods (and if those god-dammed variants didn't need to be cast, you wouldn't need the conversion back at all!)


Ok, so now you have a wrapper methods and you have created a robust API IMHO - I like this API think it is robust like the DVR and the AE I posted e.g. you could change the implementation of underlying code (from DVR/Variant/AE) and it would not affect the API or end user.

However, I would disagree that it less work than the DVR module I posted:
So the example I posted (and you modified) is quite simple.
How are you going to handle multiple inputs for a method?
E.g. each method has 2 or more inputs.

For your implementation (variant) I see two options (there may be others?)
  • More Variant inputs on the CP of the AE
  • Or the interface to the AE stays the same and you create a typedef Cluster of the inputs for that method and convert them back on the other side.
In (1) more variant inputs could get messy fast and hard to manage in the AE?


In (2) creating a Cluster means that you are going to have the exact same issues I have highlighted in terms of boiler plate code.

So the typing issues has to do with the inputs/outputs to the AE not the state (persistent) data of the either module.
The DVR is the state (albeit a reference to the state - accessed safely using the IPE)
The DVR method inputs/outputs do not need to be isolated/grouped/protected etc... as there is only a single VI that will use them.
In order to handle multiple inputs I don't have to do anything special, thus this makes the DVR less coding.

So back to the case in point. I think that the example I have provided is a fairer comparison between the super simple 2009 API and a classic AE. Which is more robust? I don't think there is a difference personally. Which is less coding? Again. I don't think there is much in it except to point out that changes are concentrated into the 1 VI (AE) in the classic method. You could argue that to extend the classic AE you have to add a case and an accessor rather than just an accessor, but you don't actually need accessors in the AE (and they are trivial anyway since they are there just revert to type).


IMHO the classic AE is not as robust, I have already addressed the following as to why I think it is not and why it should be wrapped to provide a more robust API to the end user:

The first thing that come to mind from looking at it is that when I go to select a method I do not know which data I should set without opening the block diagram and looking at the code.
This is a simple example, but what happens when the code is more complex?
What if there 2-3 inputs are needed for each method and there was 5 methods?
What if some inputs are required and some are optional - how do you specify that?
It's going to get harder to figure out what is going on for the end user.
Once you run out of room for inputs/ouputs then you will need to use clusters - exposing this data (clusters, enum) leads to higher coupling.


Additionally the Command Enum should be private/hidden as e.g. this will not allow user to run private methods.


<edit>
For discussion here are some images of the Variant implementations when I had to increase the number of inputs to a method:

1. More Variant CP inputs:

1.png

1b.png

2. Switch over to a cluster:

2.png

2b.png

#24 ShaunR

ShaunR

    LabVIEW Archetype

  • Members
  • PipPipPipPipPipPip
  • 2,224 posts
  • Version:LabVIEW 2009
  • Since:1994

Posted 29 December 2011 - 07:05 AM

It does not have to be a class, here I changed it to a cluster and updated the DVR refnum and the rest of the code stays the same (in that example).

Ok so I'm clear on that now.

Ok, so now you have a wrapper methods and you have created a robust API IMHO - I like this API think it is robust like the DVR and the AE I posted e.g. you could change the implementation of underlying code (from DVR/Variant/AE) and it would not affect the API or end user.

However, I would disagree that it less work than the DVR module I posted:

That's not what I said. I said it wasn't a fair comparison (your original AE and the super slim one) and that there is little difference in effort for the more equivelent one I supplied.

So the example I posted (and you modified) is quite simple.

It's different? Wasn't intentional. I did save As (copy) a few times so that I didn't have to re-invent the wheel. Maybe something got messed up when it recompiled.

How are you going to handle multiple inputs for a method?
E.g. each method has 2 or more inputs.

For your implementation (variant) I see two options (there may be others?)

  • More Variant inputs on the CP of the AE
  • Or the interface to the AE stays the same and you create a typedef Cluster of the inputs for that method and convert them back on the other side.
In (1) more variant inputs could get messy fast and hard to manage in the AE?







<snip>
In (2) creating a Cluster means that you are going to have the exact same issues I have highlighted in terms of boiler plate code.

No 2. With a slight variation (I know you will pick me up on moving the typedef cluster outside the AE, but in the long run it's worth the "potential" pitfall. If we are supplying accessors, then it's only a pitfall for us, not the user). So I am deliberately sacrificing a small bit of robustness for a large gain in flexibility.

Accessor


AE

I don't think it's any different to the boiler plate code that you have to use with a DVR. But there is a big motivation for doing this as I hope you will see a bit further down.

So the typing issues has to do with the inputs/outputs to the AE not the state (persistent) data of the either module.
The DVR is the state (albeit a reference to the state - accessed safely using the IPE)
The DVR method inputs/outputs do not need to be isolated/grouped/protected etc... as there is only a single VI that will use them.
In order to handle multiple inputs I don't have to do anything special, thus this makes the DVR less coding.

Not strictly true. You still have to create the bundle and un-bundles in the accessors (and the extra controls/indicators etc) the same as I do in the above images (if changing a current implementation). If you are adding new "Methods" then yes. It only affects the new VI. Wheras I (may) have to create the new VI and add the cases to the AE.this is the point I was making about selection via frames or via VIs. This, however is both a strength and a weakness for the DVR method
.

IMHO the classic AE is not as robust, I have already addressed the following as to why I think it is not and why it should be wrapped to provide a more robust API to the end user:



Additionally the Command Enum should be private/hidden as e.g. this will not allow user to run private methods.

Point of interest/view etc. I don't consider AE=API.An API might be composed of many AEs which are self-contained sub-components. (Maybe that's just in my world though)

Considering what I just said, the Cmd enum is not private in an AE, it is public. Why should it be private? (what was I saying earlier about anal computer science?). We want the user to be able to choose the methods and there is nothing in the AE that he shouldn't be accessing (unless you've not partitioned correctly and have loads of methods that are internal only-a state machine is an abuse of an AE!). If it's not on the enum, then he can't access it so why go making it harder for him to do so? You wouldn't go making a drop-down on a front panel private, would you?

I like the DVR method, now I know more about it and will certainly be looking at some of my current implementations to see if this type would be better. But it has one weakness which (as I stated earlier) is also it's strength.

So here's the kicker. :)
It has one accessor (VI) for each and every method!

We've covered the ground with different inputs and (I think) there is little in it (but the DVR is definitely in the lead at this point). What if we have multiple methods but the same input type?

Lets say we have in our AE example the boolean input but we can do AND, OR, XOR, NAND, NOR, NXOR etc. Thats 6 more accessors (VIs) for the DVR all looking remarkably similar except for the boolean operation. That's not promoting code-reuse and and inflates the code-base.

This is the (single) accessor for the AE with the 6 extra operations (1 extra type-def).



I have to modify the case structure to include the extra operations, but I only have 1 "vi" and 1 typedef ("boolean Method") to maintain regardless of the number of boolean operations. The codebase also doesn't change i.e there is zero increase in the number of VIs for increasing boolean operations. This is why partitioning is so important. If you can partition your engines so that they are grouped "by function" then maintenance is easier and code re-use is increased . The DVR code-base seems to increase linearly with the methods and there also seems to be zero opportunity for re-use of the accessors.(not mentioning the compile time here :P ).

Edited by ShaunR, 29 December 2011 - 07:17 AM.

A positive attitude may not solve all your problems, but it will annoy enough people to make it worth the effort. (Herm Albright 1876-1944).

Founder and general mischief maker on www.labview-tools.com.
SQlite aficionado and websocket zealot.
If it 'aint in LabVIEW, then you 'aint got a clue!

#25 jgcode

jgcode

    LabVIEW Renegade

  • OpenG
  • PipPipPipPipPipPip
  • 2,397 posts
  • Location:Australia
  • Version:LabVIEW 2009
  • Since:2005

Posted 29 December 2011 - 08:53 AM

I don't think it's any different to the boiler plate code that you have to use with a DVR... ...You still have to create the bundle and un-bundles in the accessors (and the extra controls/indicators etc) the same as I do


There is no boilerplate code with the DVR (that is why it is less coding).
Sure data is bundled/unbundled but this is the state data i.e. the data that is persistent for that module - same as in an AE:

AE state.png

DVR state.png

This is the (single) accessor for the AE with the 6 extra operations (1 extra type-def).


I don't agree with sharing inputs for methods.
Yes, it may appear advantageous to share them initially - especially if a module starts off small.
But it violates encapsulation (and I aside for that I find it confusing).
What if we have to change the inputs for Method 1 in the future - how do we know that it won't affect any other methods?
We don't. If each method has it's own input/output cluster then we can confidently make changes to that method.
We do not need to worry about this with the DVR-IPE implementation.

In the example you are referring to, this is your method's interface:

method.png

In order to reuse your states you have created an input Enum that is a subset of your module's Command Enum - now they are coupled to each other.
A change will mean you will need to make a change in two places.

Posted Image

Now this method interface can still be replicated using a DVR-IPE - and I think it's cleaner/more-robust (just throw in the paths):

BD.png

#26 neil

neil

    Extremely Active

  • Members
  • PipPipPipPip
  • 408 posts
  • Location:Surrey, UK
  • Version:LabVIEW 2012
  • Since:2004

Posted 29 December 2011 - 10:41 AM

Methods/accessors/wrapper VIs should be simple (do one thing, do it properly), so for most of the time there will not be the need for multiple variant inputs to the main VI.
CLA, CPI and CTM (Certified Tea Maker)

#27 jgcode

jgcode

    LabVIEW Renegade

  • OpenG
  • PipPipPipPipPipPip
  • 2,397 posts
  • Location:Australia
  • Version:LabVIEW 2009
  • Since:2005

Posted 29 December 2011 - 10:45 AM

Methods/accessors/wrapper VIs should be simple (do one thing, do it properly), so for most of the time there will not be the need for multiple variant inputs to the main VI.


Saying that a method only has one argument most of the time is a pretty big assumption!

It is going to be totally dependent on the module.

#28 ShaunR

ShaunR

    LabVIEW Archetype

  • Members
  • PipPipPipPipPipPip
  • 2,224 posts
  • Version:LabVIEW 2009
  • Since:1994

Posted 29 December 2011 - 03:53 PM

Methods/accessors/wrapper VIs should be simple (do one thing, do it properly), so for most of the time there will not be the need for multiple variant inputs to the main VI.

I tend to make a distinction here. An accessor (for me) will be of the ilk "do one thing, do it properly" (get name, get value set name, set value etc). But a wrapper would be a simplifier of a more complex function or "wrap" several "Methods" to yield a new function.

There is no boilerplate code with the DVR (that is why it is less coding).
Sure data is bundled/unbundled but this is the state data i.e. the data that is persistent for that module - same as in an AE:


Of course there is. It's the IPE, (un)bundles, case structure and the "get ref". That's why all the accessors look identical at first glance and why you can use a wizard to create them (or a template vi from the palette or your Save As (copy) gets a thorough workout).

I don't agree with sharing inputs for methods.


That strikes me as a bit odd, for you to say, since since overrides (and overloading) are the epitome of input sharing.

Yes, it may appear advantageous to share them initially - especially if a module starts off small.
But it violates encapsulation (and I aside for that I find it confusing).


I disagree. It has nothing to do with encapsulation.

What if we have to change the inputs for Method 1 in the future - how do we know that it won't affect any other methods?
We don't. If each method has it's own input/output cluster then we can confidently make changes to that method.
We do not need to worry about this with the DVR-IPE implementation.

"What-ifs" don't feature much in my designs nowadays. If there is an immediate "genericism" then I will most likely code it that way. Otherwise it will be to spec and no more. I exclusively use an iterative (agile) development cycle so changes will be factored in on the next cycle and costed accordingly. If you don't need to worry about impacts of changes on other functions, then regression testing is a thing of the past, right? The fact is, most changes affect most things to a greater or lesser extent. With linear coding (which is what this is), you've just got more to check.

In the example you are referring to, this is your method's interface:

In order to reuse your states you have created an input Enum that is a subset of your module's Command Enum - now they are coupled to each other.

A change will mean you will need to make a change in two places.

Yup. Coupling is a bad thing. Oh hang on. :) I have to get info from here...to here. How do I do that if I uncouple them?
Coupling, as has been discussed here before, is a balancing act the same way as efficiency vs function.

Now this method interface can still be replicated using a DVR-IPE - and I think it's cleaner/more-robust (just throw in the paths):

BD.png

Yup. I like that. I'm still warming...not red hot yet though. :yes: Now re-use it for integer types.

Linear programming is fine, but tends to lead to bloat, very little re-use and, if used ad-nauseam inflexible code. If you want software to create software, then it's great because it is crank the handle and you get one for everything, all the same, with a slight variation. But the cost is long term maintainability, increased code-base, compile times and re-use.

This is the reason I like polymorphic VIs, but think very carefully before using them. They, in themselves are re-usable and give the ability to adapt-to-type making it easier for users. But they are code replicators. Copy and paste managers. Hierarchy flatteners. And that doesn't sit well with me.

Back to topic ;)
A positive attitude may not solve all your problems, but it will annoy enough people to make it worth the effort. (Herm Albright 1876-1944).

Founder and general mischief maker on www.labview-tools.com.
SQlite aficionado and websocket zealot.
If it 'aint in LabVIEW, then you 'aint got a clue!

#29 neil

neil

    Extremely Active

  • Members
  • PipPipPipPip
  • 408 posts
  • Location:Surrey, UK
  • Version:LabVIEW 2012
  • Since:2004

Posted 29 December 2011 - 07:08 PM

Saying that a method only has one argument most of the time is a pretty big assumption!

It is going to be totally dependent on the module.


This is the way I code my AEs. I usually have single input accessors for every single variable stored locally (feedback node is my current flavour). This is quite a bit of code usually, but quick to generate and VERY flexible.

The data is set then an action is performed on it (another VI). I very seldom need two variant inputs this way.
CLA, CPI and CTM (Certified Tea Maker)

#30 jgcode

jgcode

    LabVIEW Renegade

  • OpenG
  • PipPipPipPipPipPip
  • 2,397 posts
  • Location:Australia
  • Version:LabVIEW 2009
  • Since:2005

Posted 30 December 2011 - 01:05 AM

This is the way I code my AEs. I usually have single input accessors...


I tend to make a distinction here. An accessor (for me) will be of the ilk "do one thing, do it properly" (get name, get value set name, set value etc). But a wrapper would be a simplifier of a more complex function or "wrap" several "Methods" to yield a new function.


I agree with Shaun to make the distinction for the purpose of discussion.
And yes, if you define accessors then they should get/set one piece of the internal state data. (because that's what accessors do).
In the examples I have posted I haven't mentioned accessors - I have been talking about supplying inputs/outputs for methods (I guess that's a distinction made there) - and the issues I have with that in the past and trying to make it more robust.

I wanted to present other way of creating an AE using a DVR-IPE.

#31 Mechatroner

Mechatroner

    Are we there yet?

  • Members
  • 5 posts
  • Location:US
  • Version:LabVIEW 8.5
  • Since:1996

Posted 08 January 2012 - 12:25 PM

Thanks for all of your comments. I'm glad to hear that there appear to be no known problems with FG and USRs. It's also been interesting to hear about the different variations of FGs that have been developed.

Regards,

John Bergmans

#32 Val Brown

Val Brown

    The 500 club

  • Members
  • PipPipPipPipPip
  • 702 posts

Posted 08 January 2012 - 05:12 PM

So if I'm following this, jgcode you would "approve" of FGVs as an accessor but not as a wrapper, whereas others are OK with using FGVs as wrappers, using either a (large) typedef cluster for the inputs and outputs, in that sense turning the FGV into an "accessor" if you will to a collection of methods, properties, etc.
All of my objects are byval

#33 jgcode

jgcode

    LabVIEW Renegade

  • OpenG
  • PipPipPipPipPipPip
  • 2,397 posts
  • Location:Australia
  • Version:LabVIEW 2009
  • Since:2005

Posted 10 January 2012 - 01:51 PM

So if I'm following this, jgcode you would "approve" of FGVs as an accessor but not as a wrapper, whereas others are OK with using FGVs as wrappers, using either a (large) typedef cluster for the inputs and outputs, in that sense turning the FGV into an "accessor" if you will to a collection of methods, properties, etc.


I don't 100% follow the above (I think our definitions of things are different - but that's ok).
If it helps here are my posts in summary:
  • I agree with using FGV/MFVI/AE's etc... on a module per module basis
  • I think all approaches discussed are valid - there are good reasons for both (I particularly find ShaunR's perspective in his last post above very interesting)
  • I just personally prefer creating an API for a module
  • I really like the 'LV2009' approach and hence wanted to post it in this thread to share with the OP


#34 Val Brown

Val Brown

    The 500 club

  • Members
  • PipPipPipPipPip
  • 702 posts

Posted 10 January 2012 - 07:22 PM


I don't 100% follow the above (I think our definitions of things are different - but that's ok).
If it helps here are my posts in summary:

  • I agree with using FGV/MFVI/AE's etc... on a module per module basis
  • I think all approaches discussed are valid - there are good reasons for both (I particularly find ShaunR's perspective in his last post above very interesting)
  • I just personally prefer creating an API for a module
  • I really like the 'LV2009' approach and hence wanted to post it in this thread to share with the OP


Yeah, jargon can always get in the way. Like Shaw said: "England and America are two countries separated by a common language."

Thanks for the confirmation of that and my (I think I got it) understanding.
All of my objects are byval