FOLLOWING
BEST PRACTICES
WHAT WE ARE GOING TO TALK ABOUT
- HTML and CSS Best Practices
- Principles of Writing Consistent JavaScript
- Importance of JSLint
- Commenting made easy - JSDocs
- Tools for improving Development
Best Practices for writing HTML and CSS
Why is this important?
One Simple Idea
All code in any code-base should look like a single person typed it, no matter how many people contributed.
HTML and CSS 101
- Use DOCTYPE
<!-- HTML 5 -->> <!DOCTYPE html>
- Close the tags. Always.
<li>Some text here. <li>Some new text here. <li>You get the idea.
- Use Semantic Elements
//Bad code
<span class="heading"><strong>Welcome Back</span></strong>
<br><br>
It has been a while. What have you been up to lately?
<br><br>
//Good Code
<h1>Welcome Back</h1>
<p>It has been a while. What have you been up to lately?</p>
4. Keep the Syntax Organized
- Use lowercase letters within element names, attributes, and values
- Indent nested elements
- Strictly use double quotes, not single or completely omitted quotes
- Remove the forward slash at the end of self-closing elements
- Omit the values on Boolean attributes
5. Use alt for img tags
6. No inline - CSS or JavaScript
7. Learn the html tags
- What is <abbr> tag used for?
- How about <cite>?
8. Understand and use CSS Resets
9. Do not use IDs in CSS selectors
10. Use specific classes when necessary
11. Use shorthand properties and values
img {
margin: 5px 10px;
}
button {
padding-left: 20px;
}
12. Write CSS lines using multiple lines and spaces
a,
.btn {
background: #aaa;
color: #f60;
font-size: 18px;
padding: 6px;
}
13. Use proper class names
.Red_Box { ... } //NO
.alert-message { ... } //YES
14. Modularize styles for re-use
15. Avoid using tables!!
16. Browser support
- Use fallbacks and shims
17. Provide fallbacks for media
<audio controls>
<source src=sound.ogg type=audio/ogg>
<source src=sound.mp3 type=audio/mp3>
<!-- fallback content: -->
<a href=sound.ogg>Ogg</a>
<a href=sound.mp3>MP3</a>
</audio>
<video controls>
<source src=video.webm type=video/webm>
<source src=video.mp4 type=video/mp4>
<!-- fallback content: -->
<iframe width="480" height="360" src="#" frameborder="0" allowfullscreen>/<iframe>
</video>
18. Forms
- Enclose all label names with the <label> tag.
- Use the new email and url input types to define these common fields.
- Use the placeholder attribute to provide input hints.
- Use the required attribute to request validation.
- Drop the name attribute in favor of an id where needed.
19. Understand Device limitations
20. Avoid using iframes
21. Use .htaccess to the maximum
- Enable GZIP compression
- Add expire headers to static content
- Using redirects
- Add MIME types
22. Place CSS links in the head tag
23. Place JS links at the end of the body tag
Principles of writing consistent and correct JavaScript code
"law of code style consistency"
Whitespacing
- Never mix white spaces and tabs
- Check for indentation
- No extra spaces / tabs at the end of line / file
- Use SublimeText to convert between spaces and tabs
- The file .jshintrc does all the work. Just use it correctly.
Beautiful Syntax
a. Parenthesis, Braces and Linebreaks
Have spaces, braces and span multiple lines
-
if
-
else
-
for
-
while
-
try
Encourages readability
Beautiful Syntax
DO NOT DO THIS
if(condition) doSomething();
while(condition) iterating++;
for(var i=0;i<100;i++) someIterativeFn();
YOU CODE IS MINIFIED AT END
IMPROVE READABILITY NOW
Beautiful Syntax
// Use whitespace to promote readability if ( condition ) { // statements } while ( condition ) { // statements } for ( var i = 0; i < 100; i++ ) { // statements }
var prop; for ( prop in object ) { // statements } if ( true ) { // statements } else { // statements }
Beautiful Syntax
b. Assignments, Declarations, Functions
Use only one 'var' per scope
// Variables var foo = "bar", num = 1, undef; // Literal notations: var array = [], object = {};
// Using only one `var` per scope (function) promotes readability // and keeps your declaration list free of clutter (also saves a few keystrokes)
Beautiful Syntax
// Bad var foo = ""; var bar = ""; var qux; // Good var foo = "", bar = "", quux;
One Scope -> One var
Beautiful Syntax
var statements should always be in the beginning of their respective scope (function).
// Bad
function foo() {
// some statements here
var bar = "",
qux;
}
// Good
function foo() {
var bar = "",
qux;
// all statements after the variables declarations.
}
Beautiful Syntax
Using Function Declaration, Expression and Usage
// Named Function Declaration function foo( arg1, argN ) { } // Usage foo( arg1, argN ); // Function Expression var square = function( number ) { // Return something valuable and relevant return number * number; };
// Constructor Declaration function FooBar( options ) { this.options = options; } // Usage var fooBar = new FooBar({ a: "alpha" }); fooBar.options;
Beautiful Syntax
c. Exceptions and Slight Deviations
// Functions with callbacks foo(function() { // Note there is no extra space between the first paren // of the executing function call and the word "function" }); // Function accepting an array, no space foo([ "alpha", "beta" ]);
// Function accepting an object, no space foo({ a: "alpha", b: "beta" }); // Single argument string literal, no space foo("bar"); // Inner grouping parens, no space if ( !("foo" in obj) ) { }
Beautiful Syntax
d. Be Consistent everywhere
if (condition) { // statements } while (condition) { // statements } for (var i = 0; i < 100; i++) { // statements }
if (true) { // statements } else { // statements }
Beautiful Syntax
e. Quotes
- Single or Double - Doesn't matter
- ABSOLUTELY MUST BE CONSISTENT
- NEVER MIX QUOTES IN THE PROJECT
Type Checking
a. Actual Types
-----Use 'type of'-----
String: typeof variable === "string"
Number: typeof variable === "number"
Boolean: typeof variable === "boolean"
Object: typeof variable === "object"
Array: Array.isArray( arrayLikeObject ) (wherever possible)
Type Checking
b. Coerced Types
// `foo` has been declared with the value `0` and its type is `number` var foo = 0;
// typeof foo; ?
foo = document.getElementById("foo-input").value;
// typeof foo; ?
if ( foo === 1 ) { importantTask(); }
Type Checking
Solution??
// You can preempt issues by using smart coercion with unary + or - operators:
foo = +document.getElementById("foo-input").value;
// ^ unary + operator will convert its right side operand to a number
// typeof foo; ??
if ( foo === 1 ) {
importantTask();
}
Type Checking
More examples
var number = 1,
string = "1",
bool = false;
number; //answer?
number + "";
string;
+string;
+string++;
string;
bool;
+bool;
bool + "";
"1", "1", 1, 1, 2, false, 0, "false"
Type Checking
Small Exercise
var number = 1, string = "1", bool = true; string === number; string === number + "";
+string === number; bool === number; +bool === number; bool === string; bool === !!string;
Conditional Evaluation
For Arrays
// When only evaluating that an array has length, // instead of this: if ( array.length > 0 ) ... // ...evaluate truthiness, like this: if ( array.length ) ...
// When only evaluating that an array is empty, // instead of this: if ( array.length === 0 ) ... // ...evaluate truthiness, like this: if ( !array.length ) ...
Conditional Evaluation
For Strings
// When only evaluating that a string is not empty,
// instead of this: if ( string !== "" ) ...
// ...evaluate truthiness, like this: if ( string ) ...
// When only evaluating that a string _is_ empty, // instead of this: if ( string === "" ) ...
// ...evaluate falsy-ness, like this: if ( !string ) ...
Conditional Evaluation
For Variables
// When only evaluating that a reference is true, // instead of this: if ( foo === true ) ...
// ...evaluate like you mean it, take advantage of built in capabilities: if ( foo ) ... // When evaluating that a reference is false, // instead of this: if ( foo === false ) ...
// ...use negation to coerce a true evaluation if ( !foo ) ...
// ...Be careful, this will also match: 0, "", null, undefined, NaN
// If you _MUST_ test for a boolean false, then use if ( foo === false ) ...
Conditional Evaluation
A Simple Trick
// When only evaluating a ref that might be null or undefined, but NOT false, "" or 0, // instead of this: if ( foo === null || foo === undefined ) ...
// ...take advantage of == type coercion, like this: if ( foo == null ) ...
// Remember, using == will match a `null` to BOTH `null` and `undefined` // but not `false`, "" or 0 null == undefined
USE '==='* and Booleans
Naming
- You are not computer / compiler
- Don't save space by using short variable names
- Use meaningful variable names
NO NO to these
// Example of code with poor names
function q(s) {
return document.querySelectorAll(s);
}
var i,a=[],els=q("#foo");
for(i=0;i<els.length;i++){a.push(els[i]);}
Naming
// Same code with improved names
function query( selector ) {
return document.querySelectorAll( selector );
}
var idx = 0,
elements = [],
matches = query("#foo"),
length = matches.length;
for ( ; idx < length; idx++ ) {
elements.push( matches[ idx ] );
}
Naming
Conventions
// Naming strings `dog` is a string // Naming arrays `dogs` is an array of `dog` strings
// Naming functions, objects, instances, etc camelCase; function and var declarations // Naming pseudo-classes, constructors, prototypes, etc. PascalCase; constructor function // Naming regular expressions rDesc = //;
Naming
Google Closure Library Style Guide
functionNamesLikeThis;
variableNamesLikeThis;
ConstructorNamesLikeThis;
EnumNamesLikeThis;
methodNamesLikeThis;
SYMBOLIC_CONSTANTS_LIKE_THIS;
Naming
Using this and bind correctly
function Device( opts ) { this.value = null;
// open an async stream, // this will be called continuously stream.read( opts.path, function( data ) {
// Update this instance's current value // with the most recent value from the // data stream this.value = data; }.bind(this) );
// Throttle the frequency of events emitted from // this Device instance setInterval(function() { // Emit a throttled event this.emit("event"); }.bind(this), opts.freq || 100 ); }
Naming
Using this and bind with libraries
// underscore, _.bind() function Device( opts ) { this.value = null; stream.read( opts.path, _.bind(function( data ) { this.value = data; }, this) ); setInterval(_.bind(function() { this.emit("event");
}, this), opts.freq || 100 ); }
Naming
Last resort
NOT ADVISABLE
function Device( opts ) { var self = this; this.value = null; stream.read( opts.path, function( data ) { self.value = data; }); setInterval(function() { self.emit("event");
}, opts.freq || 100 ); }
Naming
a special 'thisArg' signature
var obj; obj = { f: "foo", b: "bar", q: "qux" }; Object.keys( obj ).forEach(function( key ) { // |this| now refers to `obj` console.log( this[ key ] ); }, obj ); // <-- the last arg is `thisArg` // Prints...
// "foo" // "bar" // "qux"
Miscellaneous
Early returns promote code readability
// Bad: function returnLate( foo ) { var ret; if ( foo ) { ret = "foo"; } else { ret = "quux"; } return ret; }
// Good: function returnEarly( foo ) { if ( foo ) { return "foo"; } return "quux"; }
Misc
Comments
- Single lines above the code -> Subject
- Multiline commenting -> Very Good
- End of line commenting -> Prohibited
More about commenting later...
Misc
The semicolon confusion
var foo = function() { return true; }; // semicolon here.
function foo() { return true; } // no semicolon here.
Misc
Function declaration within blocks
NO TO THIS
if (x) {
function foo() {}
}
USE THIS
if (x) {
var foo = function() {};
}
Misc
Prefer nullifying than deleting
Use this.foo = null, instead of delete this.foo
//Use
Foo.prototype.dispose = function() { this.property_ = null; };
//Instead of: Foo.prototype.dispose = function() { delete this.property_; };
Misc
eval??
Only for code loaders and REPL (Read Eval Print Loop)
{ "name": "Alice", "id": 31502, "email": "looking_glass@example.com" }
//NO TO THIS PLEASE
var userInfo = eval(feed); var email = userInfo['email'];
// USE ALTERNATIVES INSTEAD
var userInfo = JSON.parse(feed); var email = userInfo['email'];
Misc
Multiline String Literals
//NO TO THIS
var myString = 'A rather long string of English text, an error message \ actually that just keeps going and going -- an error \ message to make the Energizer bunny blush (right through \ those Schwarzenegger shades)! Where was I? Oh yes, \ you\'ve got an error and all the extraneous whitespace is\ just gravy. Have a nice day.';
//USE CONCATENATION INSTEAD
var myString = 'A rather long string of English text, an error message ' + 'actually that just keeps going and going -- an error ' + 'message to make the Energizer bunny blush (right through ' + 'those Schwarzenegger shades)! Where was I? Oh yes, ' + 'you\'ve got an error and all the extraneous whitespace is ' + 'just gravy. Have a nice day.';
Misc
Using Array Literals
Do not use 'new'
//BAD
// Length is 3. var a1 = new Array(x1, x2, x3);
// Length is 2. var a2 = new Array(x1, x2);
//GOOD
var a = [x1, x2, x3];
var a2 = [x1, x2];
Misc
Using Object Literals
//BAD
var o = new Object(); var o2 = new Object(); o2.a = 0; o2.b = 1; o2.c = 2;
o2['strange key'] = 3;
//GOOD
var o = {}; var o2 = { a: 0, b: 1, c: 2, 'strange key': 3 };
Misc
Modifying Prototypes of built in Objects
DO NOT MODIFY BUILTINS like
Object.prototype
Array.prototype
Function.prototype
Misc
Boolean Expressions
Boolean('0') == true '0' != true 0 != null 0 == [] 0 == false
Boolean(null) == false null != true null != false
Boolean(undefined) == false undefined != true undefined != false
Boolean([]) == true [] != true [] == false Boolean({}) == true {} != true {} != false
Misc
Use ternary operators like || and && for short-circuiting
/** @param {*=} opt_win */
function foo(opt_win) {
var win = opt_win || window;
// ...
}
var kid = node && node.kids && node.kids[index];
if (kid) {
foo(kid);
}
Don't have more than 4 filters while checking
Misc
Iterating over Node lists
NO NO
var paragraphs = document.getElementsByTagName('p');
for (var i = 0; i < paragraphs.length; i++) {
doSomething(paragraphs[i]);
}
YES YES YES
var paragraphs = document.getElementsByTagName('p');
for (var i = 0, paragraph; paragraph = paragraphs[i]; i++) {
doSomething(paragraph);
}
Using JSLint
JS Lint
Checks your code for structural and formatting errors
Install the latest SublimeLinter v3
Install these packages
- SublimeLinter-jshint
- SublimeLinter-json
- SublimeLinter-phplint
- SublimeLinter-csslint
- SublimeLinter-html-tidy
Commenting Code using JSDocs
JSDocs
/**
* Illustrates line wrapping for long param/return descriptions.
* @param {string} foo This is a param with a description too long to fit in
* one line.
* @return {number} This returns something that has a description too long to
* fit in one line.
*/
project.MyClass.prototype.method = function(foo) {
return 5;
};
Run /** or // and 'tab' to auto form the comments
Works across HTML, JS, CSS and PHP
Tools for easy development
Next Session
Best Practices
By Chaithanya Yambari
Best Practices
Best Practices to follow while developing HTML / JS Applications
- 638