5 Tips for designing interfaces to reusable software modules
Creating consistent and proper interfaces for reusable software modules is one of the most critical and overlooked aspects of embedded software design. Interfaces are usually developed on the fly with little to no forethought. But in order to ensure that software can easily be used from one application to the next, there are five tips that every developer should keep in mind.
Tip #1 – Start with a list of required operations Before ever beginning to write an interface for a software module, a developer should take a few moments to write out a simple list of operations that the interface needs to perform. The list acts as a scratch pad for a developer to think through what exactly the interface needs to be doing. What are the module's operations? What are the inputs it needs? What are the outputs it will produce? All three of these questions need to be answered. The list and the questions will serve as the starting point for designing the interface.
Tip #2 – Use a UML Class Diagram
A UML class diagram is used to represent a class but it can also be used to represent a module and, more importantly, the module interface. The basic component of a class diagram is a box consisting of three sections. The first section (the top) contains the module's name. The second section (the middle) contains the module's attributes. The third and final section is used to define the operations and methods that the interface publicly exposes.
The module's attributes can be thought of as both the private and public variables that the operation of the interface will manipulate. A plus sign in front of the attribute indicates that it is public and exposed directly as part of the interface. A minus sign indicates that the attribute is private and only manipulated behind the scenes through the use of operations that the interface exposes. Think of these operations as the same ones that were listed as part of Tip #1. Figure 1 shows an example of a generic module definition on the left and a streamlined interface for an EEPROM module.
Figure 1 – Example Class / Module Diagram
Tip #3 – Separate the interface from the implementation
When beginning to develop an interface to a module, a developer should do everything that they can to separate the interface from the module's implementation. The details of the interface's public facing portions should all be contained in the header file, which in this case defines the module's interface. The implementation details should be kept in the source file. Keeping the details of implementation separate from the interface begins to provide a developer with the ability to hide the implementation. This hiding results in an abstraction of the module's class and provides the capability to later redefine the implementation without affecting the interface.
Tip #4 – Use abstract data types
Requirements always change and anticipating how requirements are going to change is usually a futile activity, even if one is equipped with a crystal ball. Abstract data types are meant to help developers deal with changing requirements. Take for example a data structure defined as part of the interface, in the header file. Any module that references the header file has the ability to create and modify data based on that data structure. When requirements change and that data structure is changed, the result is a need to provide updates to any file that used the header file.
Had the developer instead created an abstract data type, one in which the details of the data structure were hidden in the implementation, only the source file implementation would need to be updated. Any modules that used the header file would simply continue to use the public interface and the underlying implementation would deal with the changed data type.
Tip #5 – Encapsulate the data
One of the first concepts taught in computer science courses is that a variable or object should be limited to the smallest program scope possible. Similarly, details of how an interface is implemented should be limited to a need-to-know basis. Developers should attempt to hide as much data and implementation as possible from the module's users. Hiding the details can help prevent users from directly manipulating a module's internal data, which could then cause the module to enter into an unknown or inconsistent state.
Development is fraught with changing requirements and short development cycles. Using proper interface design techniques can improve software's overall design and minimize the impact of the ever- elusive moving target of requirements. We’ve examined five simple tips for designing an interface. What other considerations should developers keep in mind when developing an interface that will stand the test of time?
Jacob Beningo is a Certified Software Development Professional (CSDP) whose expertise is in embedded software. He works with companies to decrease costs and time to market while maintaining a quality and robust product. Feel free to contact him at email@example.com, at his website www.beningo.com, and sign-up for his monthly Embedded Bytes Newsletter here.