Categories
JavaScript Best Practices

Maintainable JavaScript — Comments and Statements

Creating maintainable JavaScript code is important if want to keep using the code.

In this article, we’ll look at the basics of creating maintainable JavaScript code by writing comments and statements properly.

Potential Author Errors

If there’re author errors in the code, then we should comment on them so that they can be fixed.

At least someone can check if it’s actually an error.

For example, if we have:

while (element && (element = element[axis])) {
  // NOTE: assignment
  if ((all || element[TAG_NAME]) &&
    (!fn || fn(element))) {
    return element;
  }
}

then some people may think that the assignment operation in the while loop head is a mistake.

This is a valid syntax, so we can use it.

It’s not a mistake, so we tell readers that it’s not with a comment.

It may be flagged by some linting tools since we usually don’t use assignments in our loop header.

Browser-Specific Hacks

If we need to make our code work with multiple browsers, then we may need to write hacks to make them work with some specific browser.

This is common when we need to make our front end code work with Internet Explorer.

If we have hacks in our code, we should make comments on what we’re doing so people know what’s going on.

This should be less common as browsers become more standardized.

Documentation Comments

Comments can be used for documentation with programs like JSDoc.

For example, we can write:

/**
  add 2 numbers together
  @method add
  @param {number} x - a number
  @param {number} y - another number
  @return {number} the sum of 2 numbers
**/
function add(x, y) {
  return x + y;
}

We have the add function that has 2 parameters.

We add some comments about the parameters so we know the type of the parameters.

Also, we do the same with the return type.

This can be read with a documentation generator to create our documentation.

We should document all methods, including the expected arguments and possible return values.

Constructors should have comments with the custom type and expected arguments.

Other objects that have one or more methods can have comments on the methods.

They must be documented for proper documentation generation.

The document generator would determine how the comments should be formatted.

Statements

Statements like if or for can be used in 2 ways in JavaScript.

We can have the curly braces or we can skip them if our block is only one line long.

However, skipping the curly braces is bad since it’s hard to tell where the block starts or ends.

So instead of writing:

if (condition)
  doWork();

or

if (condition) doWork();

or

if (condition) { doWork(); }

We should write:

if (condition) {
  doWork();
}

Having the body below the first line is better than having it on the same line.

The curly-brace surrounds the block and it’s easy to tell where the block starts or ends with them.

Conclusion

Comments should be added for potential errors or hard to understand code.

Also, statements should be surrounded with curly braces.

Categories
JavaScript Best Practices

Maintainable JavaScript — Comments

Creating maintainable JavaScript code is important if want to keep using the code.

In this article, we’ll look at the basics of creating maintainable JavaScript code by creating better single-line comments.

Comments

Many people don’t like comments.

They’re a chore to add and update.

And they feel like documentation.

Fortunately, the code serves as our documentation most of the time.

We can just write some comments to cover things that haven’t been covered by the code.

JavaScript supports 2 kinds of comments.

A comment can be a single line or multiline.

Single-Line Comments

A single-line comment starts with 2 slashes and ends at the end of the line.

For instance, we can write:

// a single-line comment

to add a single-line comment.

We usually add a space after the 2 slashes to offset the comment text.

Single-line comments can be used in a few ways.

They can be used in their own line to explain what’s following the comment.

The line should always be preceded by an empty line.

The comment should be at the same level of indentation as the following line,

We can also use them as a trailing comment at the end of a line of code.

Therefore should be at least one indent between the code and the comment.

And the comment shouldn’t go beyond the max line length.

This avoids any kind of horizontal scrolling just to read the comment.

If the comment needs to go into the next line, then we should put the comment in its own line above the code.

We can also use comments to temporarily stop a piece of code from running by commenting them out.

This can be done automatically with many text editors.

Single line comments shouldn’t be used on consecutive lines unless we’re using it to comment out code temporarily.

For instance, we can write:

if (condition) {

  // all permission checks are successful
  allowed();
}

We have an empty line above the comment to improve readability.

This is better than:

if (condition) {
  // all permission checks are successful
  allowed();
}

which is harder to read because of a lack of blank lines.

The indentation is also important.

It should be at the same level as the code we’re commenting on.

So we shouldn’t write comments like:

if (condition) {
// all permission checks are successful
  allowed();
}

Also, we should add some spaces between a piece of code and the comment if they’re on the same line.

For example, we write:

var result = count + anotherCount; // both are always numbers

This way, we have a space between the code and the comment.

We shouldn’t write something like:

var result = count + anotherCount;//both are always numbers

since there’s no space between the code and the comments.

Also, we shouldn’t write comments like:

// a condition that checks for
// all permissions.
// If all permissions are present,
// then we do something
if (condition) {
  allowed();
}

We have multiple single-line comments, which should be a multiline comment instead.

Conclusion

There are better ways to write JavaScript comments than others.

Single-line comments can be formatted better with spaces and the correct indentation.

If a single-line comment is too long, then it should be a multiline comment.

Categories
JavaScript Best Practices

Maintainable JavaScript — Blocks

Creating maintainable JavaScript code is important if want to keep using the code.

In this article, we’ll look at the basics of creating maintainable JavaScript code by writing statements properly.

Block Statements

Block statements should have curly braces surround them.

The body should also be in a separate line.

Skipping the curly braces and putting everything on the same line is valid, but it’s hard to read.

They’re also disallowed by various style guides and linters like ESLint or JSHint.

Therefore, we should add braces and have blocks that occupy multiple lines.

For instance, if we have:

if (condition)  
  doWork();  
  doSomethingElse();

Then many people will be mistaken that both lines are in the if block.

However, this isn’t the case.

Only the first line if within in the if block.

Therefore, we should just add the curly braces so that we separate the blocks clearly.

We write:

if (condition) {  
  doWork();  
}  
doSomethingElse();

and make everything clearer.

Braces should be used for all block statements, which includes:

  • if
  • for
  • while
  • do…while
  • try…catch…finally

Brace Alignment

The braces should be aligned properly.

One way to add the braces is to have the opening brace at the same line as the start of the block.

For example, we can write:

if (condition) {  
  doWork();  
} else {  
  doSomething();  
}

This is similar to Java’s style, and it’s recommended in most style guides like Google, Airbnb, and ESLint.

Another style is to have the opening braces on their own line.

For instance, some people may write:

if (condition)   
{  
  doWork();  
} else   
{  
  doSomething();  
}

This is more popular with C# since this is enforced by Visual Studio.

However, there’s no style guide that recommended this style.

And Google forbids this since it may introduce automatic semicolon insertion errors.

Block Statement Spacing

The spacing around the first line of the block is a matter of preference.

There’re 3 kinds of styles.

One of them if having the spaces between each item in the first line.

We have:

if (condition) {  
  doWork();  
} else {  
  doSomething();  
}

We have spaces between the if and the opening parentheses, and the closing parentheses and the opening brace.

This is preferred by some programmers because it’s compact but still have adequate spacing to make the code easy to read.

Another style would be:

if(condition){  
  doWork();  
}else{  
  doSomething();  
}

We have no space between anything but it’s compact.

So it’s hard to recommend this style.

The 3rtd style add spaces after the opening parentheses and before the closing parentheses, like:

if ( condition ) {  
  doWork();  
} else {  
  doSomething();  
}

This style takes more space but it’s more readable.

The first style is a good compromise between the amount of space it takes while maintaining readability.

Conclusion

Block statements can be written in a better way.

There’re ways that gives us enough space to improve readability while not taking too much space.

Also, curly braces should always be surround blocks so that we always know where they start or end.

Categories
JavaScript Best Practices

Maintainable JavaScript — Basic Formatting

Basic Formatting

Formatting our code is important for readability.

This is probably the first thing we’ve to think about when we’re wiring JavaScript code.

The suggested indentation is 2 spaces.

Spaces are portable between different platforms and text editors and so they’re consistent anywhere.

Most text editors will automatically fix formatting of our code files.

If not, then linters will help us fix them.

For example, we have 2 spaces for indentation in the following code:

if (wl && wl.length) {
  for (i = 0, l = wl.length; i < l; i++) {
    p = wl[i];
    if (s.hasOwnProperty(p)) {
      if (merge && type == 'object') {
        Y.mix(r[p], s[p]);
      } else if (p in r) {
        r[p] = s[p];
      }
    }
  }
}

A single tab character can be different from different platforms.

This means we’ve to configure tab spacing if we need to move between different platforms.

So opening a file with tabs may look different from different programs.

Therefore, multiple spaces are better for indentation.

We can change tabs to spaces automatically if we want to save some typing.

Different style guides may stipulate different kinds of spacing for our code files.

jQuery’s style guide treats indents as tabs.

Douglas Crockford’s code style guide specified indents as 4 spaces.

We can just stick with one and forget about it.

2 spaces save typing and it’s consistent everywhere so we can use that.

Statement Termination

JavaScript statements can be terminated with a newline or a semicolon.

This is different from other C-like languages which requires a semicolon.

We can skip the semicolon since JavaScript will insert it for us automatically.

That means the semicolon is actually required.

It’s just inserted automatically for us.

Therefore, it’s just better to insert it ourselves.

The rules for automatic semicolon insertion is hard to remember, so we shouldn’t both remembering them ourselves.

For example:

function getData() {
  return
  {
    firstName: 'jane',
    lastName: 'smith'
  }
}

is probably a mistake since the return statement would be added after the return .

Instead, we write:

function getData() {
  return {
    firstName: 'jane',
    lastName: 'smith'
  };
}

so there’s no chance that we’ll make a mistake.

Limiting automatic semicolon insertion helps us reduce errors.

Errors are typically caused by the misunderstanding of automatic semicolon insertion.

Various linters like JSHint and ESLint will check for these errors and let us fix them.

Line Length

Line length also matters for maintainable JavaScript because we got to make reading the code easier.

Therefore, we won’t want to scroll horizontally to read each line of our code.

Many code conventions tell us the line of code shouldn’t be longer than 80 characters.

This is a convention that’s created when screens are small.

Today, we may be able to increase the length slightly to 100 characters or even more depending on how big our screens are.

Conclusion

Basic formatting is important for creating maintainable JavaScript code.

We got to make our code easy to read.

Categories
JavaScript Best Practices

Maintainable JavaScript — Browser Detection

Creating maintainable JavaScript code is important if want to keep using the code.

In this article, we’ll look at the basics of creating maintainable JavaScript code by looking at how to detect browsers.

Browser Detection

Browser detection is a tricky topic.

There’s no perfect way to detect the actual browser.

User-Agent Detection

One way to detect the browser is user-agent detection.

The client or server can look at the user-agent string to determine the browser that made the request.

The browser’s user-agent string can be found in the navigation.userAgent property.

So we may think about writing something like:

if (navigator.userAgent.includes("MSIE")) {
  // ...
} else {
  // ...
}

We check for Internet Explorer by using the user-agent string.

The problem is that parsing the user-agent string is hard.

Also, browsers have copied each other to maintain compatibility.

With every new browser release, we need to update the user-agent detection code.

This added to the maintenance burden that we have to do.

User-agent string checking should be the last approach to check for the correct course of action.

If we check for user-agent strings, then we should only check the older browsers.

This is because newer browsers probably have the new features we want.

New features won’t be added to old browsers.

Feature Detection

Instead of checking the user-agent string, we should check whether the feature we want exists in the browser.

To do that, we can check for properties.

For instance, we can write:

if (typeof document.getElementById === 'function') {
  // ...
}

to check that document.getElementById is a function.

This way, we know exactly what we’re looking for exists or not.

It doesn’t rely on knowledge of which browser is used and only which features are available.

Therefore, it’s easy to support new browsers.

We should provide a logical fallback is there’s no feature available in the browser to provide the functionality that we want.

If we want to use newer features, then we’ve to different kinds of checks for different browsers’ implementations.

For instance, we may write:

function setAnimation(callback) {
  if (window.requestAnimationFrame) {
    return requestAnimationFrame(callback);
  } else if (window.mozRequestAnimationFrame) {
    return mozRequestAnimationFrame(callback);
  } else if (window.webkitRequestAnimationFrame) {
    return webkitRequestAnimationFrame(callback);
  } else if (window.oRequestAnimationFrame) {
    return oRequestAnimationFrame(callback);
  } else if (window.msRequestAnimationFrame) {
    return msRequestAnimationFrame(callback);
  } else {
    return setTimeout(callback, 0);
  }
}

to check each browser’s implementation of the requestAnimation method.

If none of the variants available, then we use the setTimeout method.

Avoid Feature Inference

We should assume that if one feature is available, then the related features are available.

For instance, we shouldn’t assume that if document.getElementsByTagName() is present, then document.getElementById() is present.

This also applies to any other kind of object.

Avoid Browser Inference

Also, we shouldn’t infer the browser from a given feature.

So we shouldn’t write something like:

if (document.all) {
  //...
} else {
  //...
}

to infer that is document.all exists, then IE is being used.

The code above isn’t an equivalent to:

const isIE = navigator.userAgent.includes("MSIE");
if (isIE) {
  //...
} else {
  //...
}

We can’t assume that if one feature exists, then our code is running on a given browser.

This is because the feature can be present in other browsers.

Conclusion

Browser detection is a tricky topic.

User-agent string detection isn’t very accurate.

But we can check for features to see if they’re present before we use them.