This document outlines some general principles to follow when designing effective, usable APIs. Then it describes the intended audiences of Songbird's Web Page and Extension APIs, and specific patterns to follow while extending those APIs so that they are consistent with the environments that they will be used in.
Generally, APIs must be aesthetic and appropriate.
getWidth method there should probably be setWidth, getHeight and setHeight methods.
var toast = kitchen.toaster.cook(new Bread());var toaster = kitchenManager.getAppliance(Appliance::TOASTER);var toast = toaster.cook(breadFactory.createSlice());Songbird's Web Page API is exposed to scripts running in web pages loaded into the browser pane. It extends the W3C DOM interfaces that are already available to web page scripts. It should look and feel similar to modern DOM interfaces like WHATWG HTML5.
We should resist the temptation to make our API look like the APIs provided by JavaScript libraries. Each developer or project will have their own preferred library. If we use similar patterns to the DOM then any existing libraries will work on top of the Web Page API.
We should consider exposing some simple, common functionality through declaratively through semantic HTML or microformats.
Both advanced and intermediate web developers will use the Web Page API. Advanced web developers will be familiar with writing their own JavaScript, manipulating the DOM and making Ajax calls either by calling DOM APIs directly or through one or more JavaScript library.
Intermediate web developers will be comfortable building web pages with HTML and copying JavaScript patterns they find on instructional web sites for simple interactions such as animation or form validation.
Lists of items are called either Collections or Lists.
For historical reasons no term is preferred, but we should stick to one.
They have a read only number attribute named length that returns the list's length.
NodeList and
HTMLOptionsCollection
Lists can be indexed like an array or accessed via a method named item.
list[4] and list.item(4) both return the fourth item.
addFoo,
appendFoo, and removeFoo.
Methods to get retrieve a subset of a list look like
getFooFromBar for a single item or
getFoosFromBar for multiple items.
Document
has document.getElementById('foo') which returns the one element
in the document with id="foo" while
document.getElementByTagName('div') will return all the
<div> elements in the document.
Type names LookLikeThis.
Constants are integer constants on interfaces and
LOOK_LIKE_THIS.
Method and attribute names lookLikeThis.
Node's
name is capitalized, it has methods named
insertBefore(newChild, refChild) and hasChildNode(),
attributes named prefix and localName,
and constants named ELEMENT_NODE and ATTRIBUTE_NODE.
Object creation is often done through methods that look like
createFoo().
Document
provides methods to create different kinds of DOM node, for example
document.createElement('img'),
document.createAttribute('src'),
document.createTextNode('Hello, world').
Changes to object properties and method calls should be reflected visually immediately.
Getters and setters should be used when possible, but there's a
pattern of getFoo / setFoo.
img.getAttribute('src') and
img.setAttribute('src', 'http://www.songbirdnest.com/favicon.ico').
State change notification should take place through the
DOM Events
system. To be notified of state changes scripts should call
addEventListener, to stop receiving notifications they
should call removeEventListener.
Event handlers may be objects which implement the W3C DOM
EventHandler interface or be a functions that accepts a
single Event argument.
The context of the event that was triggered is available as
properties of the event object.
The event target is the object whose state changed.
Songbird's Extension API builds on Mozilla's platform, especially its XPCOM interfaces. It is exposed to C++ and JavaScript through its IDL interfaces. We should consider building a FUEL-like library for JavaScript extension developers.
The Extension API will be used by Firefox extension developers and desktop application developers.
Firefox developers will have experience with XUL, JS and CSS and experience using some common Mozilla XPCOM interfaces (eg: nsITimer, nsIObserverService, nsIWebProgressListener).
There is a wide range of skills and experience among Firefox extension developers, but whatever their skill level they should be able to apply that to Songbird.
For example, if they know how to add toolbar buttons to Firefox it should be easy for them to add shuttle control buttons to Songbird, if they know how to write new protocol handlers for Firefox they should be able to add new media handlers to Songbird.
Desktop application developers will have experience with several desktop application frameworks (for example MFC, Cocoa, Gtk+, Swing, etc). They will learn the base platform knowledge from Mozilla's platform documentation.
Functionality is exposed through XPCOM interfaces.
They are named according to the pattern namespaceIMyComponentName
(ie: a Songbird interface would be named like sbIFooBar).
They are defined using the XPIDL variant of IDL.
IDL supports single inheritance which should be used when appropriate.
Mozilla has an IDL style guide that should be followed.
Methods and attributes should be named in camelCase.
Attributes should be used rather than methods to get and set the properties of objects.
Constants should be const unsigned integers named in ALL_CAPS_WITH_UNDERSCORES.
Constants that are flags are often implemented as bit masks.
Objects which expose XPCOM interfaces are called components.
Singleton components are called Services or Managers.
Components are activated by contract ID in the form @domain.com/subsystem/component-name;1
Application-wide event and state change notification happens via the nsIObserverService.
Callbacks come to objects which implement the nsIObserver interface method observe.
observe takes three arguments:
aSubject &emdash; the object being observed,
aTopic &emdash; what changed about the object and
aData &emdash; information about the change.
State and and event change notification on individual components is done through callback objects called either Observers or Listeners.
Observers and Listeners are associated with and dissociated from components using the addObserver or addListener and the removeObserver or removeListener methods.
Callbacks to methods are usually called Listeners and are passed as the last argument.
Methods in Listener and Observer interfaces typically take the form onFoo
and take the object that the method is being called for as the first argument.
Errors are returned via the nserror mechanism &emdash; returned from C++ methods and thrown by JavaScript methods.
Sequences should be returned as nsISimpleEnumerator when the items are XPCOM objects or as nsIStringEnumerator when the items are strings.
Another option is nsIArray, but that is less commonly used.
Extensibility can be achieved through the category manager. Classes of component can be registered with the category manager at startup and instantiated as required.
The convention is to make the value of the category manager entry the component's contract ID.
Another solution is to have predictable contract Ids with query strings.
Eg: @mozilla.org/rdf/datasource;1?name=bookmarks