Times are crazy right now. While I’d love to make a GUI really shine or build a clever implementation of a communication protocol or error handler, I need to focus on the big things at work right now: architecture and algorithms – and delegate a lot of things to novice programmers. Even if it means code riddled with sequences, global variables and much more WTFs than I’d like to. (Look at this comic about code quality!)
So in the midst of a really stressful time at work, I’ve set up a meeting and will try to teach my coworkers how to write good LabVIEW programs. (Not sure what the boss is thinking about this, but we’re not getting paid for overtime anyway..)
None of them are coders, the target audience is from absolute beginner (intern, has read 10 chapters of my LabVIEW book last week) to some engineers (who have some exposure, but never thought about code quality) to someone very, very familiar with C and dialects. (Well, we’re good with SVN and trac. That helps. 😉 I’d love to use LabVIEW with git, but we can’t have everything..)
Architecture / Patterns
I’m going to talk about state machines. If there’s anything I want a LabVIEW programmer to know, it’s state machines.
Producer consumer pattern.
Second most important piece of architectural knowledge, standard case for image processing. Might be a good place to talk about parallelization, too.
Event structures/ loops. Because I hate those “Write to local vars of buttons”-constructs so much.
Queued state machines.
(My favorite pattern, btw – and what we’re going to use for this project. A bit complicated for their level, but we’ll deal with it.)
I’ll talk about code smells in LV. Code smells are signs that you have a quality problem in your code, like huge, messy piles of spaghetti code, sequences that violate data flow, or clusters that replace decent data structures and stuff that nobody understands. Duplicate code. Lack of comments. Useless, verbose comments (“Increase i by one”). Non-descriptive, non-trivial UI parts. Memory leaks. Weird dependency warnings. doSomething1.vi and doSomething2.vi. Inconsistent naming conventions. Extremely deep nesting…
Don’t use local variables to get rid of wires too often. Use shift registers. Use good clusters. Don’t violate data flow.
1 abstraction level per subvi layer It’s not a law, and I absolutely don’t want you to make unnecessary communication layers and subvis that just pass things to a lower level (Most software engineers will have their architecture astronaut phase, though..),.. Decouple things. Make separate builds for separate parts of your software. Keep subvis for different parts in separate folders.
Use State Machines. Nest state machines: If you have more than 15 states in your state machine, you’re doing it wrong. I know, state machines are an awesome concept. You can hide a lot of things in case-structures, and that’s almost like building a program with a lot of sequences.. In fact, a state machine where most of the states have just one “next” state is nothing but a sequence with a label. Think about it.
(But don’t nest too many things!)
Write APIs/Drivers. If you are connecting to hardware or something outside NI universe, write yourself an abstraction layer that hides all the ugly dll calls. Hide them in a lvlib. You’ll thank me when the next project needs the same thing. TDD and agile followers often tell you not to “pre-build” stuff you’re not gonna need anyway, but they don’t know about LabVIEW.
Look, for example, at a part of my collection of code snippets, notes and bridges. This is how I get stuff done.
Start to build your own libraries. (Which is pretty much the same thing as the above). So you figured out how to create awesome pdfs? So you wrote your own implementation of the ftp protocol that can deal with the stupid things your vendor came up with? So you have your own error handler, tracer, profiler? Something that does memory handling for imaq pics? Some custom config files concept? A localization concept?
I’m not a fan of huge frameworks, but there’s something about just opening your folders and just pulling out a solution for a partial problem. Or opening up your custom palette.
Document, smartly. Use the help LabVIEW gives you. Label wires. Give subvis icons (I usually just use a rectangle with one color per part – image processing is always orange, helper functions are white, low-level dll calls and other hidden things are grey, motion parts are blue… And then I add some text. Always english, always black and unchanged font.)
Insert pictures to explain what you are doing. (Concept sketches, UML diagrams!)
Profile your code.
Think about error handling. Use daisy chains as much as you can, but be aware of the consequences for data flow/ ”easy” parallelization. Create your own error codes. (I found this feature just this year, and I like it a lot.) Always use the same connector pattern (I like the one in the picture!) for your subvis and put error in/out where they belong. (Lowest left/right).
Oh, and as a final tip (it’s not a style tip, but you’ll love it –) use Quickdrop. Quickdrop is the single most powerful and underused part of LV coding. I type Ctrl+Blank and “+” to get an add. Ctrl+Blank and “fr” to get my custom “read line n of a textfile”. Ctrl+Blank+”rgb” to open an RGB image, complete with type and created reference. People are usually quite impressed by that 😉
Well, now I’m off to put this into some sort of powerpoint. 🙂
Jeez, there’s so much I haven’t even started to talk about. All those parallization tricks and fallacies. Timing issues / Not polling at 100%CPU. Asserting hardware status at every step. How to use events – and how dangerous – and elegant – they can be. The beautiful- and the ugly uses of variants. Documentation, documentation, documentation. References, and when close them. Performance issues with some kinds of data types. Performance comparisons of simple constructs. Inplace operations and buffer allocations. Regular expressions. Absolute and relative paths … Some things so trivial, some so complex.. So much to do, so much to learn, so much to teach..