If you haven’t heard, LabVIEW 2012 features a redesigned ‘Create Project’ dialog that provides recommended starting points for a breadth of measurement and control systems. One of our primary goals was to ensure that you don’t have to start new projects from scratch, and to help the LabVIEW community leverage well-established and robust architectures. In the process of designing this new experience, we recognized the importance of making it open and extensible by the LabVIEW community so that you can create and add your own custom templates and distribute them to colleagues and customers.
In this entry, I wanted to provide insight into the necessary steps to create a template, package and distribute it as a VI Package file, and also explore... [Read more]
If your instinct is to use an array to manage a lookup table, keep reading - there's a far better way. In case you're not familiar with the term, a 'lookup table' refers to a large table of values that need to be randomly and arbitrarily retrieved programmatically - you may also see these referred to as a 'dictionary' or 'map.' As the name implies, these are typically used in software when you want to retrieve a very specific element or value from a large dataset based on some unique identifier or key. If the data you need to retrieve is stored in a large, unsorted array, the only way to retrieve the information is to inspect every element in the array until you find the information you need - this is often referred to as a 'brute-force' method, and it's highly inefficient and extremely slow. As I'll explain, variant-attributes provide a very efficient and highly performant alternative to this approach in LabVIEW.
A real-world scenario that may help cement this concept would be the task of looking up a word in a dictionary - the word itself is the unique identifier and the information we're hoping to retrieve is the definition of that word. No one would ever try to find a word by inspecting every page in order, as this could take an extremely long time. Instead, we quickly skip to the word we want thanks to the fact that the dictionary stores the word in a sorted order. A typical dictionary (especially a print edition) also has the luxury of being a predefined dataset that remains fixed - words are not regularly added or removed.
In software, large datasets are often dynamic - elements are regularly added, changed or removed, which necessitates an efficient algorithm to easily find, retrieve, store and modify these items. I recently published this Measurement Utility, which employs several lookup tables that I'll use as examples. If you're not familiar with it, this utility is an architectural illustration of how to abstract measurements, the hardware that they measurements interact with, and the results that individual measurements return. The framework keeps track of the measurements that are currently running, the hardware that the system has access to, results from completed measurements, and other characteristics of the system. Since the framework is designed to run arbitrary measurements with arbitrary (but compatible) hardware, I needed a dynamic and performant way to easily store and retrieve various pieces of information.
The Measurement Utility uses a total of seven lookup tables to store various pieces of information, all of which are retrieved using a unique identifier string. If you're interested in exploring any of these and their use, look for them in the private data of Controller Object (in user.lib). The data-type of the value returned is predefined and indicated in the parenthesis:
- Table 1: Given the name of a measurement, return the queue to send messages to this task (Queue Reference)
- Table 2: Given the name of a measurement, return the Object representing this measurement (Class)
- Table 3: Given the name of a piece of hardware, return the Object representing this device (Class)
- Table 4: Given the name of a measurement, return an array of device types (ie: DMM, FGEN) it needs (Array of Strings)
- Table 5: Given the type of hardware needed, return an array of device IDs (ie: PXIe-4110) that match the type (Array of Strings)
- Table 6: Given the device ID of a piece of hardware, return whether or not it is currently in use (Boolean)
- Table 7: Given the name and time of a previously run measurement, return the Object representing the results of this measurement (Class)
Before going any further, we need to understand what a variant-attribute is. A variant is a data-type in LabVIEW that can be used to encapsulate and store any piece of data in LabVIEW; however, nothing is actually stored in the variant when using it as a lookup table. What we care about for the sake of creating a lookup table is a little-known property of the variant data-type: it can store attributes! If you look under the 'Cluster, class and variant' palette and dig into the 'variant' sub-palette, you'll see the API that we'll use - in particular, we care about the following functions:
- Set Variant Attribute
- Get Variant Attribute
- Delete Variant Attribute
Figure 1: The API for storing and retrieving keyed-value-pairs using Variant Attributes are straight forward and easy to use
This very simple API takes advantage of very high-performance algorithms under-the-hood to sort, manage and retrieve keyed-value-pairs. As per usual in LabVIEW, you don't have to know or understand how this mechanism works to take advantage of it, and it saves you the trouble of trying to keep a dataset ordered and writing the algorithms necessary to parse it efficiently (think hash tables and linked-lists).
One of the logical next questions is, 'how much more performant is a variant-attribute table versus simple brute-force?' The actual speed will obviously vary depending upon where in an array the data value would be located, but to compare algorithms you always examine the worst-case scenario. The worst-case-scenario for brute force is that you'll have to look through every single element before finding an item at the end, so we denote this as O(N) complexity, meaning that there is a linear relationship between the number of elements and the amount of time this operation may take. Variant-attributes are implemented using a C++ std:: map structure (this has not always been the case - only in more recent versions of LabVIEW), which has an O(log N) complexity, which is a considerable difference, even as N approaches a modest size.
Figure 2: A comparison of the two algorithms reveals a considerable difference between the performance - the performance of the variant-attribute table is represented by the blue line, which is very hard to see when compared with the linear complexity of an array.
In addition, it's also much simpler than writing the code necessary to parse and search an array. The following block diagram illustrates how Table 2 is used in the Measurement Utility to retrieve the specific object representing a measurement based on the name.
When loading a new measurement into the system, tables 2 and 4 are populated with information: Table 2 is the only location where the Measurement Object is stored (to avoid data copies), and Table 4 allows quick retrieval of the required hardware types when needed. You could argue that table 4 is unnecessary, but since retrieving this information is a common operation (perfored everytime a user selects a measurement from the UI drop-down), I made the design decision to not fetch the measurement object every single time.
For those of you familiar with the Actor Framework, the Measurement Class is actually derived from the Actor Class. Everytime a measurement gets spun up, the queue for this actor is stored in Table 1, which makes it easy to retrieve anytime a message needs to be sent to that measurement. Upon completion of the measurement, that queue is deleted from the lookup table. Results are returned (as an object) from measurements upon completion, which are stored in yet another lookup table (Table 7). This is especially useful, since we can easily accrue a large number of results, and we want users to be able to quickly retrieve and review results.
Hopefully this gives you a good understanding of how variant-attributes can be used as a much more efficient alternative to arrays. If you're interested in learning more, I would encourage you to explore the Measurement Utility referenced by this article, here. As usual, let me know if you have any thoughts or feedback or want additional explination!
NIWeek is just a few days away, and there's plenty to be excited about this year! I've made a habit of recommending sessions that I think will be especially good for advanced users in previous years, but in reviewing the schedule for 2012, I feel like I'd have to list the majority of software sessions. Considering that the software track has more sessions this year than we've ever had before, that would be a very long list!
For those of you who have been to NIWeek before, we've moved things arround to accomodate the tremendous attendnace growth. The area where the keynote used to be will now be used for additional sessions and hands-ons, and the keynote will now be held in the room where the Expo Floor used to be. We've also increased our focus on Thursday by making it a full day and balancing the must-see sessions across all three days.
I'm especially excited about a new session I'll be presenting on Tuesday at 3:30 in Room 19A, "LabVIEW 2012 Advanced Templates and Sample Projects." I'll be showcasing how a new features of LabVIEW 2012 that gives advanced developers a new tool for distributing and using templates across a team and especially for a large project. My plan is to adapt an Actor Framework based application and illustrate how a new measurement can be templatized.
I'll also be presenting "Software Engineering With LabVIEW," which will be a reprise of last year's session on the topic. In this session I'll be more focsued on the procedural recommendations and life-cycle management techniques to ensure system quality and mitigate risk. In paricular, I'll be discussing the use of source code control, requirements management solutions, and static and dynamic code analysis. This session will be on Tuesday from 4:45 to 5:45 in Room 19B and we will have a hands-on with the tools available on Wednesday at 3:30 pm.
You can also find me showcasing the new features of the latest version of LabVIEW on Tuesday morning at 10:30 in 19A, at the annual "What's New in LabVIEW." You'll also have the opportunity to get your try out some of the exciting new feature in a hands-on in 18D on Thursday at 10:30 am.
Finally, I do want to mention a few other sessions that I think will be especially interesting to the 'Large App' community.
I hope everyone is as excited about NIWeek as I am - less than two weeks to go! I plan to create and post my recommended list of 'large app' NIWeek sessions very soon.
In the meantime, I wanted to make this group aware that I finally recorded a video of the presentation on Measurement Abstraction Layers, Model-View Controller and the use of Actor Framework (yes, all with one application). If you're interested, you can watch the video here (warning: it's 80 minutes long). Slides and demo files can be downloaded from this link.
See you at NIWeek very, very soon! (back to work...)
I am using labview to read intensity data from a camera. I have a constant X where Y is variable. SO i need only the Y data and it comes as one column.
Everytime when i export to a excel sheet i save as a new file.
What I want.... to save all the data in a single XL sheet. If possible to do with a shortcut key would be great. In that case just press a key and data will be saved in a particlular file. If i press 10 times there will 10 different column in that file.
I don't normally use this blog to promote customer applications, but I feel that this one is especially relevant to this group given the focus on software engineering best practices with LabVIEW. Lawrence Livermore is home to the world's largest laser array, and they make heavy use of LabVIEW in an environment that requires the application and enforcement of strict development practices.
Today's entry was inspired by a question I recently received from someone while presenting at Developer Days in Salt Lake City - I was asked, "when and why should I use the 'preserve run-time class' node, and what's the difference between it and the 'to more specific' primitive?" It was a good question, and something that I didn't fully understand myself until I spent some serious time doing object-oriented programming. What follows is my attempt to explain this for anyone else who might have ever wondered the same thing.
The 'to more specific' node is a mechanism to tell the LabVIEW compiler that an object is guaranteed to belong to a certain class of objects. Without this assurance, the compiler has no way of knowing what the object belongs to or is capable of at compile time, and would therefore show a broken wire if you attempted to pass the object wire into a function that can only act upon a certain class of objects.
Perhaps the most common illustration of this is a plug-in framework using classes (also known as a factory pattern). A factory pattern enables you to add or change functionality simply by loading a new child class at run-time. It is required that the calling application already have in memory a common parent, but the newly loaded child class can then override or extend the behavior of dynamically dispatched methods. As an example, a framework may already be written to act upon a generic measurement, which has methods to initialize, acquire and analyze a signal. A specific measurement, such as a frequency sweep, could redefine the implementation of these methods.
Shown below is the code required to load a specific measurement at run-time. The 'Get LV Class Default Value.vi' brings a class into memory from a location on disk, but the compiler has no way of knowing the type of object prior to this operation. This is why we use the 'to more specific class' node, which then allows us to treat the object as belonging to a specific hierarchy - in this case, we treat it as a measurement. Note that the error handling is designed such that we only add the loaded class to the array if it is a valid member of that class hierarchy. If we had not handled this correctly, and we attempted to load an invalid class, this node would return the parent 'Measurement.lvclass' object.
The 'preserve run-time class' node is also a way to give the LabVIEW compiler a guarantee that it would not otherwise have at compile-time - in this case, we are telling the compiler exactly what class of object will be passed out. The primary use-case for this node is within a VI that has a dynamic input terminal and a dynamic output terminal for the same class, but there is not a guarantee that the object's class will be preserved between them. If, for example, we are dynamically loading an object that will replace the object that was passed into the VI, the compiler has no way to know what class the object will be, and will therefore have a broken arrow. 'To more specific' cannot be used in this case, as we need to guarantee the exact class of the object.
In the example below, the other case of the case structure is set to 'Use Default' for the class wire, which means that LabVIEW does not know at compile-time what the class of object is that it will receive. The first diagram of 'common.vi' attempts to use 'to more specific' to indicate that the object will be a child of 'Hardware.lvclass,' but it still does not guarantee that it will be 'SCOPE.lvclass.' As a result, the calling VI, initialize.vi, which has dynamic input and output terminals, is broken, as it needs to know that the exact same class of object will be passed between.
The diagram below shows how we use 'preserve run-time class' to guarantee that the class of the object will be the same as it receives. As a result, initialize.vi can compile and we no longer see a broken run arrow.
This illustrates the most common and important use case for 'preserve run-time class.'
As always, you can find more information on these in the LabVIEW help, but free to post questions and comments!
Hello everyone - I just wanted to take a minute to make sure everyone is aware that LabVIEW 2012 is now in Beta and that the Beta 2 version is now available for download from ni.com/beta. This is not only your chance to get a sneak peak of the new features, it's a key opportunity to evaluate the performance and behavior of your existing applications in the new version and to provide feedback.
I'm especially excited for experienced users to look at the new Templates and Sample Projects that we've put front-and-center in the new Getting Started Window. These templates and sample projects provide recommended starting points for LabVIEW projects, all of which use established design patterns. These sample applications range from basic measurement applications to frameworks for complex embedded control and multi-process applications.
We've also continued to focus on the stability of the environment, as well as a number of new productivity features and enhancements. For a full list of new features to try, be sure to visit the Beta forums after you are registered for the Beta program (you should have access within 24 hours of joining the program).
Also in Beta is NI Requirements Gateway. The new version, which will be releasing with LabVIEW 2012, features increased performance and improved support for LabVIEW classes and the Unit Test Framework. If you've never heard of Requirements Gateway, it's a tool to help track and manage requirements and map them to the implementation. It has advanced reporting and project management capabilities.
So be sure to check these out and let us know what you think,
I just want to take a moment to thank everyone who attended this year’s Certified LabVIEW Architect (CLA) Summit at NI. Once again, I was really impressed by the caliber of the presentations and the level of discussion among all of the attendees. We had a record number of attendees at this year’s summit (almost 100 people from all over the world), and it was impressive to see so many people stay for a third day to dive deep into some of the topics that came out of the first two.
The CLA Summit is a unique opportunity for me, as I get to participate as both a user and as a product manager. It’s great to be able to talk to so many other passionate and knowledgeable LabVIEW users, and as always, to hear your feedback and opinions regarding LabVIEW and the latest advanced concepts.
For those of you who weren’t able to attend, the topic this year was ‘separating user interfaces from application logic,’ which prompted a lot of passionate discussion (and healthy debate) regarding various approaches, such as model-view-controller and various frameworks for implementation. Presentations and demos from the summit are going to be posted to the community group, here: Certified LabVIEW Architect Community Group. You can also try to make the upcoming European CLA Summit, on March 28th and 29th, though I hear that registration is almost full.
Finally, many thanks to the organizers of the event, Fabiola, Mallori, Rob, and Nancy. Well done!
The Certified LabVIEW Architect (CLA) Summit began this morning with a keynote from Jeff K. He spoke about his affinity for object-oriented programming in LabVIEW and welcomed the 99 attendees this year. This year's topic: separating implementation from the user interface.
I’d like to start by wishing everyone a belated happy new year! Time to jump into a new year of LabVIEW programming…
It’s easy to tell code that uses standard design patterns from code that doesn’t – it’s the difference between being able to understand how the application works and having no idea what’s going on without spending a significant amount of time studying the code. This is especially important when working with a team of developers or when developing an application that will need to be maintained over a long-period of time. In either scenario, it’s highly likely that someone besides yourself will have to modify or update the code. This person may not be an expert in exactly what your application does, but if it uses a familiar design pattern, they’ll at least be able to recognize familiar constructs and quickly start contributing.
There are a handful of G-specific design patterns that proficient LabVIEW programmers should already be aware of, including state machines, functional globals, and producer-consumer loops, but LabVIEW programmers should also look to apply concepts from the computer science world to address problems that are universal to all languages. Some of the best-known patterns were first published by a group of authors known as the ‘gang-of-four’ in a book titled ‘Design Patterns: Elements of Reusable Object-Oriented Software’. Since then, the list of object-oriented design patterns has continued to expand to address the growing number of complex software challenges.
One of the first steps when designing software should be to identify where and how standard patterns can be used in your application. This process requires isolating and defining what needs to be achieved in order to meet very specific design requirements, which is a level deeper than the overall architecture of the application. There are numerous examples of patterns and the problems they address, several of which can be found here, but as a starting point, consider the following four patterns and their implementation in LabVIEW.
The factory pattern has been referred to as the most commonly used pattern in modern languages. A factory creates objects without exposing the instantiation logic to the client and refers to the newly created object through a common interface. It’s commonly used in applications that have a plugin component, or some functionality that needs to be loaded dynamically at run-time. This requires the definition of a generic parent object, which encapsulates functionality that can then be reused and even extended by children. [More Info]
Figure 1: This simple snippet of code in LabVIEW enables an application to load children of ‘Generic Plugin.lvclass’ at runtime without having to be aware of the children or their specific functionality ahead of time.
The command pattern is especially relevant to LabVIEW programmers, as it can help address some of the challenges typically associated with sending a command or a message between processes. This typically requires the coupling of the command itself with any data required by that command to execute, which is often achieved by using a cluster containing the command as an enumerated constant and a variant for an arbitrary data-type. The command pattern instead instantiates a new instance of a child class to represents the specific command, which defines the information to be associated with that command within the private data. [more info]
Figure 2: The command pattern uses child classes to represent commands or messages that need to be sent to a consumer loop. Data associated with the command is stored within the object, and the execute method is overridden by each specific class to implement the functionality required to handle the specific message.
As the name implies, the observer pattern can be constructed in LabVIEW such that an observer is aware of changes made to the parent observerable class. In this particular example, the observable class has a method that modifies the data of a class that is referred to by a data value reference. Throughout the lifetime of the observable class, multiple observers may subscribe and unsubscribe. [more info]
Figure 3: In this example, two string indicators are subscribed to an observable class, ‘Text Message.lvclass.’ The observable class stores an array of data value references to observers, which are then retrieved and modified when the method to update observers is run.
Applications are often designed with the knowledge that future functionality will need to be added at a later date, but this is best done without the risk associated with modifying pre-existing code that is tested. The decorator pattern can help in such a scenario, by making it possible to add responsibilities and information dynamically to an object. [more info]
Figure 4: The original object, which is a Dark Roast coffee, is decorated with additional properties by children of a separate hierarchy for condiments. The set of condiments can dynamically be expanded without modifying peers. Invoking the methods to get the cost and the description recursively iterates through all the decorations to aggregate the total values.
These four patterns are just a small number of simple examples illustrating how object-oriented design patterns can be used to solve common problems. To download examples and see many more examples of how object-oriented design patterns can be applied to LabVIEW, visit the community site Applying Common Object-Oriented (OO) Design Patterns in LabVIEW
The use of dynamically loaded VIs is a common and important approach for large applications. It can help decrease load-time or make it possible to 'plug-in' new functionality into an existing application. It's a concept I use in several of the examples I've shared in this blog, but one that often trips up users who are just experimenting with dynamic calls for the first time.
Christina Rogers, author of the Eyes on VIs blog, just posted a great video that explains how LabVIEW manages VI references, which is important for dynamic VI calls. If you have a few minutes, be sure to check it out: VI Reference Lifetime
I've been eager to compose a new blog entry on a wide variety of topics, but I've resigned myself to the reality that I won't have time until I'm back from traveling in mid-November. In the meantime, I did want to pass along a link to a recent online user group presentation that I gave, entitled: Source Code Control and Team Based Development Best Practices. It covers the use of TortoiseSVN (Subversion) with LabVIEW, as well as source-only and the use of the VI Package Manager.
PS: I apologize in advance for the audio - seems my mic was a little too close.
This is a long-overdue continuation of my post on May 8th regarding the use of plugins - an important piece of the puzzle when managing plugins is communication to and from them and in this entry I'd like to focus on how communication can be accomplished through the use of user events.
Open any sufficiently complex LabVIEW application, and you're likely to see more than one while loop. From an organizational standpoint, most programmers consider this an easy way to visually de-couple segments of their code that perform independent, asynchronous tasks. It's also important to note that data-independent loops will automatically utilize multithreading, which makes it possible to take advantage of multicore hardware for the sake of performance and responsiveness. (Note: Two loops are data-independent if neither has an input terminal that depends upon the output terminal of the other).
As important as multiple loops are to most applications, many programmers still struggle to select the correct approach for communication between separate processes. This is often magnified as the application becomes larger and more complex, where a highly-scalable, and highly recognizable solution becomes critical. As with many things in LabVIEW, there are numerous technologies that can be used to solve this problem... in fact, a recent estimation put the count just under 25 (I challenge those of you reading to name all of them, including third-party solutions).
At the risk of grossly over generalizing, one of the most popular solutions for both sending both commands and data streams amongst LabVIEW users are queues, but in this article I would like to highlight how dynamically registered events can be used as an alternative. It's especially applicable when managing plugins, as you'll likely want to broadcast a message to an arbitrary number of registered listeners. Consider how you tell all of the plugins to STOP! If you were using a queue, you would need to create and manage a separate queue for every single recipient (remember, a queue can have multiple producers, but should only ever have one consumer). Instead of creating and managing an arbitraty (and potentiall large) number of queue references, we would like to be able to broadcast a message to an arbitrary number of registered listeners. As you may have already guessed, we can do this with a user event.
The creation and generation of a user event is fairly simple. Like many things in LabVIEW, you create the user event, generate the event when you want to send the message, and eventually destroy it. This event will be handled by any and all Event Structures that have been configured to listen to registered events. The image below shows an illustration of how this is setup. Notice that the event structure has a terminal input known as the 'Dynamic Events Terminal' where these user events are registered (if you do not see this on your event structure, right-click on the frame and select 'show dynamic events terminal'. Because this scenario utilizes an Event Structure, it's an especially useful mechanism for communication with separate 'things' (ie: a Plugin), which may already have a user interface and therefore already be utilizing an event structure. For an actual example of this approach in use with plugins, check out Exercise 5 of the Object Oriented Design Patterns Technical Manual.
Once the registered events have been wired into the Event Structure, you'll have a new list of options to select from when editing the list of events that the structure handles. Ideally, these commands would be pre-defined by the framework or the calling application and the user would be able to choose if and how to handle these events. The OO Technical Manual example passes all the registered events to the plugins through an API that completely hides how and when these events are created and generated. Some (such as 'shutdown') are broadcase, while others are only sent to one specific listener, but this complexity is hidden from the developer responsible for writing the plugin.
One registered, every User Event will appear as an option that can be selected and handled (as shown above), but one of the limitations to this approach is that you have to define the behavior for every single listener and you have to manually configure the event structure to handle that particular user event. However, this can be overcome thanks to the fact that user events can pass data - more importantly, the data can be an Object!
When combined with the command pattern (also mentioned in the OO technical manual), we can create a hierarchy of commands that can potentially be sent to any and all registered listeners. This allows us to easily add new commands and define their behavior without even having to modify the individual plugins. All we need is one event in the structure that dynamically dispatches a method of this class hierarchy that contains the command-specific behavior.
The example below shows how we could send a stop command using this approach, where 'Stop Commpand.lvclass' is a child of 'UI Command Manager.lvclass,' and 'Execute Command.vi' is a dynamically dispatched VI that belongs to this class hierachy.
I've become a big fan of user events to broadcast messages, and (in case you couldn't tell), especially when I need to make it easy to send messages to plugins that need to remain very de-coupled from the calling application. This is not the only approach and doesn't necessarily suit use cases where you need to stream large amounts of data at a high-rate. For this purpose, consider some sort of a FIFO (Queues for local communication, RT FIFOs when it needs to be deterministic, and Network Streams for target to target).
Another approach for async communication between independent processes is the Actor Framework, which simplifies the process of sending commands and data betwen multiple arbitrary processes, and also makes it possible to inherit and extend the functionality of existing actors. More on this later!
Error handling is an important but challenging part of any large application. In an attempt to make it easier to generate specific errors throughout your application, AristosQueue and company has created a new Error Cluster Constant. An early version is available for you to evaluate and download from here.
I am in the process of lobbying them to create a VI Package file to make installation easier, but I strongly encourage anyone that's interested in more advanced error handling to download and evaluate this new tool.
On a related note, the latest version of the Structured Error Handler API is available here.
I am pleased to announce that all toolkits that were formerly available in the Software Validation Tools Developer Suite Bundle are now included with the purchase of Developer Suite Core. This means that anyone who purchases or renews their license for Developer Suite now has access to the following products at no additional charge:
LabVIEW VI Analyzer Toolkit - Enforce proper coding styles with more than 80 included tests and screen for performance and code quality issues
These products have become increasingly important for the success of large systems, and we recognize that they should be in the toolbelt of anyone developing sufficiently complex systems with LabVIEW. These products improve and automate otherwise time-consuming software engineering tasks, such as code reviews, validation, static and dynamic analysis, etc.. For more information and best practices for using these and other software engineering products with LabVIEW, visit ni.com/largeapps, or post your questions and comments below.
Every NIWeek I try to compile a list of recommended sessions for you gurus that are hoping to expand your G horizons, pick up some new skills, or dive deep with advanecd capabilities of LabVIEW. This year, identifying a 'short-list' of recommended sessions is proving especially difficult, due to the abundance of very technical and advanced content that is being presented this year. Of course, you can always expect to find sessions on new products and new features, including 'What's New in LabVIEW 2011,' but I've tried to highlight the sessions that are especially technical and relevant to those of you who care about software engineering and developing large applications.
As an example of this, we have more sessions on Object-Orientation (OO) in LabVIEW than we've ever had. This list doesn't even include some of the more basic sessions on OO, which I would highly recommend if you're just getting started.
You can find the full session abstract and presenter information in the session catalog, but I've given a brief explination of the value I think you'll derive from each session. Also, if I've missed any please feel free to let me know in the comments. Thanks, and see you at NIWeek 2011!
10:30: Hands-On: Manage Reusable Code and Build Commercial Add-Ons with VIPM - If you've ever found yourself struggling to actually reuse code across applications, you need to learn more about VI Package Manager (VIPM). It's also a great way to get reusable libraries that other people have created.
1:00: Building Quality LabVIEW User Interfaces - If you're trying to break free of the highly-recignizeable LabVIEW GUIs, this session will give you some tips and tricks for how to make them look more professional.
2:15: Hands-On: Software Engineering with LabVIEW - Get your hands dirty with Subversion, VI Analyzer, Unit Test Framework, etc... it's a lot for an hour, but you can take the exercise manual with you.
3:30: Trends in LabVIEW OOP - I believe that the highlight of this session will be a glimpse at the latest version of the Actor Framework, which is an increadibly powerful framework that will benefit many advanced LabVIEW programmers.
3:30: Advanced Error Handling in LabVIEW - the name explains it all: frankly, any power user needs more than the native error handling tools and this will be an opportunity to see a very powerful API developed by some of our systems engineers
4:45: Hands-On: Intro to Object Oriented Programming in LabVIEW - this will be a chance to step through exercises that introdce important patterns like the State Pattern and the Factory Pattern.
4:45: The LabVIEW Compiler and Memory Management Techniques - dive deep with members of our R&D team on what makes LabVIEW tick
10:30: Hands-On: Software Engineering with LabVIEW - Get your hands dirty with Subversion (SCC), Requirements Gateway, VI Analyzer, Unit Test Framework, etc... it's a lot for an hour, but you can take the exercise manual with you.
1:00: Hands-On: Intro to Object Oriented Programming in LabVIEW - this will be a chance to step through exercises that introdce important patterns like the State Pattern and the Factory Pattern.
1:00: Team Based Development Techniques, and the Impact of Source Only - Dive deep on source only and the use of source code control. I believe the tool of choice for this presentation will be Perforce.
2:15: Software Engineering Tools for LabVIEW - I'll be presenting as much as I can on software engineering within an hour, including source code control, code reviews, requirements management, etc... (yes, this is a shameless self plug)
10:30: Tips and Tricks to Speed LabVIEW Performance - Darren always delivers with this session, and he always updates it with some new insights each year.
1:00: Building Plug-in Architectures and HALs - This is a new session that I'm especially looking forward to presenting. I will attempt to show the State Pattern and the Factory Pattern inside of an hour and how they can be used for a Hardware Abstraction Layer
2:15: Software Engineering Tools for LabVIEW - this is a repeat in case you couldn't make it on Wednesday
In general, LabVIEW is a highly-productive graphical development environment for scientists and engineers. The language, which is commonly referred to as G, is just one of the aspects of LabVIEW that we believe makes our customers so productive when building and designing systems with our products. To go beyond the language itself, it is the combination of all the elements of engineering in one environment that really differentiates LabVIEW. I'm referring to the abstraction of various hardware platforms, the inclusion of a very large amount of IP that is aimed at engineering and scientific applications, and the very tight integration with hardware and I/O. Because it is so much more than just a language, it is sometimes a difficult comparison with other approaches, and the comparison often risks overlooking a lot of the other benefits.
As the complexity of the applications people are using LabVIEW in has grown over the years, so to has our offering of professional software tools and capabilities. The professional version of LabIVEW includes many features and capabilities that are targeted towards users that do consider themselves programmers, which has made it more approachable for this audience. This has already helped elevate our visibility as a language, but our primary goal is to enable engineers and scientists who care about I/O and turning real-world data into meaningful information for the sake of measurement and control applications.
That's the world as we see it - at this point, here are some specific thoughts on your points (thank you to Shelley G. for contributing her input to several of these posts as well):
1) Reduce the price of LabVIEW Professional to $1500 (and get rid of LabVIEW Base – why teach poor programming practices)
Pricing is always tricky, but Base exists to provide a inexpensive entry point with all of the functionality needed for very simple data acquisition and instrumentation applications. Our model is designed to enable the use of our products at a reasonable price, while still making it possible to fund the very high-level of investment in new features and products (an average of one a day!). Consider that we strive to re-invest roughly 16% of our annual revenue back into our R&D groups. We don't want to teach bad programming practices, but our assumption is that simple tasks do not require the use of advanced programming concepts, which are specific to the professional version.
2) Allow a standard web browser to be the user interface (without any plug-ins!)
I'm glad you brought this up! If this were an individual suggestion I would mark it as complete and point you towards our new LabVIEW Web UI Builder, which you can see and use at ni.com/uibuilder. There are multiple approaches to interacting with a web browser from LabVIEW, but this new tool actually allows you to design an HMI that runs in your browser and communicates with other LabVIEW applications via standard web services. You will need to have Microsoft Silverlight installed on your system, but you do not need the LabVIEW Run-Time Engine (unlike remote front panels).
3) Fold in some of the general purpose toolkits into the main product (best way to add new features!, but I can live without this)
That's exactly what we strive to do with Developer Suite, which gives you access to a wide variety of add-ons and toolkits without having to spend much more. That being said, we have received consistent and vocal feedback from users who want a few toolkits in particular to be more readily available in the Developer Suite Core package, so look for some changes in the packaging with the release of LabVIEW 2011. (I've already said too much!)
4) Sell single board cRIO in quantities of one (at a reasonable price). And show the price on the NI website.
5) Reduce the price of LabVIEW RT, FPGA and embedded.
This goes back to the tricky topic of pricing, but embedded development tools are normally extremely expensive. What you can achieve with LabVIEW FPGA for a few thousand dollars is unmatched in the embedded or test industry.
6) Offer more deployment platforms (RT, FPGA and embedded) – this is where NI will make money, by selling more hardware.
Earlier I mentioned that we release an average of one new product a day, and I think that this is evident if you look at are large portfolio of products on ni.com/products. LabVIEW has enabled us to abstract the complexities of programming for multiple and different hardware targets - making it possible to leverage all the latest platforms and technologies in your application, which we see as a core value proposition. We can target all the latest Xilinx FPGAs and we're constantly coming out with newer, faster and better RT targets. We also recently introduced the LabVIEW ARM module.
7) Offer general-purpose low-cost mini-board (a few digital and analog I/O and a controller). Think 32-bit Arduino-like. In fact, why not make it compatible with the Arduino shields (stackable plug in boards that add functionality).
While we evaluate our own low-cost platforms, we have already plugged LabVIEW into the low-end hardware ecosystems (it’s a big request from our academic market). Check out some of the Arduino resources:
8) Improve the robustness of LabVIEW (in preference to new features).
Absolutely. Based on feedback from users, this is the primary focus of our LabVIEW development team – you will see in LabVIEW 2011 and future releases, an intense focus on performance and stability. This focus is a direct result of compelling customer input like yours.
9) More tutorials, examples and learning documentation (helps users, reduces support costs and opens the door to cheaper LabVIEW).
We have a very large offering of online and in-person training courses for all of our software products, which you can find at ni.com/training. LabVIEW also installs hundreds of examples in the Example Finder (in the 'Help' menu). When it comes to software development best practices and similar practices, you can find a lot of the latest content here at ni.com/largeapps. To see a summary of all of our technical resources, visit ni.com/labview/technical-resources
10) Increase the user base by a factor of 4 (needed to get to “critical mass” for user community).
We totally agree with you here! Lets increase it by 10X for that matter. To this end, we have a large focus on increasing the number of students that know how to use our tools and better connecting them with demand from industry. You can also get involved as a FIRST mentor, participate in local LabVIEW user groups, or even contribute to online discussions (like these). If you have any other ideas, let us know.
11) Have the same feature set across Windows, Macintosh and Unix (or at least reduce the gap).
This is ideal, but, as you know, extremely difficult. Each of those operating systems has a unique set of APIs and capabilities particularly around their UI idioms and more importantly their OS level driver integration models. We have wrestled with this issue for 20+ years and invest heavily to try to normalize what we can with LabVIEW, but we also won’t succumb to creating a lowest common denominator experience. We have actively searched for a software technology that could provide an execution abstraction that runs on Pharlap, LinuxRT, VxWorks, iOS, MacOSX, Windows, Windows Phone, Android, and Web browsers and sadly have not found one. However, we agree that we need to continue invest in better cross platform support and we are actively doing so for our future feature developments. We believe we have found a path that only requires us to implement features twice to run on the platforms that you have requested and we or an a path to better support for drivers on the Mac and on Linux.
12) Publish a textbook for experienced LabVIEW programmers that want to move step-by-step to object oriented LabVIEW programming (assuming this is the way to go, haven’t used it myself so not sure how useful it is).
I definitely think it's the way to go, and there are a number of great resources that you should check out. Actually, several people in this community contributed to a document I'd recommend you review, called Applying Common OO Design Patterns to LabVIEW. We also have a growing number of text-books, which you can find a list of here. For more information on object-orientation, we even have instructor-led training: LabVIEW Object Oriented Design Patterns.
13) Add features to make it a more general purpose programming language (to challenge C, C++ and C#). Don’t take it too far, we don’t need LabVIEW to write word processors and database programs, but we would like to write home automation software (my next hobby project), general purpose utilities and more commercial software to go with our products (as opposed to our current usage of just in-house software).
We couldn't agree more, which is why we've invested so heavily in advanced software features and in enabling the standard software engineering and configuration management practices that users expect. You can and should be using LabVIEW with fundamental tools like source code control and static code analyzers. For more information on this, visit ni.com/largeapps, or just browse around this community.
14) Improve controls and indicators to allow the same look-and-feel as “professional” programmes. Want to create an awful user interface? Just add a Toggle Switch! There done! (Can you imagine any commercial software written in any other language that would go out of their way to add a Toggle Switch looking control? Can you even begin to imagine this in, say, Windows?). Anyway, more controls and indicators that look like those of general purpose applications and a built-in powerful easy-to-use control and indicator editor.
I love that I can always spot a LabVIEW Front Panel when watching the Discovery Channel, but I agree that alot of them are pretty ugly. Many people don't realize just how much you can customize the appearance of front-panel controls in order to design an extremely professional application. There is an entire community (and avery active one) dedicated to this very topic, here: UI Interest Group. There are also a number of great examples of progessional UIs throughout the web and in the product (a lot of LabVIEW is written in G). Finally, I strongly recommend checking out the Beta of LabVIEW 2011, as you might find some new palettes that will make designing professional interfaces even easier.
That should do it for LabVIEW 2012. I’ve got more to take LabVIEW to the Top 20 programming languages.
The use of plugins in the design of software provides an elegant and popular solution for a lot of common architecture challenges, especially when dealing with a set of several similar but different components. The encapsulation of functionality into a plugin is intended to make it easy to manage and define the behavior of a component without modifying the calling framework. It also helps enforce a number of other best practices concerning the modularity and scalability of an application. To illustrate this, we'll be taking a look at designs that make use of a factory pattern and LabVIEW Classes, concepts we'll spend more time on in a minute.
For LabVIEW programmers, plugins can provide an especially scalable mechanism for large systems that have to interface with a wide variety of hardware - especially when the hardware may vary across different systems, or has to be regularly changed or added to. Because of this, a plugin approach can help mitigate the costs and risks associated with hardware that becomes obsolete and has to be replaced, making plugins an integral part of almost any Hardware Abstraction Layer (HAL). This also makes it possible for development to proceed concurrently on separate parts of the application with minimal or no risk of impacting unrelated parts of a project, something which is especially useful when dealing with large teams.
Another example of the benefit of a plugin-based approach is a complex user interface such as an options dialog or a wizard-like dialog. As an example, consider the LabVIEW options dialog, which makes use of plugins. It displays different interfaces depending upon what software is installed. Like the hardware scenario, you have a set of similar objects that have different functionality and you want to be able to change, add or remove functionality without modifying any code that is above it in the application hierarchy. This brings me to a very important point... a plugin architecture inverts the dependency you would see in a statically linked application. This is typically referred to as the dependency inversion principle. This principle states (source: wikipedia)
A. High-level modules should not depend on low-level modules. Both should depend on abstractions.
B. Abstractions should not depend upon details. Details should depend upon abstractions.
To understand the dependency inversion principle, consider a large, monolithic application whose dependencies are entirely statically linked. Top level components are dependent on the VIs it calls, which are dependent on the VIs they call. As a result, modifying the lowest-level component can create changes that propagate up and at the very least, require recompiling the entire application or rebuilding the executable. If the code is entirely statically linked and monolithic, it tends to expose developers to additional risk when making changes because standard APIs and communication with other components has not been defined in an abstract way. In a well designed application, the dependency is inverted such that a set of low-level components (ie: plugins) are actually dependent on the calling framework through standard APIs and communication mechanisms. As long as these are maintained, the plugins can be modified and developed without impacting any callers. These same abstractions and APIs make it equally possible to modify the framework without recompiling or changing the plugins - again, this relies on those abstractions remaining the same.
So how do design an application to use plugins in LabVIEW? Before jumping to a solution, there are several very important things to consider (this is not an exhaustive list):
will they be loaded upon initialization or during execution? Is a delay at the start of the application okay, or should it be a background or on-demand process?
what information will the framework need to send the plugins? Will commands dispatch a VI or send a commandthat the plugin handles?
what information will the plugins need to send to the framework? Should commands return an acknowledgement?
will messages need to be broadcast to all the plugins? If the number of plugins is potentially large, queues might not be an ideal communication mechanism. Consider user events.
how much functionality will be reused across plugins? Consider putting this functionality in a parent of a class hierarchy, allowing all children to easily make use of it.
how will plugins be installed and organized? Should they reside in a folder on disk, set a registry variable or be built into the exe?
should users be able to modify plugins? What deployment format should be used?
And perhaps most importantly, how do you define what goes into a plugin versus what is owned by the framework? The answers to all of these will obviously vary based upon your specific use case, but there are some common approaches that we will look at. For starters, plugins are almost always going to be loaded dynamically, be it at initialization or at the request of some operation during execution. In general, the act of loading a plugin is either done by bringing a VI or set of VIs into memory, or by loading a class. All of them make use of the Factory Design Pattern, making it one of the most important design patterns to familiarize yourself with.
LabVIEW Classes are an especially powerful way to create plugins. If the plugins all need to make use of some similar functionality, this can easily be encapsulated in the parent and reused by the various plugins. If plugins need to further customize or extend the default behavior, they can override the dynamic methods. Instead of dynamically loading a new VI for every dynamic method, the use of a class hierarchy means that the act of loading a new child brings all the associated methods into memory, which can then be dynamically dispatched. The image below shows the simplified UML for the UI Plugin Framework's plugin class hierarchy. Note that the 'Generic Plugin' class defines functionality that can then be reused by all of the children. All of the children override the 'Configure Plugin' method, but they selectively override the other methods, depending upon what they need to do.
I've uploaded several examples of a plugin framework to this community page for you to explore.
Basic Subpanel Options Dialog - this is a very simple illustration of how you can dynamically load VIs as plugins. In this case, the plugins are a VI which is displayed in the subpanel, much like the LabVIEW Options dialog.
LabVIEW Benchmarking Utility - this is a utility that allows users to create and add their own benchmarks for comparing LabVIEW and executables written in other languages. Each benchmark is a plugin.
User Interface Plugin Framework - this plugin framework shows how LabVIEW classes can be used to represent the individual plugins. This framwork uses Dynamic User Events to broadcast or unicast messages to registered listeners, eliminating the need for individual queues. It also makes use of an API that is defined by the parent class of the plugins, which is then reused by the various children.
Hardware Abstraction Layer - this simple example loads different plugins depending upon the configuration that is specified in an XML file. It abstracts the measurement tasks in avery simple test application to exemplify a hardware abstraction layer.
In the next entry, I'll discuss the use of User Events for sending messages to the plugins.
This continues to be a constant question from customers, so I just want to make sure everyone is aware that you can configure Subversion (or any source code control tool) to automatically call LabVIEW graphical differencing tool (only in LabVIEW Professional).
To setup, simply enter the following command line into the settings dialog of TortoiseSVN for a .vi file:
For more details on how to set this up and what the command line parameters mean, download this guide to software engineering. Once you've set this up, using it is a breeze, and you'll find you can't live without it. You can use it simply by right-cliking on a modified file, and selecting 'Diff' (or 'Diff with Previous')
And the result:
I'm always looking for feedback about this utility. What would you improve? What do you or don't you like about this feature? How often do you use it? Do you have any need or interest in the ability to export or save the results of this comparison? Thank you in advance for your comments!
Are you up to a LabVIEW code challenge? Think you canslam dunk with original LabVIEW code? Join us in the LabVIEW Code Madness: Example Program Challenge, and share the great example code that you are developing in LabVIEW.
Qualifying Round: February 14-March 6
The qualifying round is open to all NI Community Users. The selection of the top 16 to move on to the tournament will be based on total downloads, "likes", and a weighted sum of the ratings for the submissions. Comments and views will be the tie-breakers. You may submit more than one code, but keep in mind that each submission is judged separately. Additionally, tournament pool seeding is based on performance in the qualifying round. The earlier you submit code, the longer you have to generate a top performer.
Tournament: March 8-April 4
Each round in the tournament will present a new code challenge for competitors to undertake as they match up head-to-head. Polls will open for one day at the end of each round, and members of the NI Community will vote to determine which code from each head-to-head match will advance to the next round. The tournament will begin with the Sweet 16-bit (top 16 teams), progressing to the Elite 8-bit, Final 4-bit, and finally the Championship.
Error handling is one of the most difficult and unappreciated components of a complex application architecture. For many LabVIEW users, the normal error wire and error case structure are adequate, but it's not uncommon to run into scenarios that are difficult to handle with the default error handling in LabVIEW. It's for this very reason that a member of our systems engineering group put together the Specific Error Handler (SEH) Reference Library.
The 'Specific Error Handler' Express VI allows a user to configure actions based on specific errors. Perhaps most valuable of all is the fact that when an error occurs, it's handled by an independent, a-synchronous process. You can specify the level of criticality of errors and the appropriate course of action, be it ignore, retry, or run custom code. For anyone developing even a modestly complex application that is struggling to handle errors, I strongly recommend visiting the link above for more inforrmation on how to download and use this free API.
This is an image of the configuration dialog that allows users to specify actions for specific errors.
National Instruments is gathering information about how customers develop applications in LabVIEW and the processes and tools that they use for software engineering. Please consider taking 10 minutes of your time to complete this survey - your input helps us develop new training materials and guide future product development.
Many of you reading this are writing cutting-edge, innovative applications that are helping solve some of the most complex problems facing engineers and scientists today, so why not get some recognition for it? The call for 2011 Graphical System Design Achievement Award nominees was just announced, so it seemed natural to make sure those of you developing 'Large LabVIEW Applications' were aware and getting ready to submit your paper!
Object-oriented programming in LabVIEW (aka LVOOP) has become a very popular solution for complex applications that need elegant and scalable architectures. For those of you who are new to object-orientation, I would highly recommend the new NI Customer Education class, Object-Oriented Design and Programming in LabVIEW (which just became available in 2011). You might also check out an old blog entry I wrote to provide a very basic overview of how classes can be used, When Should You Use LabVIEW Classes?
For those of you who are either familiar with text-based design patterns, or who are familiar with LVOOP and interested in getting your hands on more sophisticated examples, I want to highlight and promote some new examples that have been posted to this Large Application community. Aristos Queue wrote an early draft of this document, Applying Common OO Design Patterns to LabVIEW, which has since been expanded on and added to with the help of individuals from the systems engineering group at NI. The design patterns in this book are largely adapted from the examples put together by The-Gang-of-Four in 1995, which wrote 'Design Patterns by Gamma, Helm, Johnson and Vlissides.'
As of 1/7/11 we have posted ten different examples that you can download and begin using. Each of the documents carefully explains when and when you'd want to use one of the patterns. If you're interested, please review the examples and let us know what you think and if you have any questions or ideas. I'd also like to put a challenge out the community to post alternative examples and even add new patterns from the original 1995 text.
Happy new year fellow wire-workers!
PS: We are also working on codifying examples of hardware abstraction layers (HALs) built on LabVIEW classes. More on that soon.
This is by no means an exhaustive list of things you should know, but it represents a short-list of things that are often overlooked, especially when people are using LabVIEW.
I also recently put together a list of mistakes I see made by many users, over and over again. These are all common examples that can lead to the duct-tape and hot-glue block diagram that we've all seen before.As engineers, we all appreciate the cost of cutting-corners or taking a short-cut… it may get us there sooner, but at what cost?In the world of software, there’s a concept known as ‘Software Engineering Debt.’If we cut corners, we take on more debt, and these are all examples of how we do that.The more debt we take on, the more interest we accumulate over time, and as we’ve all seen in the recent years, that debt can quickly pile up and accumulate a mountain of interest, making it more exponentially more expensive.If we wait to pay down that debt until after we release a version of the software to our customer, it’s going to painful and the bugs will be much more costly than if we’d caught them up front.
No source code control (or Project) – if you’re not using it, you’re playing with fire.Even for a small project with one developer, these tools can save you a tremendous amount of time and heartache.
Flat file hierarchy – ever had trouble identifying the top-level VI in an application?It’s not just an organizational problem, it indicates a lack of encapsulation and proper design.Use folders, encapsulate your code and make APIs obvious from private subVIs
‘Stop’ isn’t tested regularly – there are lots of ways to assess the health of an application, but this is an easy one that you should always be thinking about.A new feature is no good if it impedes expected behavior and one key indicator is whether or not the application still stops instantly when asked to
Wait until the ‘end’ of a project to build an application – if you’re one of those that waited until you were ‘done’ to build an exe for the first time, you’re probably a long ways away from done.The reality is that, as with any language, a lot of things change in the RTE, and you need to test this on a regular basis
Few specifications / documentation / requirements – this is perhaps the most common mistake and the easiest way to ensure that code is not reusable or maintainable
No ‘buddying’ or code reviews – sometimes the mere act of explaining your code to someone else finds major problems or bugs… do it, and do it often
Poor planning (Lack of consideration for SMoRES) – This acronym stands for ‘Scalable,’ ‘Modular,’ ‘Reusable,’ ‘Extensible,’ and ‘Simple.’
No test plans – you can’t test code if you don’t define how it should behave.
Poor error handling – does it stop? Does it tell the user an error? Does it log the error?If you don’t plan for this early, a simple error can lead to even more problems
No consistent style = not readible, not maintainable
Tight coupling, poor cohesion – impedes reuse
A lot of us are under pressure to get things done quickly and to hit aggressive deadlines, but there are a few practices that if we invest in early, will pay dividends down the road. If you go through this list and find that more than just a few of these apply to you, time to re-evaluate your development process!
It's been a few weeks since I had a chance to post a blog entry, but the good news is that I have a lot of new information and examples that I'm eager to share over the next few months. I've been on the road working with customers, which always helps give me a fresh perspective and new ideas. When I have been in Austin, I've been working on the new ni.com/largeapps, which I would encourage everyone to visit and provide feedback on.
I also want to encourage everyone to register for a presentation I'll be giving next week over the web, 'Software Engineering Best Practices with LabVIEW.' It will be held this Wednesday, November 10th at 11:00 am CDT. Bring your questions and I hope to see you all there!
For those of you using source code control (I hope that's everyone reading this), you may have run into this situation before: You make a simple, seemingly trivial change to one your VIs, and then LabVIEW starts asking you to re-save a dozen other VIs you didn't touch. Although this may befuddle you, it may go unnoticed for the majority of you reading this. However, if you have to justify, track or even validate any and all changes to your source code, this can be extremely frustrating. In addition to the fact that you have to check-in 'modified' VIs that you didn't touch, this may raise some red-flags in a regulated environment, especially if someone else insists on examining your changes.
So first off, why does this happen? Unlike other programming languages, the VI file format not only contains the source code, it also contains the compiled code (also referred to as object code). For the vast majority of LabVIEW users, this simplifies application management and avoids having to keep track of the compiled code separately. However, one simple change may cause LabVIEW to recompile other parts of your application - this can be attributed to optimization routines and the propagation of datatypes. When this happens, the new object code is saved into the respective VIs, which have then been modified by LabVIEW, even though the source code hasn't changed.
LabVIEW 2010 introduced a new capability to address this problem. You can now remove the object code from VIs and store them separately on disk. As a result, the only thing that can cause a change to a VI is the modification of source code, which is what anyone from a text-based background would expect.
The LabVIEW 2010 Help documents how to turn this on for a VI or even the contents of a Project file, but we've had several requests from users to enable this feature by default so that any and all new VIs are saved as 'source-only' VIs. Thankfully, this can be done using an ini token: SourceOnlyEnvironment=True. As with any 'secret' ini token, it's not supported and it's considered experimental. One side affect to be wary of is that you cannot create a normal 'uni-file' with this setting enabled (the VI Property setting is ignored), which is required for dynamically loaded VIs.
Many people have asked why this isn't just on by default in 2010. The original plan was that it would be on by default, but benchmarks showed that the operation required to check the cache of object files 'mod date' slowed down load time to the point that we were not comfortable turning it on for everyone. We also weighed the ramifications for people who were calling VIs directly from a built executables (not a recommended practice, by the way). Because the RTE does not have a compiler, the executable would not be able to create the object files for source-only VIs and would not be able to run source-only VIs. As a result, you either have to build VIs into something that includes the object files, or include them with the executable when it's built. If this affects you, consider packaging your VIs as packed project libraries (new in 2010), DLLs, separate executables or including them in the main executable. Before you protest, consider the fact that you would never call a .C file directly from an EXE.
Anyway, R&D has been hard at work looking for ways to address the problems we saw with load time and they've come across some very promising solutions using databases. Without making any guarantees, I strongly encourage everyone to assume that this feature will be the only available option for future versions of LabVIEW. The bottom line, is that if you have applications you'll know you'll be upgrading to 2011 and beyond, turn this setting on sooner, rather than later.