Categories
JavaScript Best Practices

JavaScript Best Practices — Error Processing and Exceptions

JavaScript is a very forgiving language. It’s easy to write code that runs but has issues in it.

In this article, we’ll look at how to handle errors in JavaScript programs.

Design Implications of Error Processing

If we handle errors in our system, then we got to test our error processing code.

This is to ensure that we did everything properly.

If we have return values, then we test the return values.

We should never ignore error information.

If we have a consistent approach for handling errors, then we should follow it so that we can have issues with inconsistency and duplication of error processing code.

Exceptions

Exceptions are the means of which code can pass along errors from the code that caused the error to the surface.

If we don’t want our program to crash, then we should catch them so that we can deal with them gracefully.

In JavaScript, we can throw errors by using the throw keyword on the Error class or subclass of Error .

To catch errors, we can use try...catch to catch them.

If we want to run code regardless of whether an exception is thrown, we can put them in the finally clause.

For instance, we can write the following to throw an error:

throw new Error('error');

To catch exceptions that are raised from code that may cause errors, we write:

try {  
  errorThrowingCode();  
  //...  
} catch (ex) {  
  // handdle errors  
}

Where errorThrowingCode may throw errors.

A finally clause may be added after the catch block.

Use Exceptions to Notify Other Parts of the Program About Errors that Should not Be Ignored

The whole point of throwing exceptions is that we can’t ignore them without users seeing them.

Therefore, we should use exceptions to notify other parts of our programs about errors that shouldn’t be ignored.

Throw an Exception Only for Conditions that are Truly Exceptional

Even though we should throw exceptions for things that shouldn’t be ignored, we shouldn’t use them everywhere.

If we have too many then, then we’ve to have code everywhere to handle exceptions.

We don’t want that, so we should think about using exceptions for those errors that must be handled for proper operations of our program.

Exception handling makes our code more complex as we have to catch them and then handle them.

There’re better ways to deal with non-critical errors like checking for values and do something instead of throwing exceptions.

Don’t Use an Exception to Pass the Buck

If errors can be handled locally, then we should do that.

Handling them elsewhere just makes our code more complex.

Include in the Exception Message All Information that Led to the Exception

We should include useful information in our exceptions so that we can have enough information to debug and fix the issue that caused the exception to be raised.

It just makes dealing with errors easier if we give everyone more information so that we can deal with them.

Avoid Empty Catch Blocks

Empty catch blocks are useless, so we shouldn’t include them.

We got to handle exceptions that are thrown rather than doing nothing when an exception is caught.

If we want to do nothing, we should at least log about the error.

Know the Exceptions Our Library Code Throws

Knowing exceptions that our libraries throw is important so that we can handle them when they arise.

Failing to catch them will be caught our program to crash and that won’t be good user experience.

Consider Building a Centralized Exception Reporter

Creating a centralized exception reporter makes logging and formatting exceptions a breeze as all that is done in one place.

It’s better than handling them all separately in different places.

Standardize Our Project’s Use of Exceptions

For the sake of keeping things consistent, we should standardize how exceptions are handled in our code to reduce developers’ cognitive load.

We can create project-specific exception classes and define code that is allowed to throw exceptions.

Also, we can centralize reporting and logging.

Conclusion

There is a lot to think about when we throw exceptions.

We got to think about when and how to throw exceptions. Where they handle and whether we can create our own error classes.

Standardization would make our work easier.

Categories
JavaScript Best Practices

JavaScript Best Practices for Writing More Robust Code — Clean Code

JavaScript is an easy to learn programming language. It’s easy to write programs that run and does something. However, it’s hard to account for all the uses cases and write robust JavaScript code.

In this article, we’ll look at some ways to keep our JavaScript code clean and easy to read so that changing it is a piece of cake.

Keep Code Organized

Our JavaScript code should be organized well so that they can be easily reasoned with. Well organized code don’t repeat anything.

Functions and classes inside all do one thing only and no more. They’re mostly independent of each other, and they only expose what’s needed to the outside world, which is the bare minimum to avoid tight coupling.

This is easy to do if we organize things cleanly from the beginning. For instance, we can write the following code to keep things clean:

fruit.js

export class Fruit {
  constructor(name) {
    this.name = name;
  }
}

person.js

export class Person {
  constructor(name) {
    this.name = name;
  }
}

index.js

import { Fruit } from "./fruit";
import { Person } from "./person";
const sentence = `${new Person("foo").name} likes ${new Fruit("apple").name}`;
console.log(sentence);

In the code above, we have 3 modules. The first 2, person.js and fruit.js all have one class.

They all have one class each and the class only represent one thing. The Person class represents a person and the Fruit class represents a fruit.

Then in index.js , we import both of them and reference them in the string.

With the way we organized the code, the classes don’t reference each other. Each class only does one thing, and we only reference the classes when it’s necessary.

Don’t Write Clever Code

Clever code is bad because they’re usually hard to read, even though they’re usually shorter.

Simple solutions are better for maintenance than clever code. Clever but hard to read code isn’t good since they’re hard to reason with.

For instance, the following code is an example of clever but hard to read code:

const foo = bar ? bar ? qux ? 0 : 1 : 2 : 3;

In the code above, we have a series of nested ternary operators used in one line, which is shorter than writing out each if statement directly, but it’s hard to read.

Many people probably don’t understand what it’s doing. They have to write out the parentheses in their head so that they can where each ternary operation starts and ends.

Therefore, we shouldn’t have nested ternary operators used like that. Instead, we should write use if statements or only use ternary operators to return one thing or the other for one condition.

Debugging is harder than programming, and we often have to revisit old code to debug and make changes. So we shouldn’t make our job even harder by writing clever code that is hard to read.

Photo by Charis Gegelman on Unsplash

Splitting Code in Ways That They Can Be Tested Easily

Our code should be organized in a way that can be tested easily. This means that they should be exposed to the outside so that they can tested with unit tests.

We should also aim to write pure functions. Pure functions always return the same output for a given set of inputs. This means that they can easily be tested.

Side effects should be minimized in functions so that we don’t have to check code that’s outside the function for correctness when we’re testing.

For instance, we can write our code and tests as follows:

math.js

const add = (a, b) => a + b;
const subtract = (a, b) => a - b;
module.exports = { add, subtract };

math.test.js

const { add, subtract } = require('./math');

test('adds 1 + 2 to equal 3', () => {
  expect(add(1, 2)).toBe(3);
});

test('adds 1 - 2 to equal -1', () => {
  expect(subtract(1, 2)).toBe(-1);
});

In the code above, we have math.js with the functions that we want to test. They’re both pure functions so that they always return the same output for the given set of inputs.

Then in math.test.js , we have 2 tests that are run with Jest to test those 2 functions that we imported from our math.js module.

We called add and subtract to test them and check their values with Jests’s built-in expect and toBe methods.

We want to organize our code this way so we can easily expose them for testing.

Also, they have no side effects so that they can be tested on their own without checking results on code that’s outside.

Conclusion

Code organization is important for writing robust JavaScript since it’s harder to break clean code. They shouldn’t be tightly coupled. Also, side effects should be eliminated as much as possible for easy testing and reasoning.

Finally, clever code should be avoided since they’re often hard to read.

Categories
JavaScript Best Practices

JavaScript Best Practices for Writing More Robust Code — Avoiding Bad Code

JavaScript is an easy to learn programming language. It’s easy to write programs that run and does something. However, it’s hard to account for all the uses cases and write robust JavaScript code.

In this article, we’ll look at some bad code that should be avoided if we want to write more robust JavaScript code.

Avoid Large Modules

Large modules are bad because they have too many members, which makes them hard to track and debug.

Longer pieces of code are also hard to read.

Modules should be small. For instance, we can have one module that only does mathematical operations.

We can write something like the following:

export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;

The code above is short and easy to read.

Avoid Modules With Multiple Responsibilities

Modules with multiple responsibilities are probably doing too much.

This violates the single responsibility principles which are bad because it’s confusing to have many different things going on in one piece of code.

Modules with multiple responsibilities are confusing for many people since they do too many things. It’s not logical to have one module to be doing more than one thing.

For instance, if we have:

export const add = (a, b) => a + b;
export const foo = () => console.log("foo");

then that’s bad because we have functions in a module that do multiple kinds of things.

We have an add function that adds 2 numbers, and another function that logs 'foo' .

This doesn’t make sense since it does multiple things. This makes using it harder since we’ve to look at it to find out what the module does.

If the module only does one thing and the module name suggests that it’s so, then people don’t have to look too hard to find out what a module is doing.

Avoid Tight Coupling

Tight coupling is bad because it’s easy to break code when we need to change it, which is inevitable.

To avoid tight coupling, we should avoid exposing too many members from a module to the outside.

When 2 modules are tightly coupled, this means that 2 classes have to change together.

On the other hand, loose coupling of modules means that they’re mostly independent.

Other entities that may be tightly coupled include classes and functions. For instance, if we have the following code:

index.js

import { greet } from "./module";
export class Person {
  constructor(name) {
    this.name = name;
  }

  greet(greeting) {
    greet(`${greeting} ${this.name}`);
  }
}

module.js

import { Person } from "./index";
export const greet = greeting =>
  console.log(`${greeting} ${new Person("foo")}`);

In the code above, we have the greet function outside index.js and we imported Person in the greet function. In index.js , we have the Person class that imported the greet function from module.js .

This kind of dependency structure is too tightly coupled because Person depends on greet and greet depends on Person .

When one changes, we’ve to worry if it breaks the other, which isn’t good since it makes our code more fragile and slows us down when we try to make changes.

It’s better for them to be independent. If we don’t need them to be dependent on the other, then we should eliminate that dependency.

For instance, we can write the following:

index.js

class Person {
  constructor(name) {
    this.name = name;
  }

  greet(greeting) {
    console.log(`${greeting} ${this.name}`);
  }
}

module.js

export const greet = greeting => console.log(greeting);

In the code above, we kept them independent by eliminating the imports and referencing of the dependencies.

This is much cleaner and we don’t have to worry about breaking things outside of the code the module the items are in since they don’t depend on each other.

Avoid Magic Numbers

Magic numbers are numbers that occur in multiple places with an unexplained meaning. They’re often used as constants.

Since they’re used as constants, they should be replaced with named constants.

For instance instead of writing the following:

const foo = 1;
const bar = 1;
const baz = 1;

We should use a named constant instead of 1. For instance, we can write the following:

const CONSTANT = 1;
const foo = CONSTANT;
const bar = CONSTANT;
const baz = CONSTANT;

This way, we know that 1 is constant and give it meaning. Constant names in JavaScript are usually upper-case to make it clear that it’s a constant.

Conclusion

To write robust JavaScript, we should create small modules that only does one thing.

Tight coupling between entities should be eliminated. Finally, magic numbers should be avoided and should be replaced with constants.

Categories
JavaScript Best Practices

JavaScript Best Practices for Writing More Robust Code — Error Prevention

JavaScript is an easy to learn programming language. It’s easy to write programs that run and does something. However, it’s hard to account for all the uses cases and write robust JavaScript code.

In this article, we’ll look at ways to write more robust code when dealing with JSON and best practices when writing code to handle errors better and to prevent them from happening.

Use try…catch When Using JSON.parse or JSON.stringify

JSON.parse and JSON.stringify will throw errors if they encounter issues.

Whenever JSON.parse encounters invalid JSON in a string, it’ll throw an error. JSON.stringify throws errors when it tries to convert a circular structure to JSON.

Therefore, we should use try...catch to wrap around JSON.stringify and JSON.parse to prevent errors from stopping our program from running.

For instance, we should write something like:

try {  
  const json = '{}';  
  const parsed = JSON.parse(json);  
} catch (ex) {  
  console.error(ex);  
}

so that JSON.parse won’t crash our program when it runs into issues parsing JSON. We can also replace JSON.parse with JSON.stringify for code that uses that.

Use ESLint or Another Linter to Catching Errors Early

ESLint is a standard linter for JavaScript. It checks for syntax errors and confusing code to prevent developers from committing many kinds of problematic code or potential bugs.

It has a big list of rules which check for possible errors or useless and confusing code.

For instance, it checks for return statements in getters. This because there’s no point in having a getter that doesn’t return anything in a JavaScript or class. A getter that returns nothing is useless and it’s probably a mistake if it’s there.

Other things include disallowing the assignment operator in conditional expressions, as we probably want to use == or === to compare things instead and we forgot the extra equal sign.

There’re many more rules located at https://eslint.org/docs/rules/.

It’s easy to set up for any project. We can just install eslint in our project folder by running:

npm install eslint --save-dev

Then we create ESLint configuration file by running:

npx eslint --init

to customize the rules that we want to enable. It’s very flexible and we don’t have to enable checks for all the rules.

It also has lots of plugins to add more rules. Popular rules include Airbnb and the default rules. We can also include Node.js rules, Angular, React, Vue, etc.

Don’t Mess With Built-in Object Prototypes

We should never mess with prototypes of built-in global objects. Objects like Object , String , Date , etc. all have instances methods and variables in their prototypes which shouldn’t be messed with.

If we change them by mistake, then our code probably won’t work the way we expect them to since they often call instance methods from these built-in objects and manipulating them in our code will probably break our code.

The member of native objects may also have name collisions with members in our own code.

It’s also confusing since if we change the built-in object’s prototypes, a lot of people may think that it’s actually a method that’s part of the standard library.

We don’t want people to make that mistake and write more bad code and create more issues down the road.

Therefore, we should never modify built-in objects and their prototypes.

If we need any new functionality that built-in native objects don’t provide, then we should write our own code from scratch and reference built-in native items if necessary.

Also, if we want to use new native methods that don’t exist in the browser your app is targeting, then we can use polyfills to add that functionality instead of implementing it from scratch ourselves.

Photo by Sean McGee on Unsplash

Always Use Strict Mode

JavaScript used to let people do a lot of things that people aren’t supposed to do.

Strict mode throws errors when we write code that isn’t supposed to be written, like assign null or undefined with a value, or accidentally creating global variables by omitting var , let or const .

Other things that throw errors include trying to extend objects new properties that have the Object.freeze method applied to it.

For instance, the following will do nothing without strict mode:

const foo = {};  
Object.preventExtensions(foo);  
foo.newProp = 'foo';

However, with strict mode on:

'use strict'  
const foo = {};  
Object.preventExtensions(foo);  
foo.newProp = 'foo';

We’ll get an error ‘Uncaught TypeError: Cannot add property newProp, object is not extensible’.

It also prohibits us from using keywords and constructs that may be used in future versions of JavaScript. For instance, we can’t declare a variable called class since it’s a reserved keyword.

Strict mode is applied to all JavaScript modules by default. However, old-style scripts don’t have strict mode on by default. Therefore, we should make sure that those have strict mode on by adding 'use strict' to the top of our code.

We can also add 'use strict' inside a function, but we definitely want strict mode everywhere so we should just put it on top of the script file.

Since strict mode prevents us from committing so many kinds of errors, we should always have it on.

Conclusion

Preventing JavaScript code errors is easy with ESLint and strict mode. They prevent us from making so many kinds of errors that it’ll save us a lot time from debugging bad code.

Also, we should use try...catch to catch errors when parsing and stringifying JSON.

Categories
JavaScript Best Practices

JavaScript Best Practices for Creating Objects

JavaScript is an easy programming language to learn. It’s easy to write programs that run and do something. However, it’s hard to account for all the use cases and write robust JavaScript code.

In this article, we’ll look at some best practices for writing robust JavaScript code.


Use Factory Functions

Factory functions are functions that return a new instance of a constructor or class.

We can use them to create objects without writing any code with the new keyword to instantiate classes or constructors.

Constructors are often a confusing part of JavaScript and definitely one we can avoid if we wish to.

For instance, we can make our own factory function as follows:

In the code above, we have the createPerson factory function that takes a firstName and lastName parameter and returns an object with the firstName, lastName, and the fullName method.

We used an arrow function so that we don’t get confused with the value of this that’s in the returned object. Since arrow functions don’t bind to this, we know that the value of this in fullName is the returned object.

Factory functions can return objects with anything, so the possibilities are endless.

To use our createPerson factory function, we can write the following code:

const person = createPerson('Jane', 'Smith');
const fullName = person.fullName();

We created a person object with the createPerson function and then called the fullName method on it.

Then we get that fullName is ‘Jane Smith’ since this references the person object.

Many JavaScript functions like Number and Boolean are factory functions. They take any object as an argument and then return a number or boolean, respectively.

It makes our JavaScript code more robust because we don’t have to worry about class or constructor instances. We just have to think in terms of objects and composing functions.

Composing functions makes code more reusable and testable, creating more robust code because of this.


Create Instance Methods for Constructors by Attaching to the prototype Property

When we want to create instance methods of a constructor, we should attach the methods to the prototype property of the constructor.

This way, when we instantiate the constructor, we can also call the methods on the instance.

A method that’s attached directly to the function is a static method that’s shared by all methods.

For instance, we can add instance methods to a constructor by attaching it to its prototype property as follows:

In the code above, we created a Fruit constructor that returns a Fruit instance. Then we added the grow instance method by writing:

Fruit.prototype.grow = function() {
  console.log(`${this.name} grew.`);
}

Then when we instantiate it as follows:

const fruit = new Fruit('apple');
fruit.grow();

Instance methods encapsulate methods inside the constructor instance, preventing it from being exposed to outside code and allowing it to make accidental changes.

Therefore, this makes our code more robust. Also, every constructor has its own responsibility since it has its own instance method. This prevents multiple constructors from doing different things to the same object.

The alternative (above) creates a copy of the grow instance method for each instance. The method isn’t cached, so it’s slower to use attach instance methods this way.


Use the .type Property to Create Factory Functions That Can Create Multiple Types of Objects

Since factory functions can be composed, we can create a factory function that can create multiple types of objects.

We can differentiate between them with the type property, which is a conventional way to distinguish between different types of objects that we want to create.

To do this, we can write the following code:

In the code above, we have the createPet factory function that calls the createDog or createCat factory function depending on what kind of pet type we pass into createPet.

We also composed factory functions by calling a factory function inside the createPet factory function.

Now we just have to worry about one factory function (createPet) instead of using multiple factory functions to create different kinds of objects. This hides the complexity that’s underneath the code and thus there’s less risk of breaking things when we make changes.


Conclusion

With factory functions, we can create them to create new objects. We can also compose them and call different ones within one factory function to do different things.

When we have a constructor function, we should attach instance methods to the prototype property of the constructor function so that they don’t have to be recreated all the time.