User:Jacek Antonelli/Plugin System/API Design Principles

Just as with any other creative process, there are principles for designing a good API.

Abstraction
It's important that any API we design be highly abstracted. That is, the API should reflect the core concepts of the system, not the details of any specific implementation. The reasons for this are simple:


 * 1) Implementations change, but interfaces should not. If the interface is too closely tied to the implementation, than you can't (easily) change the one without changing the other.
 * 2) An API which is not tied to a specific implementation is a good candidate to become a standard across multiple implementations. That means that a plugin written for Imprudence could work on another viewer with a different implementation, as long as they both support the same abstracted API.

Example: HTML
An example of this is HTML. The same web page can be viewed on many different browsers, even though their implementations may be radically different. The reason this is possible is that HTML provides an abstract language for expressing documents, which is abstracted from any specific implementation. A web browser could have a separate class for bold text as it does for regular text, or it may not, and it doesn't make a difference to the HTML. (Of course, some web browsers do not comply with the language standards, so they display some pages incorrectly, but this is the fault of the browser, not of HTML.)

Selectivity
Hand in hand with abstraction is being selective (picky) about which pieces of functionality are exposed via API. Not every detail of every part of a complex system can or should be offered via API. The reasons for being selective are:


 * 1) It decreases workload on the API designer and implementer, since there are fewer API components to create.
 * 2) It reduces bloat in the API and code by keeping out unnecessary API components.
 * 3) It promotes cleanliness and elegance by limiting the API to a smaller number of more important components.
 * 4) It promotes abstraction, since the opportunity and urge to expose internal details is reduced.
 * 5) It makes the API easier to learn, remember, and use, since the API components are fewer in number and more significant.

Specification Levels
In designing an API, we have to ask, "What are the properties and actions of the thing this part of the API is describing?", not, "What variables and methods does this class have in the C++ code?".

There are several levels of specification for properties (and methods) in a robust and portable API:

Core Properties
For example, the UI widget for a menu fundamentally has a text label and a list of children. If you removed either of those things, it wouldn't be a menu. Also, like all UI widgets, it can be active or inactive, visible or invisible. These are common properties of all UI widgets, regardless of implementation details.

A plugin should be able to rely on every implementation supporting all core properties. Therefore, the core properties and their meanings should be specified in the API, and every implementations should be required to provide them in order to be considered API-compliant.

Optional Properties
In addition to core properties, there are optional properties. These are distinguished by the fact that the object can reasonably be expected to function without. For example, style properties like color or font family are not necessary for a menu to function, so those properties are optional.

Like core properties, optional properties and their meanings should be specified in the API. Unlike core properties, an implementation is not required to support all or any of the optional properties in order to be considered API-compliant. However, an implementation must not break if it receives an unsupported optional property, and it also must not break if it doesn't receive an optional property that it expected.

Extra Properties
It's inevitable that there will be unanticipated properties which are meant for use on only one or a few implementations, due to the unique set of features offered by those implementations. These properties are termed extra properties, because they are not part of the API (they are extra).

An extra property may not override a property of the same name in the same context (i.e. an implementation can't give a special new meaning to an API-defined property.)

The requirements of extra properties are similar to optional properties, including the requirement of gracefully handling both unexpected properties and expected-but-not-received properties.

Required vs Optional Arguments
Request "arguments" should only be required when they are actually required, i.e. when it's not possible to perform the operation without them.

Wherever possible, arguments that are not required for the operation should be allowed to be omitted. For example, if the user is changing a prim's texture properties, and they only want to change the color, they should not be required to also provide a texture UUID.

If a required argument is missing, the viewer should respond with a descriptive error explaining which required argument(s) were missing.

If an optional argument is omitted, the viewer should either use the default value (as defined in the API), or have no effect on the omitted part (as in the texture example above). The proper behavior for each request should be defined as part of the API.