Coding Standards
NOTE: these standards have yet to be updated to include the latest syntax available via ECMA6.
A number of the recommendations here can be done more efficiently and effectively using today's latest syntax options.
Wins
- Minimize coding errors due to JavaScript idiosyncrasies.
- Minimize errors from browser quirks or markup glitches.
- Maximize use of tools to enforce chosen coding standards.
- Write code maintainable by large-scale development teams.
- Isolate TIBET and TIBET consumers from browser evolution.
Contents
Concepts
Cookbook
JavaScript
- Write fully-bracketed code.
- Terminate every line with a semi-colon.
- Declare local variables explicitly.
- Place 'var' statements at the top of each function.
- Don't use parameters as LVALUEs.
- Use test functions for null, undefined, and isNaN.
- Don't test equality when identity will work.
- Use test functions for equality checks.
- Use single quotes for JavaScript strings.
- Never trust the browser: encapsulate.
- Run a linter.
- Pick a standard and enforce it.
- Write comments. Seriously.
- Comment inside functions
- Follow naming conventions.
- Using get('foo') and set('foo')
- Using
get()
vs.$get()
- Using get('lastname') vs. getLastname()
XHTML
- Use an HTML5 DOCTYPE.
- Use well-formed XHTML.
- Target Section 508 and other accessibility standards.
- Use semantic markup.
- Use markup with the right display mode.
- Use markup with the right data structure.
- Use a background
<div>
. - Use a
<tbody>
in your<table>
elements. - Test your markup without CSS.
- Namespace-qualify your extensions.
- Use a well-formed checker.
DOM
- Don’t assume a node is an element.
- Don’t assume namespace handling is correct.
- Don’t manipulate the DOM while iterating over childNodes.
- Build UI in a non-windowed document and append once.
- Leverage XSLT.
- Encapsulate, encapsulate, encapsulate.
CSS
- Use a CSS "reset" baseline.
- Don’t rely on traditional CSS "hacks/filters" based on bugs.
- Do not use inline style attributes.
- Don’t default unit specifications.
- Use
cellspacing="0"
on<table>
and CSS for the rest. - Read great books on modern CSS3 techniques.
Code
Concepts
The great thing about the core web languages (JavaScript, CSS, HTML) is that they're dynamic, flexible languages with a lot of expressive power.
The down side is these technologies demand discipline if you're going to avoid some of the common bugs and inconsistencies they contain.
This document lists the coding standards we've arrived at over our 20-plus years developing applications using web technology, standards that helped TIBET survive over two decades of browser and web standard evolution with minimal impact.
Reading these you might consider some of these archaic or unnecessary, and with some of them you'd be right with respect to modern browsers.
Some of these rules arose from early work bringing TIBET to IE4 and Nav4 (Yes, it ran; Yes, we were crazy.).
Since then they've helped us port TIBET to modern HTML5 browsers with minimal change. Simply put, they work.

Like any set of coding standards ours will undoubtedly cause heated discussion and dissent. That's fine, they're our standards not yours, but if you "use the source" you'll see them in TIBET.
Ultimately your coding standard is the one your tools enforce. Here are ours.
JavaScript (ESLint)
We use eslint
to enforce JavaScript standards. See TIBET's .eslintrc
file for
details.
JSON (require/JSON.parse)
The tibet lint
command loads/parses JSON files to ensure they're well-formed.
XHTML/XML (xmllint, Xerces)
The tibet lint
command checks all XML is well-formed. No validation is done.
CSS/Less (stylelint)
We run stylelint
to keep our styles clean. See TIBET's .stylelintrc
file for details.
Cookbook
JavaScript
Bug Avoidance
This first section of standards is strongly recommended since they focus on habits that will help you avoid a number of common JavaScript coding traps.
JavaScript may look like C/C++ a bit, and it may share the 'Java' prefix with another popular language, but it is a unique language with its own unique requirements. Write JavaScript like it was some other language and you’ll pay the price.
Write fully-bracketed code.
One of the frequent errors when using C-style languages is adding statements to
an if
or while
statement when that statement has not been fully bracketed.
Always use fully bracketed code, even if there is only a single statement:
Do this:
if (foo.equalTo(bar))
{
alert('Foo does indeed equal bar');
}
Not this:
// DON'T DO THIS
if (foo.equalTo(bar))
alert('Foo does indeed equal bar');
Terminate every line with a semi-colon.
JavaScript’s automatic semicolon insertion feature can cause hard-to-find bugs. We recommend authoring with intent and letting tools do the minification. Don't hand-minify your code at the risk of introducing bugs.
if (foo.equalTo(bar)) {
alert('Foo does indeed equal bar');
// <= Semicolon here.
} // <= Not here (on blocks) if you're using modern JS linters.
var myFunc = function () {
...
}; // <= Here since this is an assignment statement.
Declare local variables explicitly.
Variables in JavaScript are scoped at either the function or global level. If a
variable is declared it will be functionally scoped. Undeclared variable
assignments create globals. Make sure your variables have function scope. Use
var
(or let
if you're authoring in ES6`).
This:
var count = 1;
Not this:
// CREATES A GLOBAL!
count = 1;
Your goal should be to have zero global variables leaking from your code.
Place 'var' statements at the top of each function.
One of the common misconceptions about JavaScript is that because its syntax is very C-like its behavior is as well. This is not the case. The following code does not do what most programmers from block-scoped languages expect:
var index = 1;
function myFunc() {
alert('index: ' + index); // undefined!
for (var index = 0; index < myStuff.length; index++) {
alert('blah blah #' + index);
}
}
JavaScript's var
has no concept of block scope, just function scope. In
JavaScript the declaration of index
in the for-loop is hoisted and occurs as
if you'd declared it prior to the first alert()
call.
Your code actually runs as if you'd written:
var index = 1;
function myFunc() {
var index;
for (index = 0; index < myStuff.length; index++) {
alert('blah blah #' + index);
}
}
Our recommendation is write the code the way the JavaScript engine will run it.
Use let
if you're style requires you to "inline" your variable
declarations…the TIBET rule is use var
and use it at the top of the
function to make all declarations easy to spot.
Don't use parameters as LVALUEs.
Older browsers could exhibit serious problems when a non-null parameter value
was used as an LVALUE. Historically TIBET code would always create a separate
var
for any parameter whose value could be altered during function execution.
This rule has been loosened slightly over time, but it's still the way most
TIBET code is authored.
This:
var myFunction = function (paramA, paramB) {
var pA = paramA; // do this.
if (pA != "foo") {
pA = "foo"
}
};
Not this:
// DON'T DO THIS
var myFunction = function (paramA, paramB) {
if (paramA != "foo") {
paramA = "foo"; // Throws an exception in some versions of IE.
}
};
Use test functions for null, undefined, and isNaN.
JavaScript's automatic type conversions can cause problems when tests are done
with non-Boolean values, values like []
, 0
, ''
, (but not {}
) which
resolve to false
after Boolean type conversion. As a result tests for null
and undefined
often go astray.
JavaScript's isNaN
function doesn't just return true for NaN
, it also
returns true for things like native constructors. That might be "accurate" in
the sense that Date
is "not a number" but it's not accurate if you were
testing explicitly for NaN
.
To assure conceptual clarity while avoiding bugs relating to automatic type
conversions use TIBET's TP.isNull()
, TP.notNull()
,
TP.isDefined()
, TP.notDefined()
, TP.isValid()
, TP.notValid()
,
TP.isNaN()
and similar encapsulation functions.
This:
if (TP.isValid(param)) {
...
}
Not this:
if (param === null || param === undefined) {
...
}
Don't test equality when identity will work.
Using ==
will trigger automatic type conversion in JavaScript, and the results
are often unexpected. Use ===
whenever possible.
This:
if (x === 0) {
}
if (x === '') {
}
if (x === false) {
}
if (x === null) {
}
if (x === undefined) {
}
if (x === y) {
}
Not this:
if (x == 0) {
}
if (x == '') {
}
if (x == false) {
}
if (x == null) {
}
if (x == undefined) {
}
if (x == y) {
}
Use test functions for equality checks.
JavaScript's ==
and ===
operators don't always operate as you might expect.
In most OO languages an equality test works against an object's content. If two objects have the same value they are considered equal.
JavaScript does not carry this concept through to reference types (Arrays and Objects in particular). Your custom types will also fail to compare properly using the == operator.
TIBET provides TP.equal()
and TP.identical()
functions which leverage the
objects themselves as part of the comparison. The result is that you can truly
test for objects which are equal or identical based on your specific types.
This:
if (TP.equal(array1, array2)) {
...
}
Not this:
if (array1 == array2) {
... // This will never be invoked.
}
While using TP.identical()
can be cumbersome (compared to ===
) when working
with instances of your custom types it does offer the opportunity for managing
proxy objects which we've found to be invaluable in certain designs. Use it as
needed.
Use single quotes for JavaScript strings.
HTML and XHTML use double quotes for attribute values. Since markup generation is a common task you should make it easier by using single quotes for JavaScript strings, reserving double quotes for embedded markup in those strings.
This:
var something = '<a href="#">Noop</a>';
var theString = 'Hi there.'
Not this:
var something = "<a href=\"#\">Noop</a>";
var theString = "Hi there.";
Never trust the browser: encapsulate.
We wish we could say calling native browser functions or accessing native properties directly was a solid, robust approach to client-side development… one that would stand the test of time. Just the opposite.
Many of the properties and functions you know and love turn out to have either outright bugs or limitations that become problematic faster than you think.
For example:
.getElementById()
doesn’t work consistently across browsers regarding XML and HTML DOMs..getElementsByTagName()
can’t handle XML namespaces consistently,.getAttribute()
returns different values on different browsers – and even within the same browser – depending on whether the attribute exists, is empty, or is valid,typeof
incorrectly misses certain function objects on older versions of IE.- properties accessible on one browser throw an exception if you try to access them in another browser.
Bottom line? Never trust the browser. Encapsulate everything.
A function call is the cheapest insurance policy you can buy to protect your code's future.
Run a linter.
Catching a missing var declaration, or a property assignment to a keyword you overlooked, or a window method (status is a common one), etc. can save you a lot of pain and suffering later.
Common JavaScript linting tools, such as ESLint, JSLint or JSHint can save a lot of time. TIBET's tools also have built-in linting tools, courtesy of ESLint. In fact, TIBET's project templates all have prebuilt ESLint configuration files that reflect TIBET's style.
Style & Format
Pick a standard and enforce it.
Programmers can argue about whitespace and code formatting all day long. These arguments are not particularly useful. What is useful is picking a single strategy and enforcing it via automated tools your team can't avoid using.
We highly recommend that coding standards be enforced 'organizationally' :-).
Write comments. Seriously.
TIBET code is commented as if the next developer to work on it will a) be less experienced with the project, b) have no access to the original authors, c) be under pressure to fix a bug. Kind of like your project's next developer may be ;).
We write comments and documentation accordingly. You should too.
Comment inside functions
TIBET is tooled for live, interactive, development. As a result we often reflect on objects and methods within a live running application. During development this application code isn't stripped of comments and whitespace for debugging purposes.
By placing your method comments inside the function they describe you make it possible to view the comment in any browser whenever you display the function instance.

TIBET's doclint
command is also built to scan your application's live code and
to extract method comments from the function body rather than assuming a comment
is associated by proximity rather than containment.
Follow naming conventions.
Note, none of the conventions which follow are currently enforced, however future TIBET lint checks are planned which will allow you verify conformance.
Namespaces
Namespaces should be lowercase and descend from the top-level TP
or APP
global provided by the core TIBET platform.
This:
TP.lang
TP.sys
TP.meta
TP.{ns}
Not this:
TP.Foo
TP.BAR
NOTE: The TP
global is reserved for use by the TIBET library For your projects,
you should be using the APP
global:
APP.mycorp.*
Types
Types should be named using CamelCaseNames with an initial capital letter.
Constants
Constants should be named using ALL_UPPERCASE names with underscores.
Attributes
If a property is private prefix it with a single dollar sign ($
). Private means
only the object/type in question should really be using that property or method.
Subtypes should not access private variables.
If a property is protected prefix it with a single underscore (_
). In TIBET,
as with languages like Smalltalk, Ruby, or Objective-C, a protected variable is
a variable that’s private outside of a type and its subtypes/descendants.
If a property is public no special character is used. This indicates that any
consumer can access that property without concern for violating encapsulation
rules. Even so, code should be using get
and set
, never direct property
access.
TIBET further reserves a double dollar-sign ($$
) prefix for internal variables.
Use these at your own risk - they're never guaranteed between releases.
Methods/Functions
Assume the function had a Smalltalk or Objective-C syntax where each parameter is named as in:
myObject at: someIndex put: someValue. "Smalltalk"
[myObject at: someIndex put: someValue]; // Objective-C
Separate the parameter names and values, preserving the order. Titlecase all parameter names other than the first and concatenate them, resulting in:
myObject.atPut(someIndex, someValue); // TIBET
TIBET Specifics
Using get('foo') and set('foo').
TIBET development accesses object attributes by calling
get()
or set()
rather than doing a direct slot access.
This:
var lname = employee.get('lastname');
Not this:
var lname = employee.lastname;
Likewise, if you're setting a value on an object you should invoke set()
:
This:
employee.set('lastname', 'Smith');
Not this:
employee.lastname = 'Smith';
In the former case TIBET's get()
call will optimize access to the attribute
while offering some level of encapsulation.
In the later case TIBET will ensure that the value is actually changing and if
so will automatically send a Change
signal to any observers.
Using get()
vs. $get()
.
TIBET's get()
and set()
calls both take a first step of looking for a
matching method which provides encapsulated access to the property in question.
In other words, if you call get('lastname')
TIBET will check for a
getLastname
function and call it if it's found. If the method isn't found the
get()
routine will invoke $get()
, a primitive slot access routine.
If you're implementing the getLastname
routine itself you don't want to call
get('lastname')
or you'll create an endless recursion. Therefore getters you
implement should always use the $get()
call.
This:
Employee.Inst.defineMethod('getLastname', function() {
return this.$get('lastname');
});
Not this:
Employee.Inst.defineMethod('getLastname', function() {
// NO!! THIS WILL RECURSE!!!
return this.get('lastname');
});
The same approach should be used for setters. Within a setter call $set()
to
perform the actual slot update while retaining change notification support.
Using get('lastname') vs. getLastname().
From a best-practice perspective TIBET coding standards suggest that you only call a fully-formed accessor method from within the type itself. This allows the type to leverage the accessor without imposing an API dependency.
If you're concerned about performance don't be. Firstly, function calls of this
type are exceptionally fast. Secondly, a simple pass through a (future)
pre-processor can easily expand get('foo')
calls into getFoo()
for
production code deployment.
For more information about a variety of differences between regular JS and TIBET, see JavaScript: The TIBET Parts.
(X)HTML
TIBET is an XML platform in part so we can verify markup using XML tools including well-formed checks and XMLSchema if desired. Using XML also allows us to seamlessly integrate common XML formats like RSS, KML, XMPP, XBRL, and other business and government standards.
XHTML Standards
As mentioned earlier and elsewhere, TIBET is an XHTML5 platform, not an HTML5 one. That means our authoring standards for markup are grounded in writing proper XML.
The markup standards provided here should help you keep your markup-related issues to a minimum and your applications running faster and more efficiently.
Use an HTML5 DOCTYPE.
All HTML files should include a DOCTYPE which identifies their content accurately to the browser and ensures that you’re not running in "quirks mode". You should use HTML Strict DOCTYPE entries, unless you’re working around a bug that requires you to use the Transitional entry:
<!DOCTYPE html>
Use well-formed XHTML.
For your TIBET markup you must enforce an XHTML standard regarding markup structure. In other words, make your files well-formed XML with properly formatted XHTML.
In short:
- element and attribute names should be lowercase,
- attribute values should always be quoted,
- non-empty elements require end tags:
<foo>stuff</foo>
, - empty elements also require end tags:
<foo/>
or<foo></foo>
as needed.
Target Section 508 and other accessibility standards.
Craft your markup to be as accessible as possible – even if you’re not currently working toward compliance with a particular accessibility standard.
Use semantic markup.
There are almost 100 unique element types in the XHTML specification. Use the one that most closely matches the intended use. For example, use H1 thru H6 for heading-like content whenever possible, styling with CSS as needed.
Use markup with the right display mode.
If you are going to use a more generic element, such as a <div>
or <span>
,
use the one with the display mode closest to your requirements. In other word,
use <div>
when you need block-level and <span>
when you need inline
rendering.
Use markup with the right data structure.
- If you have tabular data by all means use a
<table>
. - If you have a list of values use a list of some form, either
<ul>
or<ol>
. - If you have key/value pairs use
<dl>
,<dt>
,<dd>
or a semantic alternative.
Match the data structure of your model to markup suited to that structure.
Use a background div
.
Experience shows it’s a valuable technique to put all of your page content in an
enclosing div
element rather than having multiple children on the body
element. The extra control you get seems to far outweight the cost.
Use a <tbody>
in your <table>
elements.
Certain browsers exhibit subtle CSS bugs when you leave out the <tbody>
in
XHTML. If you’re going to use a <table>
then use at least one <tbody>
to
contain its content.
Test your markup without CSS.
When laying out the structure of your page you should test early/often with little or no CSS, allowing the markup’s natural structure to render into the page. Your page should still be readable, even if it doesn’t lay out other than linearly down the page. This is not only a good test for keeping the markup semantically clear; it’s a great first-cut accessibility test.
Namespace-qualify your extensions.
If you’re going to extend the markup with additional elements or attributes be a good XML citizen and use a proper namespace declaration and qualifiers:
<html xmlns:mycorp="http://www.mycorp.com">
...
<mycorp:customtag attr="a" />
<span mycorp:customattr="a"/>
...
Use a well-formed checker.
Ensuring your markup is well-formed XHTML is key. Integrate a well-formed checker into your CI system or build process.
DOM
The XHTML you write defines a structure reflected in the Document Object Model or DOM. This structure is often a key player in the JavaScript you write, but failing to follow a few simple coding standards here can cause you untold hours of debugging.
Don’t assume a node is an element.
Perhaps the biggest source of bugs in DOM-related code comes from assuming that
all nodes in the .childNode
list for an element are themselves Elements. This
is a dangerous assumption. As part of the HTML5 specification, the new
.children
Array containing only Element-type children is available. Use it or,
better, TIBET-supplied methods like TP.nodeGetChildElements()
.
Different browsers will treat certain forms of whitespace differently, resulting
in text nodes (#text
) rather than the element node you expected. As a result
you’ll end up with intermittent bugs across browsers.
Always check using a node’s .nodeType
to ensure it's type 1
(Node.ELEMENT_NODE
).
Don’t assume JS namespace handling is correct.
At the time of this writing XML namespace support in the various browsers was spotty and error prone. Moreover it is inconsistent between the major browsers.
While we recommend being a "good XML citizen" and using namespaces for your proprietary extensions to the XHTML you write, we recommend using wrapper functions to help ensure namespaces are properly dealt with.
Don’t manipulate the DOM while iterating over childNodes.
Certain DOM collections (e.g. the .childNodes
nodelist for an
element) are mutable and cause problems if you alter an element’s structure
while iterating. The best approach is to either make a copy of the list or use
traversal tied to a query such as .nextSibling
.
Build UI in a non-windowed document and append once.
Performance is significantly higher when avoiding UI reflow due to constant
.appendChild
calls. When using the DOM to construct UI elements, build them
offscreen in a document fragment created for that purpose and append once.
NOTE that in some cases it’s even faster to use .innerHTML
, although that’s
not officially a standardized DOM call. It is supported in most major browser
platforms now, though.
Leverage XSLT.
Processing XML (or XHTML for that matter) is significantly faster using XSLT than native JavaScript. Whenever possible you should try to leverage XSLT, particularly for larger data sets. TIBET has full support for XSLT v1 built-in.
Encapsulate, encapsulate, encapsulate.
As mentioned in the section on JavaScript standards, experience has shown that encapsulation is your friend. This is particularly true around the W3C DOM APIs in modern browsers.
CSS
CSS Standards
While your XHTML may define the structure of your documents, it’s CSS that defines how it all looks and where different elements reside in the visual landscape of the page.
Use a CSS "reset" baseline.
For a number of reasons you should always include a CSS 'reset' which ensures that the values set by each user-agent stylesheet are normalized for your applications.
Don’t rely on traditional CSS "hacks/filters" based on bugs.
The first thing to do to help ensure you’re future-proofed in your CSS development is to stop using "hacks" relying on parser bugs or other issues in current browsers. Most of these hacks will break in modern browsers.
To give you control without relying on CSS parser bugs use a common CSS-compliant style sheet as your starting point, developing that sheet as you work in Mozilla, then load extra sheets as needed to deal with issues specific to other browsers.
The lines below can be placed in any HTML file and will ensure that all browsers share a common sheet, and then load their own "overrides" as needed.
<!-- the following three link entries give us a "future-proof" way
of dealing with browser-specific style sheets -->
<!-- the shared sheet for all browsers comes first -->
<link id="std_css" rel="stylesheet" href="../css/std.css" type="text/css"/>
<!-- sheet for mozilla-specific tweaks, IE will ignore this because
it will observe the disabled="true" setting here -->
<link id="moz_css" rel="stylesheet" href="../css/moz.css" type="text/css" disabled="true"/>
<link id="ie11_css" rel="stylesheet" href="../css/ie11.css" type="text/css"/>
Do not use inline style attributes.
As mentioned in the HTML standards section you should leverage class
and id
attributes. Don’t use the style
attribute -- it’s bad form to inline style
declarations. If you need something specific to an element, use an id
selector
('#myElement'
) and put an id
on the element.
AJAX techniques can be managed and maintained far more effectively by leveraging either attribute selectors (in supporting browsers) or by managing the class attribute on the fly.
Don’t default unit specifications.
If you are going to use specific unit designations always specify the unit.
This:
width: 10px;
Not this:
width: 10;
When the value is 0
you can leave off the units.
Use cellspacing="0"
on <table>
and CSS for the rest.
Use CSS to style your tables, but retain the cellspacing
attribute to turn off
extra spacing of cells. Don’t place width
, border
, cellpadding
, or other
attributes on your table elements - use their CSS equivalents.
Read great books on modern CSS3 techniques.
There are too many specific CSS tricks, traps, and workarounds to cover in this document, but reading great books on modern CSS design (remember that TIBET only runs in environments that are CSS3 compliant) while keeping the previous rules in mind – particularly those regarding hacks -- will give you the best foundation possible.
Code
All code in TIBET conforms to the standard enforced by the tools leveraged by
tibet lint
. That said, a few representative files include:
~lib/cmd/make/build.js
(tibet make cmd)~lib/dna/default/plugins/proxy.js
(TDS plugin)~lib/src/tibet/kernel/TIBETLogging.js
(kernel file)
See TIBET's .eslintrc
file for
our current standard for JS.
See TIBET's .stylelintrc
file for our current CSS rules.