Jump to content


Photo
* * * * * 4 votes

Techniques for componentizing code


  • Please log in to reply
71 replies to this topic

#61 AlexA

AlexA

    Very Active

  • Members
  • PipPipPip
  • 129 posts
  • Version:LabVIEW 2010
  • Since:2007

Posted 20 April 2012 - 06:30 AM

Yeah Daklu, after reading James post and letting a few things percolate that had already bothered me (the fact that a "cast to more specific" call feels very similar to a "variant to data" call), I've come to the conclusion that I was wasting my time.

Thankfully though, I've largely gotten over my irrational aversion to passing data via the messaging architecture. Contingent on the architecture being able to keep up with my data update rates!
Posted Image

#62 Daklu

Daklu

    Bringing the Fu to you

  • Premium Member
  • 1,752 posts
  • Location:Seattle
  • Version:LabVIEW 2009
  • Since:2006

Posted 20 April 2012 - 07:13 AM

Contingent on the architecture being able to keep up with my data update rates!

Sometimes for high throughput data streams I'll create a direct data pipe from the source to the destination to avoid loading down the messaging system. The pipe is just a native queue (or notifier depending on your needs) typed for the kind of data that is being sent. You can send the queue refnum to the data source and/or destination actors as a message. The data pipe is *only* for streaming data; all control messages (StartCapture, FlushToDisk, etc.) are still sent through the regular messaging system.

Certified LabVIEW Architect
Dak's First Law of Problem Solving: If the solution looks simple, I don't know enough about the problem.

Yes, the QSM is flexible. So is Jello. That doesn't make it good construction material.

There are two secrets to success:
Secret #1 - Never tell everything you know.


#63 AlexA

AlexA

    Very Active

  • Members
  • PipPipPip
  • 129 posts
  • Version:LabVIEW 2010
  • Since:2007

Posted 20 April 2012 - 09:37 AM

Yeah that was what I was doing, with the added difficulty that different processes could register for the same data queue (not simultaneously). Looking at my code now, I think I had a problem of too much separation of functionality. For example, almost sequential functionality such as reading in a data set from the FPGA and calculating its average, were separated, the reader read the data then passed it to a whole other process that basically existed to calculate the average and subsequently pass it to the UI. Needless complexity.

I'm busily trying to create a logical construct, but its very much a learning process for me, I'm still struggling with the fundamental discussion of this thread, the problem of componentising code. I wish I could wrap my head around the whole "write a story where the nouns become objects and the actions become methods" but it just doesn't gel with me at the moment.
Posted Image

#64 drjdpowell

drjdpowell

    The 500 club

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

Posted 20 April 2012 - 12:31 PM

Tell me again why you're developing all your own stuff instead of joining LapDog? :lol:

Short answer: started (and had the first app using it) before I knew LapDog existed. Keep meaning to see if I can reformat the message part into a LapDog extension. Or make the messenger part interoperate with your "Message Queue”.

#65 for(imstuck)

for(imstuck)

    Very Active

  • Members
  • PipPipPip
  • 139 posts
  • Location:Texas
  • Version:LabVIEW 2012
  • Since:2008

Posted 01 September 2012 - 01:50 AM

I'm curious if someone can speak to the benefits and drawbacks of having a case structure that takes a string from the message (as is shown in this example), versus something like the actor framework that has a Do.vi that is must override for every message. I feel the actor framework method of message handling is safer because the programmer is required to define a Do method for each message which defines how it is handled. In this example, the programmer still has the possibility of having a typo in his message name or case structure which would not be found until runtime. With the actor framework, it forces you to implement what to do when a specific message is gotten, and if this isnt' defined it is caught at compile time.
CLA (but still always learning)

#66 Daklu

Daklu

    Bringing the Fu to you

  • Premium Member
  • 1,752 posts
  • Location:Seattle
  • Version:LabVIEW 2009
  • Since:2006

Posted 01 September 2012 - 03:37 AM

Command pattern messages (Do.vi) are arguably a more OOPish design, they are more efficient at runtime, and yes, they eliminate the risk of typos in the case structure.

Name/Data messages (whether they are LVOOP or not) centralize the message handling code, are more familiar to most LV developers, support better natural decoupling, and (imo) require less work to refactor.

Theoretically command pattern messages are "safer." However, in practice I've found typos to be a non-issue. I write my message handlers so the default case handles any unexpected messages (such as from a typo) and generates an "Unhandled Message" notice for me. On rare occasions when I do make a mistake it is quickly discovered.

Neither is inherently better than the other. Name/data messages support my workflow and design requirements better. I'll use the command pattern only when I need it. Others swear by command pattern messages.

Certified LabVIEW Architect
Dak's First Law of Problem Solving: If the solution looks simple, I don't know enough about the problem.

Yes, the QSM is flexible. So is Jello. That doesn't make it good construction material.

There are two secrets to success:
Secret #1 - Never tell everything you know.


#67 ShaunR

ShaunR

    LabVIEW Archetype

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

Posted 01 September 2012 - 04:52 AM

I'm curious if someone can speak to the benefits and drawbacks of having a case structure that takes a string from the message (as is shown in this example), versus something like the actor framework that has a Do.vi that is must override for every message. I feel the actor framework method of message handling is safer because the programmer is required to define a Do method for each message which defines how it is handled. In this example, the programmer still has the possibility of having a typo in his message name or case structure which would not be found until runtime. With the actor framework, it forces you to implement what to do when a specific message is gotten, and if this isnt' defined it is caught at compile time.

I agree with everything Daklu has said (with the exception of efficiency ;) but wholeheartedly with typos). Since I am firmly in the case structure camp for this stuff I would also add (in addition to my earlier posts which detail other aspects):

Pros:
  • Much smaller code base.
  • Single point of maintenance,
  • Better genericism (what do I mean? Discuss :P ).
  • Looser coupling between messages and code (there is no code for messages).
  • Less replication.(you don't need wizards or tools to save copying and pasting).
  • Better portability (messages can easily be transmitted via ethernet, serial etc and interface to non-labview languages).
Cons
  • Typos (trivial)
  • State difficult to handle (e.g. timed/timeout responses).
Dynamic dispatch is a stealth case statement with handcuffs :D

Edited by ShaunR, 01 September 2012 - 04:58 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!

#68 for(imstuck)

for(imstuck)

    Very Active

  • Members
  • PipPipPip
  • 139 posts
  • Location:Texas
  • Version:LabVIEW 2012
  • Since:2008

Posted 01 September 2012 - 06:22 PM

Command pattern messages (Do.vi) are arguably a more OOPish design, they are more efficient at runtime, and yes, they eliminate the risk of typos in the case structure.

Name/Data messages (whether they are LVOOP or not) centralize the message handling code, are more familiar to most LV developers, support better natural decoupling, and (imo) require less work to refactor.

Theoretically command pattern messages are "safer." However, in practice I've found typos to be a non-issue. I write my message handlers so the default case handles any unexpected messages (such as from a typo) and generates an "Unhandled Message" notice for me. On rare occasions when I do make a mistake it is quickly discovered.

Neither is inherently better than the other. Name/data messages support my workflow and design requirements better. I'll use the command pattern only when I need it. Others swear by command pattern messages.


Thanks for the responses, guys. Hopefully this will never turn into the OOP version of the string vs. enum debate! I try to keep in mind this is LabVIEW, not c++ or JAVA so sometimes things will not conform perfectly to the generally accepted practices in those languages.
CLA (but still always learning)

#69 for(imstuck)

for(imstuck)

    Very Active

  • Members
  • PipPipPip
  • 139 posts
  • Location:Texas
  • Version:LabVIEW 2012
  • Since:2008

Posted 03 September 2012 - 06:12 AM

As I study this more and adapt it to meet my general needs, I came up with another question. You mentioned providing type safety by passing the slave loop class to the event loop, which forces developers to write methods for the messages. But it seems that this same type safety doesn't hold true for messages sent back to the "master" because the slave loop can get the queue reference directly. Would it be safer to have a "master" class as well which holds the queue ref in its private data and then pass that class to the slave loop instead? Then it would force messages sent to the master to have methods defined.

Edited by for(imstuck), 03 September 2012 - 06:15 AM.

CLA (but still always learning)

#70 Daklu

Daklu

    Bringing the Fu to you

  • Premium Member
  • 1,752 posts
  • Location:Seattle
  • Version:LabVIEW 2009
  • Since:2006

Posted 03 September 2012 - 10:26 PM

Let me start by saying my development practices have changed a lot in the 1.5 years since I started this thread. I still use slave loops (although I don't call them that any more) and my apps are still based on hierarchical messaging, but I don't put nearly as much effort into enforcing type safety. I can easily add type safety if I think I need it (like if I'm exposing a public api to other developers or building an app allowing plugins) but most of the time it's just extra work that doesn't provide me with any benefit.


Would it be safer to have a "master" class as well which holds the queue ref in its private data and then pass that class to the slave loop instead? Then it would force messages sent to the master to have methods defined.

Yeah, it probably would be safer. If you want to spend the time wrapping all the master messages in methods you certainly can--I won't tell you you're wrong for doing so.

However, there are significant consequences of doing that. Having the slave loop call methods defined by the master loop makes the slave loop statically dependent on the master loop. Since the master already depends on the slave you now have a circular dependency in your design. That's usually bad. Managing dependencies is the single most important thing I need to do to keep my apps sustainable. Unfortunately it's rarely discussed. Probably because it's not as sexy as actors and design patterns.

I am curious why you're so interested in safety. Type safety is fine, but it costs development time to implement. Furthermore, the more safety you build into your app the more time it will take you to change the app when requirements change. Too much type safety will soon have you pulling your hair out every time your customer says, "I was thinking it would be cool if we could..."

I agree with everything Daklu has said (with the exception of efficiency ;) )

I've never benchmarked examples. I got the runtime efficiency information from AQ and he's in a better position to know than I am.

Certified LabVIEW Architect
Dak's First Law of Problem Solving: If the solution looks simple, I don't know enough about the problem.

Yes, the QSM is flexible. So is Jello. That doesn't make it good construction material.

There are two secrets to success:
Secret #1 - Never tell everything you know.


#71 for(imstuck)

for(imstuck)

    Very Active

  • Members
  • PipPipPip
  • 139 posts
  • Location:Texas
  • Version:LabVIEW 2012
  • Since:2008

Posted 04 September 2012 - 12:53 AM

I am curious why you're so interested in safety. Type safety is fine, but it costs development time to implement. Furthermore, the more safety you build into your app the more time it will take you to change the app when requirements change. Too much type safety will soon have you pulling your hair out every time your customer says, "I was thinking it would be cool if we could..."


I'm not directly interested in only this, although I see why it came off that way. As I transition to using and fully understanding LVOOP, I just want to make sure I cover all of my bases, and there are certain points I understand more than others. So, some I may hammer home until I understand the best way, then move onto the next thing that I'll repeatedly ask questions about until I understand it fully :P . I assume it will be like learning LabVIEW; I'll just do it, ask questions, refactor it, ask more questions, refactor it then one day I'll realize I no longer have to ask questions and instead can answer them.

Edited by for(imstuck), 04 September 2012 - 12:53 AM.

CLA (but still always learning)

#72 Daklu

Daklu

    Bringing the Fu to you

  • Premium Member
  • 1,752 posts
  • Location:Seattle
  • Version:LabVIEW 2009
  • Since:2006

Posted 04 September 2012 - 03:58 AM

As I transition to using and fully understanding LVOOP, I just want to make sure I cover all of my bases...

Fair enough. That's very similar to how I learned it too... start by learning the "academically correct" way to implement it, then once I understand that I can selectively implement only those aspects that are important for a given project.

Certified LabVIEW Architect
Dak's First Law of Problem Solving: If the solution looks simple, I don't know enough about the problem.

Yes, the QSM is flexible. So is Jello. That doesn't make it good construction material.

There are two secrets to success:
Secret #1 - Never tell everything you know.