Ephus heavily employs two developmental paradigms. Specifically, it is heavily object oriented (Booch et al., 1994) and event-based (Yourdon and Constantine, 1979). It is object-oriented in the sense that the programs themselves, as well as the subcomponents (i.e., data acquisition, event distribution, device interfaces, etc.), are all implemented as classes/objects. The classes encapsulate related data and functionality and designate a specific, associated lifecycle for each object instance. This results in cleaner and more modular code than would be achieved with traditional functional programming. Since the mid-1990s, object-oriented programming has been standard in the design of most commercial software. Object-oriented design has not become quite as common in the Matlab environment as in many other environments. Matlab has a number of object-orientation schemes that have grown over the years. For this reason, Ephus is written using the earliest supported style of Matlab classes (which is all that was publicly available at the start of the Ephus project), often implementing its own pass-by-reference semantic scheme. Pass-by-reference is an important concept, which allows one instance of a particular object to be accessible from multiple, loosely coupled locations in the code, which in turn allows all such locations to see the same state for a given object. This becomes important when implementing event-based programming, where it is unclear, prior to runtime, which code will be accessing specific objects at any given time.
Matlab is a single-threaded environment. This means that the simple act of entering into a loop would prevent Matlab from performing other tasks, including processing any other input. To get around this limitation, critical sections of the Ephus architecture rely on the propogation of events. Objects interested in a specific event (typically an input event or a state change) must register with the appropriate agent, and when the event occurs, all registered listeners are notified. An event may be generated by a hardware subsystem (i.e., via NiMex), user input, or other source. With an event-based design, when a section of code needs a change in the program state (i.e., waiting for an external trigger, waiting for a loop iteration event, waiting for user input) in order to proceed, it does not tie up the Matlab interpreter, as it would if it used a polling loop (i.e., `while <state_not_set>`). The act of waiting for an event does not require constant computation, and subsequently leaves the Matlab interpreter free to carry out other actions.
The programmable user functions available throughout Ephus are one of the most obvious examples of the event-based system design. In the case of user functions, the event and registration mechanism is exposed all the way up to the user level. However, this design goes deep into the software, all the way to the hardware interfaces (including down into the underlying C code).
A number of industry-standard design patterns (Gamma et al., 1995) and best practices are employed throughout the implementation of Ephus. The code is rigorously documented on a per-function basis, with descriptions of all arguments, usage, and caveats. The system was designed from the very beginning with the capability for it to be modified, particularly by end-users, in mind. Various levels or programming proficiency are acceptable for customizing Ephus, because it has its own levels of complexity designed into it. At the highest level (simplest from a programmer's perspective), a user may write a new user function or modify an existing one. Moving to a lower level, users may write code to generate their own pulses and pulseJacker cycles. Lower still, users may write their own objects (i.e., write a new amplifier class for Ephys to interface with new hardware). At an even lower level, users may create entirely new programs to add fundamentally new functionality to the system. Finally, users may modify the overall architecture and the C code (in NiMex). In practice, a large number of experiments may be automated simply by writing user functions and making pulseJacker cycles, it is rarely necessary to touch any of the lower level code. Example functions are supplied with Ephus that demonstrate how to write user functions and how to create pulseJacker cycles in an automated fashion. These functions are heavily documented and are intended as tutorials and templates for users.
References
Grady Booch, Robert Maksimchuk, Michael Engle, Bobbi Young, Jim Conallen, Kelli Houston. Object-Oriented Analysis and Design with Applications. Menlo Park: Benjamin/Cummings Pub. Co, 1994.
Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software
Gamma, Erich. Design Patterns. Boston: Addison-Wesley, 1995.
Edward Yourdon and Larry L. Constantine. Structured Design: Fundamentals of a Discipline of Computer Program and System Design
Prentice-Hall, 1979.