Last Monday, Labrigger covered HelioScan, a LabVIEW-based, two-photon laser scanning microscopy software suite.
Marcel van ‘t Hoff (left) and Dominik Langer (right) are the two main developers of HelioScan. They were kind enough to answer some interview questions for Labrigger.
LR: Are there special considerations you had to make when designing HelioScan? What measures did you take in LabVIEW to support the level of modularity?
The main design considerations were to design for future flexibility and for multiple developers to easily collaborate without interfering. The idea was then to assemble the software at run-time from components that are dynamically loaded based on configuration settings. LabVIEW classes are the ideal candidates for such components:
First, they naturally bundle data and corresponding VIs into separate entities.
Second, LabVIEW allows to load and instance classes at run-time based on the class file path (which can be specified in a configuration file).
Third, using class inheritance and polymorphy, we can substitute any two components, as long as interacting other classes refer to them in terms of the same abstract base class. For example, a particular ScanHead component can handle any incoming Trajectory component as long it is a subclass of a particular expected abstract base class.
Fourth, by means of aggregation combined with the above principles, we can build up highly complex objects at run time.
An example: HelioScan may read from its main configuration file to load a particular ImagingMode. During its initialization, the loaded ImagingMode object reads its own configuration file, stating that – among other components – a particular ScanHead component is to be loaded. Once loaded, the ScanHead object reads a configuration guiding it to load a bunch of Scanner components of a particular type, etc.
A couple of others have implemented individual components, demonstrating that the distributed multideveloper scenario is working.
LR: In the near future, say 5 years, who will be maintaining the core HelioScan codebase and leading new developments?
We are currently in a transition phase. First, both Marcel and I just left Fritjof Helmchen’s lab. While Marcel is going to continue as a postdoc in the field and will still use HelioScan, I will leave the academic field. Second, we are currently working on a major new version of HelioScan that we expect to bring about another quantum leap in flexibility. The new version will be based on a framework for distributed cross-platform signal processing (Murmex) that we are developing. We have been developing this framework in our free time and plan to continue doing so. Murmex as the new core will allow HelioScan components to be written not only in LabVIEW, but various other well-known programming languages. We believe that this will lower the entry barrier for new developers enough for HelioScan to become a project that can be handed over to the community. New components will be collected on a central repository, given that they meet some basic quality standards. This will be similar to certain ImageJ distributions, such as FIJI.
LR: Do you have design principles that you follow to ensure that your LabVIEW programs don’t become spaghetti?
First, we try to stick as far as possible the style rules from “The LabVIEW Style Book” (Peter A. Blume, Prentice Hall) [Also covered here. -Labrigger]. That’s also the book we usually recommend to newcomers before they start to develop their own components.
Second, HelioScan is implemented using LabVIEW object-oriented programming (LVOOP), which naturally already structures the code by bundling related data and functionality into LabVIEW classes.
Third, we made very good experiences with the so-called XControls of LabVIEW. XControls are your own, re-usable user interface controls, which can provide arbitrarily complex functionality. For example, we made an XControl that allows to load and display multi-page TIFF files, where the user can scroll through the frames, draw different types of ROIs, load and save ROI seletions, and display file meta-information. On the VI block diagram, this whole functionality is represented by a single terminal, hiding all the underlying complexity from the developer.
Fourth, we heavily use a couple of design patterns to do certain things.
Fifth, the HelioScan framework enforces a lot of structure. When we develop a new component, we subclass an abstract class of the framework and override some of its methods. For example, when we need a new scan pattern for galvanometric mirrors, we subclass a generic Trajectory class. We override (among others) the initialise method of the class and put the code initialising the pattern exactly there (and nowhere else).