-
Notifications
You must be signed in to change notification settings - Fork 60
Code Conventions
Flocking's code conventions are a hybrid of styles from several sources. They are heavily influenced by the stylistic approach of Fluid Infusion, which in turn is influenced by Douglas Crockford's Good Parts style.
Unfortunately over the years, Douglas Crockford descended into a cranky, abusive, and absolutist mentality to code conventions and the role of his JSLint checker in enforcing his personal style. This has made it untenable for most developers to use JSLint and follow the good parts style.
As a result, Flocking continues to borrow the "good parts" from the Good Parts style and combines it with some of the conventions (but not all) promoted by the jQuery Style Guide and Rick Waldron's Idiomatic JavaScript. Thanks to both of these guides for their example code, which I have liberally borrowed.
The reality is that code conventions are one of the biggest sources of meaningless arguments and "bike shed" debates that distract a community from its real work. These Flocking code conventions are intended not as a definitive, inflexible set of rules but as a general set of guidelines from which a productive collaboration can be formed.
Lines should be indented with four spaces.
All if/else/for/while/try statements should have braces, even if they're only a single line. The braces should open on the same line as the test, and else/catch/finally/etc. statements should follow on the same line as the closing bracket.
// Good
if (true) {
// statements
} else {
// statements
}
Don't save space by omitting the brackets for single-line statements:
// Not good
if (true)
// statement.
JavaScript doesn't have block scoping. All variables are global to the function they are defined within. As a result, Flocking has gravitated towards the "one var line" style advocated by both the jQuery and Idiomatic JavaScript style guides:
var cat = "meow",
hamster = "wheel",
i;
This also has the benefit of being slightly more compact. In cases where readability is compromised, inline variable definition (such as in a for statement) can be used but should generally be avoided.
Objects should be generally broken out into multiple lines. Don't try to cram them all into one line; the Flocking's minifier will strip out the whitespace anyway.
{
farm: {
cat: "meow"
grains: ["wheat", "rye", "corn"]
}
}
Flocking typically defines named function by assigning them to variables. This helps to promote consistency with Flocking (and Infusion's) general idiom of expose all functions publicly within a hierarchical namespace:
Local function declaration:
var square = function(number) {
return number * number;
};
Function assigned to a public namespace:
flock.pets.cat = function () {
return "meow";
};
Flocking uses double quotes:
var double = "I am wrapped in double quotes";
Inner quoting should use double outside and single inside:
var html = "<div id='my-id'></div>";
Built-in types (with the exception of arrays) should be checked using typeof with no brackets:
typeof variable === "string" // Strings
typeof variable === "number" // Numbers
typeof variable === "boolean" // Booleans
typeof variable === "object" // Objects
typeof window !== "undefined" // Global variables
The non-coercive operators comparison operators should always be used:
Always:
if (foo === 1) {
}
Never:
if (foo == 1) {
}
For performance critical object types such as unit generators, Flocking uses the "that-ist" or "module pattern" from Douglas Crockford's the Good Parts.
flock.cat = function (name) {
var that = {
name: name
};
that.speak = function () {
return "meow " + name;
};
return that;
};
Everywhere else, Infusion components should be defined instead.
fluid.defaults("flock.cat", {
gradeNames: ["fluid.modelComponent", "fluid.eventedComponent", "autoInit"],
model: {
name: "hugo"
},
invokers: {
speak: {
funcName: "flock.cat.speak",
args: ["{that}.model.name"]
}
}
});
flock.cat.speak = function (name) {
return "meow " + name;
};
This component based-approach provides significant benefits including built-in options merging, dependency management using Inversion of Control, and significant flexibility for end users to customize, adapt, and extend Flocking components.
Unit generators are immensely performance critical and are intended to be usable in a reduced environment (such as in Web Workers) and constrained devices (like the Raspberry Pi). A unit generator's "gen" method may be called as many as 750x per second (at audio rate), so it needs to significantly optimized.
As a result, unit generators are defined as "that-ist" objects, and property/array access is kept to a minimum by defining local variables. Function calls should be avoided where possible, but not at the cost of hard-to-maintain code duplication.
flock.ugen.pow = function (inputs, output, options) {
var that = flock.ugen(inputs, output, options);
that.gen = function (numSamps) {
var inputs = that.inputs,
source = inputs.source,
exponent = inputs.exponent,
out = that.output,
i;
for (i = 0; i < numSamps; i++) {
out[i] = Math.pow(source[i], exponent[i]);
}
};
return that;
};
All files should be linted with JSHnit. The follow JSHint options should be included at the top of each Flocking JavaScript file:
/*jslint white: false, vars: true, newcap: true, regexp: true, browser: true,
forin: true, continue: true, nomen: true, bitwise: true, maxerr: 100,
indent: 4, plusplus: true, todo: true, culy: true, camelCase: true, eqeqeq: true,
freeze: true, latedef: true, noarg: true, nonew: true, quotmark: double, undef: true,
unused: true, strict: true, asi: false, boss: false, evil: false, expr: false,
funcscope: false*/