Global Sources
EE Times-Asia
Stay in touch with EE Times Asia
EE Times-Asia > Embedded

Learn about APIdeology: Best practices in API devt

Posted: 23 Sep 2011 ?? ?Print Version ?Bookmark and Share

Keywords:application programming interfaces? APIdeology?

A software's most important feature is the public interface of a software component. An example of that is an element such as a header file that's readily visible to the developer. Best practices in the development and maintenance of application programming interfaces (APIs), or what we might cleverly call "APIdeology," dictate that software interfaces do not change once they have been released, with the exception of adding new entry points. Therefore, it is important to design concise, extensible software interfaces that can be adapted to survive in an evolving hardware/software ecosystem.

APIs tend to follow several general patterns. For designers seeking to choose an appropriate API pattern, it's helpful to understand the ways in which the choice of pattern, or style, drives the implementation of the software component and the usage model it forces on its clients.

Consider, for example, an API for setting color values for a liquid crystal display (LCD) library. For simplicity, let's ignore details such as whether the LCD controller is integrated into the MCU or attached via some external bus, as well as power supply and timing considerations. In this idealized scenario, there is a means of plotting a pixel at some coordinate, and any pixel so plotted appears on the display in the "current drawing color." That color is specified by four values: red, green, blue and alpha.

The following formula represents one way to define an API to specify the drawing color:

typedef enum { RED, GREEN, BLUE, ALPHA, RGBA_V, RGB_V } keyword;

bool setFloatValue(keyword key, float value);

Depending on the intended application, there may be several ways to specify a color. Sometimes floating point values may be appropriate, while at other times scaled integer or short values may be desirable.

bool setIntValue(keyword key, int value);

Sometimes it makes sense to pass all of the color values independently, as above. But sometimes it is more appropriate to pass a vector (i.e., a one-dimensional array) of values.

bool setFloatVector(keyword key, float* value);

bool setIntVector(keyword key, float* value);

The number of items contained in a vector parameter is implicit in the keyword. For example, RGB_V expects 3 elements, while RGBA_V expects 4.

Although this API has only a small number of functions, it can be used for more than just setting the values of color components. This API can actually be used to set the values of anything for which a keyword has been defined.

This style is flexible and potentially usable in a wide variety of situations. But that flexibility comes with some complexity. The interface influences the implementation, encouraging each function to employ a switch on the keyword parameter, providing a case for each keyword. More keywords imply more cases in the switch, and thus larger functions. Furthermore, it is possible that an unrecognized keyword may be passed to a function. Even though the "keyword" type has an enumerated ("enum") type definition, most compilers treat enums as signed integers and will not issue a warning if some other compatible value is passed.

This situation implies a need to return some "invalid keyword" error indicator to the caller. Depending on the complexity of an API, the number and type of error that needs to be reported can vary. In this particular case, a simple Boolean indicating success, or failure due to an invalid keyword, is sufficient.

In addition to influencing the implementation, this API design choice imposes a constraint onto the caller as well. The client code calling these functions is obligated to check the returned result to ensure that no inadvertent error has occurred.

There are, of course, alternative API styles that can perform the same task but with different tradeoffs. For example:

void setColor4f(float r, float g, float b, float a);

void setColor3f(float r, float g, float b);

void setColor4i(int r, int g, int b, int a);

void setColor3i(int r, int g, int b);

void setColor4fv(float* v);

void setColor3fv(float* v);

void setColor4iv(int* v);

void setColor3iv(int* v);

This API can accomplish the same effect as the previous API, but it goes about it in a different manner. Previously the function name specified only the type of value, relying on a keyword parameter to indicate exactly which value is affected.

Like the previous example, this second API provides parameter type checking at compile time and provides flexibility to the caller by allowing parameters to be passed individually or as vectors. Its function names are somewhat more meaningful, though, conveying not only the purpose of the function, but also the number and type of arguments expected.

The implementation of each function can be small, simple and efficient. The number and type of each argument is fixed by the API, and thus there is no need for parameter validation and no need to return any sort of error code. The functions of this API cannot fail.

But the API does require a number of very similar functions for each allowed parameter type and parameter passing style. The functions that accept vector parameters have to assume that the pointer they receive is indeed a pointer to the correct number of elements of the appropriate type.

1???2?Next Page?Last Page

Article Comments - Learn about APIdeology: Best practic...
*? You can enter [0] more charecters.
*Verify code:


Visit Asia Webinars to learn about the latest in technology and get practical design tips.

Back to Top