Login | Register
My pages Projects Community openCollabNet

TreeLogic Software Engineering

Coding Standard: Web Languages



January 14, 2005

01/21/06


Christopher M. Balz




1 Markup and Style Code


1.1 HTML

Validity: All html must conform to the xhtml 1.0 Strict or Frameset standard, and must validate at w3c.org:

http://validator.w3.org/


Files: To maintain a clean separation between static document structure elements and interactive gui elements, most or all dynamic html should only be written dynamically, and should not be present in static html files.

Whitespace: See the section on whitespace in JavaScript, below.



1.2 CSS

Validity: All css must conform to the css-2 standard, and must validate at w3c.org. Do not check-in any css files before validating them at:

http://jigsaw.w3.org/css-validator/validator-upload.html


Files: Css files, except ‘skin.css’, must correspond to major application gui elements. For example, there should be separate files for user controls/viewport, image-layers, and plate. Only the necessary css properties should be defined.


The ‘skin.css’ file defines all surface-related properties, such as border-style, image background, etcetera, for all major screen elements. The css code in the individual css files extends the css classes defined in ‘skin.css’. No skin-related css should be present in the other individual css files.


Whitespace: See the section on whitespace in JavaScript, below.



1.2.1.1 Inline CSS

Inline css is css in an html file, or mixed in with a literal html element tag definition (for example, in a dynamic ‘write’ operation to the html document, coded in a JavaScript file).


There will be no inline css.



1.31.3 XML

Validity: All xml and operations on xml documents will conform to the xml 1.0 standard, by the w3c.


Files: Non-xhtml xml will be used in this application in document object model form with the ‘XmlHttpRequest’ object. No xml files are expected.




2 Executable Code

2.1 JavaScript


JavaScript v1.5 will be the only kind of executable code used on the client.


2.1.1 Introduction

JavaScript offers many avenues to accomplish almost any given task. When in doubt, follow Java’s model as closely as possible instead of other alternatives. When JavaScript offers a significant, unique tool – such as ‘eval’ – use it to advantage.


JavaScript is used in conjunction with the Document Object Model (DOM), as defined by the w3c. DOM is the bridge from executable code to markup code.



2.1.2 Inheritance


Inheritance is implemented using the built-in mechanism for inheritance in JavaScript. These two types of statements should be implemented in the extending class file:


Directly before the constructor declaration, in the global scope of the file containing the extending class:


// Set the prototype chain for efficient inheritance:

Console.prototype = new AbstractWidget();


And then in the constructor of the extending class, as the first call (as in Java):


// Complete the inheritance.

this.superC("console", objParent);


Never put any assignments of values of type ‘object’ (including the ‘null’ value) in the abstract class constructor definition unless you specifically intend the assigned value to be common (truly shared) by all objects made from classes your abstract class.


Put all any assignments of values of type ‘object’ (hashes, arrays, other objects) in the method referenced by ‘this.superC’, above.


Do put all primitive-value assignments in the abstract class constructor definition (strings, function (“method”) bindings, numbers, booleans). This is important for performance.



2.1.3 DOM Operations

All DOM operations must conform to the specification of DOM-Level 3, by the w3c. The shortcut ‘innerHTML’, which has been cross-browser for five years, is acceptable.



2.1.4 Events

All synthetic and DOM events must be passed through the event architecture only. For example:


self.gloScope.registerEvent("console",

this, this.strWindowId, "onresize");


See section 2.1.6, “Inline JavaScript”, for example code showing how to make the DOM/Html elements send events into the event architecture.


When taking events directly from html attribute event handlers (i.e., onclick='doSomething()'), use a static global event registry in order to avoid a circular document-object-model-to-custom-JavaScript reference situation. (Some browsers may present listener-attaching methods that exhibit the same circular reference forming problem).


Note that the event architecture requires that the event or events be received by the listening object in a method named ‘receiveEvent’. This makes all asynchronous operations self-documenting in any given class file.


Always name event handler methods with only lowercase letters and ensure that the names always begin with either ‘on’, ‘onbefore’, or ‘onafter’. Conversely, only name true event handler methods in this manner or with those prefixes.


Document events in the class file header with the following JavaScriptDoc tags:


@listens-to-event

@emits-event


In the case of @listens-to-event, be sure to document where the listened-to event comes from. For example,


@listens-to-event <code>onresize</code> from the <code>window</code> document object.

@emits-event <code>onresize</code>.



2.1.5 Global Variables

The only custom global variable will be ‘self.gloScope’. All other top-level custom JavaScript properties that are not class definitions must be properties of ‘self.gloScope’.



2.1.6 Inline JavaScript

There will be no inline JavaScript except for the dynamically-written calls to ‘handleEvent’. Inline JavaScript is JavaScript in an html file.


An example of a call to ‘handleEvent’ is the following:


. . . onclick=’self.Environment.handleEvent(this.id, “onresize”, this.e);’ . . . “


(The dots represent an elision; do not use these in your actual code). Note that if necessary (say, for example with ‘window.onresize’, which cannot be rendered through dynamically-written html), the event handler assignment may be done in a method called ‘bindEvents’. For example,


function Console_bindEvents() {

window.id = this.strWindowId;

window.onresize = function() {


self.Environment.handleEvent(this.id,

'onresize', this.e);

};



2.1.7 Code Formatting

2.1.7.1 Whitespace

Use a presentable code indenting style, with spaces, not literal tab characters, as the indenting character. (This means that you can use ‘tab’ to indent your code, but your editor should put down ‘space’ characters for each ‘tab’. Editors can be set to automatically substitute multiple spaces for single tab characters.


For the Gnu Emacs development environment (available on Windows/Mac/Unix), the following indenting, whitespace, and syntax coloring set-up is recommended:



;; -------- Begin JavaScript editing section. --------

;; Use c-mode indenting for the C-family language, JavaScript:

(autoload 'c-mode "cc-mode.elc")

(setq auto-mode-alist (cons '("\\.js$" . c-mode) auto-mode-alist))

;; This is the container for my custom js editing mode

;; Include this line to use no tabs for cross-editor compatibility:

;; (setq indent-tabs-mode nil)

(defun my-js-indent-setup ()

(setq c-default-style "bsd")

(setq indent-tabs-mode nil)

(setq c-basic-offset 4))


;; Add the above hook to the c-mode.

(add-hook 'c-mode-hook 'my-js-indent-setup)

;; -------- End JavaScript editing section. --------


;; ---------- Begin Global Tabs Section

;; Make sure that tabs are being used (default behavior, but doesn't hurt in case something got changed):

;; (setq indent-tabs-mode t)


;; Make sure that no tab characters are used:

(setq indent-tabs-mode nil)


;; Set the variable default-tab-width.

(setq default-tab-width 4)

;; ---------- End Global Tabs Section


;; Enable syntax coloring.

(global-font-lock-mode t)



To configure your Gnu Emacs installation to take these settings, put the code above into a file named ‘.emacs’ that is read by Emacs when it first starts up. To do this, follow the steps below. It is not hard.


First, ensure that the HOME user environment variable exists. Create it if needed. Set it to your home directory (or any directory you want to be home). Next copy-paste the code above into a file named ‘.emacs’ in your home directory. See below for details on carrying out these operations under Windows.


Setting up your .emacs file under Windows:


  1. If Windows will not let you name your file ‘.emacs’, just create the file with Gnu Emacs.


  1. To set the HOME environment under Windows:


    1. Go to: Start -> Settings -> Control Panel -> System -> Advanced -> Environment Variables


    1. If you don’t see a ‘HOME’ environment variable under ‘User variables . . . ‘ at the top of the dialog, create a new one by clicking ‘New’ and typing in ‘HOME’ (no quote marks.


    1. Set the value to your home directory path.



2.1.7.2 Line Length

Keep line length under 115 characters per line. This prevents erosion of the indenting effect by line wrapping.


2.1.7.3 Spacing

Use two consecutive blank lines between each function definition.

Do not use more than one consecutive blank line inside a function.


2.1.7.4 Curly Braces

To allow more lines of code to be visible on the screen, keep the opening curly brace on the same line as the code that precedes it. I.e.:


function MyConstructor() {

this.intMyVariable = 1;

}


To avoid difficult-to-find bugs, always enclose if-then-else blocks in curly braces, even if only one statement is in a block. I.e., do this:


if (booReady) {

alert(“Ready”);

} else {

alert(“Not ready”);

}


2.1.8 Cache Repeated or Long References

JavaScript is a slow language, and memory access decreases in speed exponentially with the allocation of memory on the web browser. So it is important to cache long or repeated object references. For example, do:


var objConStyle = this.getDomRef().style


and use ‘objConStyle’ (a local variable) instead of repeated uses of ‘this.getDomRef().style’.


For another important example, do this:


var iL = this.arrArray.length, i=0;


for (; i<iL; i++) {

}


Instead of this:


var iL = this.arrArray.length, i=0;


for (var i=0; i< this.arrArray.length; i++) {

}


The assumption all these examples is that a local variable allocation is much cheaper than the reference hops, which require searching by the interpreter at each object level involved for the desired property. Notice also how the ‘var i’ is done differently in the two examples. Some JavaScript parsers may have to skip over the ‘var’ statement that is inside the ‘for’ statement each time.


2.1.9 ‘with’ statement Use

Only use the ‘with’ statement where everything referenced in the ‘with’ block is an object property or sub-property (i.e., ‘this’ . . . ) of the object provided to the ‘with’ statement.


2.1.10 ‘switch’ Statement Pitfalls

The ‘switch’ statement in JavaScript has some surprising behavior that can result in some hard-to-find bugs. Be sure to check a reference on ‘switch’ each time before using it if you have any doubts whatsoever about exactly how the ‘switch’ statement works in JavaScript.



2.1.11 Documentation


2.1.11.1 Basic Standard

Document every class file completely, according to Javadoc conventions and the special notes below.

Document every class constructor completely, according to Javadoc conventions and the special notes below.

Document every method completely, according to Javadoc conventions and the special notes below.

Mark to-do notes in this format only:

to-do:  <your comment here>

2.1.11.2 Rules for Documenting JavaScript Datatypes


  1. Class-level documentation (the “class file header”):

    1. Ensure that the first line of the class file header gives the fully qualified name of the class (i.e., com.treelogic_swe.frameworks.aspectes.Aspect).

    2. Give the licensing terms.

    3. Describe the class itself.

    4. List the principal authors in an html list.

    5. Insert a tag for version control.

    6. Document any immediate superclass in the following manner on a new line: @inherits-from <code>AbstractMyClass</code>

    7. Next document any events that class or objects made from the class will listen to, in this manner on a new line (with extra linefeeds inserted for the formatting of this document): @listens-to-event <code>onmoveup</code> from the <code>NavigationPad</code> custom JavaScript object.

    8. Next document any events that the class or objects made from the class will emit (“fire”): @emits-event <code>onmoveup</code>.

    9. Next document any class properties, and then document any object properties, following the rules below. List, in the following order:

      1. The datatype:

        1. If a value is not explicitly created with:

          1. a constructor (i.e., a number value created by invoking the Number constructor or an array created with the Array constructor function)

          2. or object initializer syntax (i.e., an array created with square brackets ( [ ] ), or an object created with curly braces ( { } ))

then use the actual result of the application of a typeof statement to the value.

          1. For example: Given var intA = 2; typeof intA gives number. We then list number as the datatype.

          2. For example: Given var booGood = true; typeof booGood gives boolean. We then list boolean as the datatype.

          3. Some common primitive values in JavaScript are: boolean, string, number, function

        1. If this value is explicitly created with a constructor or object initalizer syntax (see above), list the name of the function that constructed the object (or the name of the function that corresponds to the initializer syntax) as the datatype.

          1. This name is given in the result of the constructor property of the object.

          2. For example:

            1. Given var arrMyArr = new Array(); arrMyArr.constructor gives the function

function Array() { [native code for Array.Array, arity=1] }

In this case, list Array as the datatype for the property.


            1. Given var objMyObj = {}; objMyObj.constructor gives the function

function Object() { [native code for Object.Object, arity=1] }

In this case, list Object as the datatype for the property.


            1. Given var strS = new String(“fred”); strS.constructor gives the function

function String() { [native code for String.String, arity=1] }

In this case, list String as the datatype for the property.


            1. Given function Fred() { this.intA = 1; }; var objF = new Fred();

objF.constructor; gives the function

function Fred() { this.intA = 1; }

In this case, list Fred as the datatype for the property.


      1. Then list the property name, with its proper type prefix.

      2. Next give a complete description of the property, ensuring that line length does not exceed 115 characters and that the description text does not wrap underneath the datatype listing discussed above. Break the line with a linefeed to prevent this from happening.

      3. Here is a complete example of a class-property JavaScriptdoc line (with extra linefeeds inserted for the formatting of this document):

* @class-prop <code>Object</code> <code>hshWidgets</code> A hash containing all instantiated widget objects, keyed by widget i.d.

      1. Here is a complete example of an object-property JavaScriptdoc line (with extra linefeeds inserted for the formatting of this document):

* @object-prop <code>FastLinkedList</code>

<code>objNewImagesList</code> A linked list of the image urls required

* for the new view on the <code>plate</code> document object model object.


  1. For every parameter in every method or constructor signature:

    1. List the name of the parameter first (after @param) and, in the sole exception to the rule, do *not* surround it with code tags if using the JavaScriptdoc tool from the Rhino JavaScript project or its derivatives.

    2. Then list the datatype on the same line, according to the rules above

    3. Next, if the parameter is optional, indicate that on the same line with the word: OPTIONAL, all in capital letters.

    4. Next, if the parameter may be null, indicate that on the same line with the statement MAY BE null.

      1. Note that in JavaScript, even variables intended for primitive values may be set to null.

        1. This one of the advantages of JavaScript’s loose typing. Since we pay the penalty for loose typing by definition, we should use it to our advantage where possible.

    5. Next put the description, starting on the same line, and ensuring that line length does not exceed 115 characters and that the description text does not wrap underneath the parameter name listing discussed above. Break the line with a linefeed to prevent this from happening.

    6. Here is an example of proper method documentation:


/**

* This method receives any events that this object

* listens to and routes them to the proper methods.

* @param pStrEventSourceElementId <code>string</code> The i.d.

* of the document object model

* from which the event sprang.

* @param pStrEventType <code>string> The event type of the

* object (e.g., 'onclick', etc).

* @param pObjEvent <code>Object</code> The event object

* itself.

*/


    1. Here is another example of proper method documentation:


/**

* Return the HTML of the object managed by

* the <code>Plate</code> widget and its child widgets.

* @return <code>string</code> A string representing

* the HTML of the

* object managed by the widget and

* its child widgets.

*/


  1. For every return value, list the datatype of the return value after the @return tag, selecting the datatype to list per the rules in item 1 of this list.

  2. If the value returned is ordinarily a primitive value, but may also be returned as null, list that return value as in the step above, resulting in an additional @return tag entry for the method.


Please note: Always use the 'code' tag where you are naming something with the same name as used in the code, unless in a case noted otherwise above. This is per the Javadoc conventions but is repeated here since the violation of this rule is a common mistake.



2.1.11.3 Functional and Procedural Code

Do not write any functional or procedural code. Inner functions may be used, since they are effectively inner methods.


Do not use plain 'callbacks', or dynamically-bound methods outside of a formal aspect definition.

Do not rely upon lexically-scoped variables (via the function closure) except when it is by far the most effective way to accomplish the task at hand. Always document reliance upon function closures in the JavaScriptdoc.

2.1.12 Class Files and Packages

Keep only one outer (top-level) JavaScript class definition per file, and nothing else -- just as in Java. 

Keep related classes in a package directory, and name these packages with the organizational namespace, as in Java.



2.1.13 Methods

Create JavaScript methods either by binding them in the class constructor, in this manner:


this.receiveEvent = Console_receiveEvent;


or by creating them as inner functions within other methods that are bound as the above, to a nested level no greater than two levels deep.


Prefix JavaScript methods with the class name and an underbar. For example,


function MyClass_myMethod(pIntMyArg) {

}


The above method is made to be a method by binding it in the JavaScript class constructor:


function MyClass() {

this.myMethod = MyClass_myMethod;

}


Never use the arguments object as a vehicle for method parameters instead of named method parameters. Instead, always fully declare all parameters in the method signature. (Use of arguments.length is fine).


Create real private methods when possible by using JavaScript inner methods. JavaScript inner methods entail some performance impact, but the true encapulation they provide (rare in JavaScript) is well worth some performance sacrifice.


JavaScript inner methods are function declarations nested inside other function declarations. Follow this stylistic convention for inner methods:


Example: When putting an inner method called upArrow (for example) inside a method called, for example, Navigation_getHtml, prepend the last chunk of the method name beginning with an underbar and add an underbar to it. In this case, the prepended fragment would be _getHtml_. So the final name of the inner method would be _getHtml_upArrow.



Additionally, demarcate ‘private’ JavaScript methods with the prefix ‘pri’:


function MyClass_priMyMethod(myArg) {

}


2.1.14 Static Definitions

Use JavaScript pseudo-static properties where you would Java static objects; i.e.:


AbstractWidget.intUniqueNum = 0;


2.1.15 Data Types

2.1.15.1 Maintaining Type Correctness

Never let a variable or property fall into a state where its true datatype does not agree with its type prefix. For example, if testing for the existance of a string match, do not do this:

var booIsRainy = strWeatherReport.indexOf( “rain” ) + 1;

instead, do this:

var booIsRainy = new Boolean( strWeatherReport.indexOf( “rain” ) ).valueOf();



2.1.15.2 Type Prefixes

Because JavaScript is a loosely typed language, a prefix notation has been used. This helps to avoid pernicious bugs. A particularly dangerous mistake to make in JavaScript is to treat an array as a plain object. Here is an illustration of the pitfall of this mistake straight from the Rhino JavaScript prompt:


js> hshA = { 2 : 2, 0 : 0, 1 : 1 };

[object Object]

js> arrA = [ 1, 2, 3 ];

1,2,3

js> print(hshA[0]);

0

js> print(arrA[0]);

1

js>


If you know that ‘hshA’ is a hash (a plain JavaScript object), the reason why ‘hshA’ does not return ‘2’ is clear. However, if you thought that ‘hshA’ was an array, you would expect ‘hshA’ to return ‘2’. Therefore, always mark hashes with the prefix ‘hsh’ and arrays with the prefix ‘arr’.


Furthermore, because of the wide variety of types of objects supported by JavaScript and the complexity that JavaScript code may reach, other type prefixes are used. This provides a shield against possible pitfalls beyond the example given above, and makes the code much more readable.



2.1.15.3 Type Prefixes Table


Use of the following datatype and structural prefixes is required:


Prefix

JavaScript Type

Comment

Abstract

Function

An function that is an abstract class constructor.

any

Any

JavaScript can put any type into a given identifier.

In rare but important cases, use of this facility can

be helpful to code clarity, compactness, and speed.

arr

Array

A JavaScript array object, for ordered access only.

boo

Boolean

A JavaScript boolean.

ct

Object

A Controller object.

dom

Object

A JavaScript object that represents an object in the

browser’s Document Object Model.

evt

Object.

An event object.

flt

Number

A JavaScript Number to be treated as a floating

point number.

fra

Object

A top-level Window frame, or an inline frame.

fun

Function

A JavaScript function, never accessed as an

object method.

hsh

Object

Used as a pure unordered set.

int

Number

A JavaScript Number to be treated as an integer.

obj

Object

An object that is a combination of data and

methods.

p

(any type)

Function Argument; capitalize the other type

prefix: i.e., pIntNumCards.

rxp

Regular Expression

A JavaScript regular expression.

str

String

A JavaScript string.

super

Function

A JavaScript function that is bound as an object

method and is used to bestow unique copies of

objects upon objects created from inheriting

classes.

und

Undefined

A JavaScript object of type “undefined”.

wgt

Object

A GUI widget object.


2.1.16 Code Optimization

        Follow standard code optimization practices detailed in any c-family language code optimization reference and in good JavaScript books, such as:

      • Caching the length of 'for' loops

      • Minimizing reference hops by caching nested object references in local var variables

      • Where performance is not absolutely critical, take advantage of the encapsulation provided by JavaScript's inner methods and inner classes.

      • Using the with statement to advantage (see above).

      • Only using eval where necessary.