To maximize the ability of other designers and developers to understand, debug,
and reuse your code, consider the following guidelines.
Modularity
-
Each control should have a clear task or responsibility that can be succinctly
stated. State this purpose in a comment at the top of the control's source file.
-
Design controls to be as context-independent as possible. The control should
make as few assumptions as possible about its container's class, styles, etc.
-
As an analogue of the
Law of Demeter,
a control should directly manipulate only the elements which it, itself,
has added to the DOM in the class’ content or prototype,
or in its own member functions.
-
As a corollary to the above point, a control should expose information to
outside consumers via property setters and other methods, rather than expecting
them to directly grovel the control’s own DOM.
-
The script tag for a control should generally define the control class’ prototype
and (if applicable) class-level methods. Avoid other side-effects.
Subclassing
Properties
-
Avoid requiring that a control must have properties set on it, and provide
useful default values for all properties. It should be possible to
instantiate a control class with a standalone tag. E.g., a control class called
Foo should be instantiable with an unadorned call to Foo.create(). If possible,
the resulting control should ideally provide some minimal functionality or
behavior.
-
As a general rule, values which are set on a control via a setter should be
retrievable by calling the same function as a getter. Avoid write-only functions
that permanently change control state without affording access to that state.
-
It should be possible to set properties in any order. If a control has two
properties that work in tandem, have the side-effect function for each invoke
a “private” function that checks to see if both are set before doing its work.
-
If someone will be likely to want to set a property through markup, support the ability to set a property as a string. Use the specific property constructors like Control.property.bool().
-
If you want to set complex defaults in initialize(), remember that the initialize() call happens after per-instance properties have been set. The initialize handler should generally only set a property to its default value if the property hasn’t already been set.
Coding style and naming conventions
Styling
-
General-purpose base classes should avoid imposing an arbitrary visual style
on all subclasses. Base classes can define styles that are likely to be
desired by all subclasses, but stylistic decisions should as color, font, etc.
should usually be left up to subclasses.
-
Base classes can provide a bare-bones UI (so that, e.g., control elements
are visible and legible) by application of a generic CSS class. This
class will automatically be applied if the class prototype's
genericSupport member is true.
-
When necessary, a control subclass can define style rules that adjust the appearance of
elements added by its parent classes. I.e., those elements are treated as
protected members of the class.
-
It is not advisable to directly style the subelements of contained controls.
If necessary, create a subclass of the control in question, then override the
parent class style in that (per the above point). This at least makes apparent
the fact that the normal parent class styling is being overruled.