[go: up one dir, main page]

DEV Community

Cover image for Guide for the daily JavaScripter
Damian Cipolat
Damian Cipolat

Posted on

Guide for the daily JavaScripter

Guide for the daily JavaScripter

This document is a summary of good programming practices in js in general.

Part of the document is based in Airbnb guideline, and other in profesional experience.

https://github.com/airbnb/javascript

The NODE.JS section is a summary of different readings and my own experience in the tecnology.

Content list

NODE.JS

Paradigm - FP

Javascript is a multiparadigm programming language. While we could make a mix of paradigms in our code is better, focus on just one. The trend today is to focus on functional programming, both to develop a frontend or a backend.

These are some functional programming principles that are useful to know.

  1. Thinks in functions
  2. Lambda
  3. Curry
  4. Stateless
  5. Composing functions
  6. pure functions:
  7. Side effects
  8. Functor
  9. High order functions
  10. First class
  11. Mutations

👉 To continue reading about FP, go to this link:
https://github.com/damiancipolat/Functional_programming_in_JS

⮬ back to top

Naming conventions

How to name objects in js.

Based in the Airbnb guide points: 23.1, 23.2, 23.3, 23.6

  • Avoid single letter names. Be descriptive with your naming.

    // bad
    function q() {
    }
    
    // good
    function query() {
    }
    
  • Use camelCase when naming objects, functions, and instances.

    // bad
    const OBJEcttsssss = {};
    const this_is_my_object = {};
    function c() {}
    
    // good
    const thisIsMyObject = {};
    function thisIsMyFunction() {}
    
  • Use PascalCase only when naming constructors or classes.

    // bad
    function user(options) {
      this.name = options.name;
    }
    
    const bad = new user({
      name: 'nope',
    });
    
    // good
    class User {
      constructor(options) {
        this.name = options.name;
      }
    }
    
    const good = new User({
      name: 'yup',
    });
    
  • Use uppercase only in constants.

    // allowed but does not supply semantic value
    export const apiKey = 'SOMEKEY';
    
    // better in most cases
    export const API_KEY = 'SOMEKEY';
    

⮬ back to top

Semicolons

Based in the Airbnb guide points: 21.1.

Why? When JavaScript encounters a line break without a semicolon, it uses a set of rules called Automatic Semicolon Insertion to determine whether or not it should regard that line break as the end of a statement, and (as the name implies) place a semicolon into your code before the line break if it thinks so. ASI contains a few eccentric behaviors, though, and your code will break if JavaScript misinterprets your line break. These rules will become more complicated as new features become a part of JavaScript. Explicitly terminating your statements and configuring your linter to catch missing semicolons will help prevent you from encountering issues

```javascript
// bad
function foo() {
  return
    'search your feelings, you know it to be foo'
}

// good
const luke = {};
const leia = {};
[luke, leia].forEach((jedi) => {
  jedi.father = 'vader';
});
```

⮬ back to top

Comments

Standarize js comments in your projects. Visualstudio code recognize this format.

Use JSDOC https://jsdoc.app/about-getting-started.html format.

  • Use block comment.

    /** This is a description of the foo function. */
    function foo() {
    }
    
  • Use JSDOC tag to describe a function.

    /**
    * Represents a book.
    * @constructor
    * @param {string} title - The title of the book.
    * @param {string} author - The author of the book.
    */
    function Book(title, author) {
    }
    

⮬ back to top

Promises.

Change the way to handle callbacks.

  • If you work with callback styled function, wrap it in a promise:
  function doAsync(function(err, data) { 
    if (err) {
      // error
    } else {
      // success
    }
  });
  • With Promises:
const doAsyncPomise= () =>{

    return new Promise((resolve,reject)=>{

        if (err)
            reject(err);
        else
            resolve(..);

    });

}

⮬ back to top

Error handling

Different ways of handle errors.

  • Using sync functions:
  try{
      makeSomething();
  } catch(err){
      rollBack();
  }
  • Using a function that return promise:
  makeSomething()
      .then(data=>{
          //....
      })
      .catch(err=>{
          rollback(...)
      });
  • Using into a async/await function:
  const run = async ()=>{

      try{
          const result = await makeSomething();
      } catch(err){
          rollBack(..)
      }

  };
  • Avoid to return "error structures" to comunicate an error, is better to launch an exception.
    //bad
    const run = (param)=>{

      const result = makeSomething(param);

      if (result){
          return result;
      } else {
          return {
              error:'processing error'
          };
      }
  }

  //good
  const run = (param)=>{

    if (!param)
      throw new Error('Bad parameters');

    const result = makeSomething(param);

    if (!result)
      throw new Error('Processing error');

    return result;

  }

⮬ back to top

Comparision

Improve your comparision methods.

Based in the Airbnb guide points: 15.1, 15.2, 15.3, 15.5, 15.6, 15.7

  • Use === and !== over == and !=.
  • Conditional statements such as the if statement evaluate their expression using coercion with the ToBoolean.
    https://github.com/airbnb/javascript/blob/master/README.md#comparison--if

    if ([0] && []) {
      // true
      // an array (even an empty one) is an object, objects will evaluate to true
    }
    
  • User shorcuts for booleans.

    // bad
    if (isValid === true) {
      // ...
    }
    
    // good
    if (isValid) {
      // ...
    }
    
  • Ternaries should not be nested and generally be single line expressions.

    // bad
    const foo = maybe1 > maybe2
      ? "bar"
      : value1 > value2 ? "baz" : null;
    
    // split into 2 separated ternary expressions
    const maybeNull = value1 > value2 ? 'baz' : null;
    
    // better
    const foo = maybe1 > maybe2
      ? 'bar'
      : maybeNull;
    
    // best
    const foo = maybe1 > maybe2 ? 'bar' : maybeNull;
    
  • Ternaries should not be nested and generally be single line expressions.

    // bad
    const foo = a ? a : b;
    const bar = c ? true : false;
    const baz = c ? false : true;
    
    // good
    const foo = a || b;
    const bar = !!c;
    const baz = !c;
    

⮬ back to top

Iterations

Handle the lopps in a functional style.

Based in the Airbnb guide points: 11.1

  • Don’t use iterators, prefer js higher-order functions instead of for / for..in

    // bad
    const increasedByOne = [];
    for (let i = 0; i < numbers.length; i++) {
      increasedByOne.push(numbers[i] + 1);
    }
    
    // good
    const increasedByOne = [];
    numbers.forEach((num) => {
      increasedByOne.push(num + 1);
    });
    

⮬ back to top

Functions

How to handle functions in a modern way.

Based in the Airbnb guide points: 7.1, 7.5, 7.6, 7.7, 7.10, 7.12, 7.13

  • Use named arrow function expressions instead of function declarations.

    // bad
    function foo() {
      // ...
    }
    
    // bad
    const foo = () => {
      // ...
    };
    
  • Never name a parameter arguments..

        // bad
        function foo(name, options, arguments) {
          // ...
        }
    
        // good
        function foo(name, options, args) {
          // ...
        }
    ``
    - Never use arguments, opt to use rest syntax ... instead. 
    


    javascript
    // bad
    function concatenateAll() {
    const args = Array.prototype.slice.call(arguments);
    return args.join('');
    }

    // good
    function concatenateAll(...args) {
    return args.join('');
    }
    ``

  • Avoid side effects with default parameters..
    `javascript
    const b = 1;
    // bad
    function count(a = b++) {
    console.log(a);
    }
    count(); // 1
    count(); // 2
    count(3); // 3
    count(); // 3

    • Never mutate parameters. `javascript // bad function f1(obj) { obj.key = 1; }

    // good
    function f2(obj) {
    const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1;
    ``

⮬ back to top

String

Best way to handle strings.

Based in the Airbnb guide points: 6.1, 6.2, 6.3, 6.4

  • Use single quotes '' for strings, don't mix with "".

    // bad
    const name = "Bart";
    
    // bad - template literals should contain interpolation or newlines
    const name = `Marge`;
    
    // good
    const name = 'Homer';
    
  • Use template string instead of concatenate string with values.

    const name    = 'Bart';
    const surname = 'Simpson';
    
     // bad
    const txt = 'hello mr. '+name+',  '+surname';
    
    // good
    const txt = `hello mr. ${name},  ${surname}`;
    ``
    **[⮬ back to top](#table-of-contents)**
    

Destructuring

Destructuring simply implies breaking down a complex structure into simpler parts.

Based in the Airbnb guide points: 5.1, 5.2, 5.3

  • Use destructuring when accessing and using multiple properties of an object.

    
    javascript
    // bad
    function getFullName(user) {
      const firstName = user.firstName;
      const lastName = user.lastName;
    
      return `${firstName} ${lastName}`;
    }
    
    // good
    function getFullName(user) {
      const { firstName, lastName } = user;
      return `${firstName} ${lastName}`;
    }
    
    
    
  • Use array destructuring.

    
    javascript
    // bad
    const first = arr[0];
    const second = arr[1];
    
    // good
    const [first, second] = arr;
    ``
    **[⮬ back to top](#table-of-contents)**
    

Arrays

Array manipulation practices.

Based in the Airbnb guide points: 4.1, 4.3, 4.4, 4.7

  • Is important to know this array prototypes: map, reduce, forEach, filter, find, push, pop, slice. https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Array/prototype
  • Use the literal syntax for array creation.

    `javascript
    // bad
    const items = new Array();

    // good
    const items = [];
    `

    • Use array spreads ... to copy arrays: `javascript // bad const len = items.length; const itemsCopy = []; let i;

    for (i = 0; i < len; i += 1) {
    itemsCopy[i] = items[i];
    }

    // good
    const itemsCopy = [...items];
    `

    • To convert an iterable object to an array, use spreads ... instead of Array.from. `javascript // bad const items = new Array();

    // good
    const items = [];
    `

    • Use array spreads ... to copy arrays: `javascript // bad const len = items.length; const itemsCopy = []; let i;

    for (i = 0; i < len; i += 1) {
    itemsCopy[i] = items[i];
    }

    // good
    const itemsCopy = [...items];
    `

    • Use return statements in array method callbacks: `javascript // bad inbox.filter((msg) => { const { subject, author } = msg; if (subject === 'Mockingbird') { return author === 'Harper Lee'; } else { return false; } });

    // good
    inbox.filter((msg) => {
    const { subject, author } = msg;
    if (subject === 'Mockingbird') {
    return author === 'Harper Lee';
    }

    return false;
    });
    `

⮬ back to top

Objects

Some tips of how to improve the object manipulation.

Based in the Airbnb guide points: 3.1,3.3,3.4,3.6,3.8

  • Use the literal syntax for object creation.
    `javascript
    // bad
    const item = new Object();

    // good
    const item = {};
    `

  • Use object method shorthand.
    `javascript
    // bad
    const atom = {
    value: 1,

    addValue: function (value) {
    return atom.value + value;
    },
    };

    // good
    const atom = {
    value: 1,

    addValue(value) {
    return atom.value + value;
    },
    };
    `

  • Use property value shorthand.
    `javascript
    const bart = 'Bart Simpson';

    // bad
    const obj = {
    bart: bart,
    };

    // good
    const obj = {
    bart,
    };
    `

  • Only quote properties that are invalid identifiers in the example is 'bla-bla'.
    `javascript
    // bad
    const bad = {
    'foo': 3,
    'bar': 4,
    'data-blah': 5,
    };

    // good
    const good = {
    foo: 3,
    bar: 4,
    'bla-bla': 5,
    };
    `

  • If you need to access dinamycali to one object atributte:
    `javascript
    const person = {
    name:'Damian',
    age:32
    };

    const key = 'age';
    console.log(person[key]);
    `

  • Prefer the object spread operator over Object.assign to shallow-copy objects:
    `javascript
    // bad
    const original = { a: 1, b: 2 };
    const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }

    // good
    const original = { a: 1, b: 2 };
    const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }
    `

⮬ back to top

Properties

Based in the Airbnb guide points: 12.1, 12.2

  • Use dot notation when accessing properties.

    `javascript
    const luke = {
    jedi: true,
    age: 28,
    };

    // bad
    const isJedi = luke['jedi'];

    // good
    const isJedi = luke.jedi;
    `

    • Use bracket notation [] when accessing properties with a variable: `javascript const person = { name:'Damian', age:32 };

    const key = 'age';
    console.log(person[key]);
    `

⮬ back to top

Primitives

The basic type data provided in js.

Based in the Airbnb guide points: 1.1

When you access a primitive type you work directly on its value.

  • string
  • number
  • boolean
  • null
  • undefined
  • symbol

⮬ back to top

Variables

Some points of how to handle and declare variables in javascript.

Based in the Airbnb guide points: 2.1, 2.2, 13.1, 13.2, 13.3, 13.4, 13.5, 13.8

  • Avoid to use global variable in the projects.
  • Avoid use var in variable declaration, use const.
  • If you must reassign references, use let instead of const.
  • Group all your const and then group all your let.
  • Remove unused variables.

    `javascript
    // bad
    var a = 1;
    var b = 2;

    // good
    const a = 1;
    const b = 2;

    // bad
    var count = 1;
    if (true) {
    count += 1;
    }

    // good, use the let.
    let count = 1;
    if (true) {
    count += 1;
    }

    // bad
    superPower = new SuperPower();

    // good
    const superPower = new SuperPower();
    `

⮬ back to top

TL;DR;

Don't use:

  • No global vars.
  • Declare variables using "var".
  • Declare functions using "function" keyword.
  • Avoid use "for" in loops.
  • Array push, inmutability.
  • Class.
  • Use delete to remove a object atribute.
  • Avoid nested if.
  • else if.
  • Heavy nesting https://www.w3.org/wiki/JavaScript_best_practices#Avoid_heavy_nesting.
  • Avoid to add prototype to functions that could be used in a module.

Use:

  • Common code in functions, follow D.R.Y principle.
  • Shorcut notation.
  • Spread operator over Object.assign (airbnb 3.8).
  • Pascal case naming.
  • Modularize your code in modules.
  • const and let!.
  • Literal syntax for object creation (airbnb 3.1).
  • Computed property names when creating objects (airbnb 3.2).
  • Property value shorthand (airbnb 3.4).
  • Group your shorthand properties at the beginning of your objec (airbnb 3.5).
  • use the literal syntax for array creation (airnbnb 4.1).
  • Use array spreads ... to copy arrays. (airbnb 4.3).
  • use spreads ... instead of, Array.from. (airbnb 4.4).
  • Use return statements in array method callbacks (airbnb 4.7).

⮬ back to top

NPM:

Some interesting tips and commands to use in npm.

#### npm init
Execute this command whenever you start a project from scratch

#### npm install {dependency} --save
Execute this command using the save parameter, when you need to install a new module, the save parameter record the dependecy in the package.json

#### npm install {dependency} --save--dev
Install a new dependency but only for development purposes, example unit testing.

#### npm install
Will install both "dependencies" and "devDependencies" from package.json.

#### npm install --dev
Run this command when you need to install only dev dependencys example into a ci/cd step to run test. Will only install "devDependencies" from package.json

#### npm install --production
Will only install "dependencies" from package.json.

#### npm audit
This command list all the security vulnerabilities of the dependencys installed in the package.json

#### npm audit --fix
Subcommand to automatically install compatible updates to vulnerable dependencies.

⮬ back to top

Package.json:

  • VERSION:

Use the version attribute to save the current project version follow the SEMVER rules, http://semver.org

`json
{
"name": "api",
"version": "1.0.0",
"description": "orders api",
"main": ""
}
`

SEMVER rules:
MAJOR: version when you make incompatible API changes.
MINOR: version when you add functionality in a backwards-compatible manner.
PATCH: version when you make backwards-compatible bug fixes.

  • DEPENDENCIES:

Make sure you are saving the dependencies modules in the "devDependencies" section.

  • SCRIPTS:

Its important to complete the script section of the package.json, the basic script should be:

`sh
npm start
npm test
npm deploy
`

⮬ back to top

Recommendations:

  • Use npm mayor / npm minor things change the versions.
  • Set NODENV in production.
  • Split common code in modules.
  • Don't use sync function for i/o;
  • Use streams.
  • Communicate error using exceptions.
  • Try/catch if you can solve the exception.
  • Good use of promises.
  • Promise.all to paralellize always
  • Wrap promise.all to avoid partial executions.
  • Async / await instead of promise.then
  • Don't use callbacksm replace them by Promise.
  • Avoid heavy nesting.
  • Avoid use else if.
  • Avoid nested if.
  • Avoid use global variables.
  • Don't abuse installing modules
  • Think first in use node core modules instead of search npm modules.
  • Create a logger wrapper instead of use console.log, (winston)
  • Create private npm modules for general purposes code used in different projects. Reutilizations.
  • Avoid the "core" patterns', the idea is avoid putting the entire business code of the application in a set of npm modules
  • Don't use class is better to focus in modules that export functions.
  • Externalize your config, make easy the test later.

Stacks:
Some recomendatios of modules.

  • For testing: Jest or Mocha / Chai / Proxyquire.
  • For logging: Winston.
  • For Api: Expressjs, Hapijs, Restify.
  • For SQL: Sequlize.
  • For Mongodb: Mongoose.
  • For Serverless: Serverless framework or AWS-CDK https://docs.aws.amazon.com/cdk/latest/guide/getting_started.html
  • For request: node-fetch or axios.
  • For time: moment / moment-timezone.
  • For lint: es-lint.
  • For schema validation: Joi

⮬ back to top

Have fun! 🛸🐧🐲👽👆👻👺

Top comments (7)

Collapse
 
thecodingalpaca profile image
Carlos Trapet

This is generally a good compilation, but a beginner would totally get lost in the amount of concepts, especially considering you don't explain what they are/what they mean. Consider providing links for them.

Also:

Async / await instead of promise.then

Why?? Is this based on any arguments or is it just something made up out of the blue?

I must strongly disagree, the only advantage async/await has over Promise chaining is that with async/await you can directly assign the value the promise resolves to, saving you a whopping line of code.

I personally prefer promise chaining as I find it much more flexible; maybe you don't want to pause code execution after all.

Collapse
 
mateiadrielrafael profile image
Matei Adriel

Wdym by pause code execution? Async await doesnt actually pause it everywhere, just in the function you call it from.

Collapse
 
damxipo profile image
Damian Cipolat

Thanks for the comment, for this documment I assume the developer has some of experience working in node.js the main idea is not a tutorial style. Is more a summary of best practices and code-style.

Collapse
 
jankapunkt profile image
Jan Küster

Thank you for this summary. I would like to read more on the functional paradigm but the link is broken in

👉 To continue reading about FP, go to this document.

would you mind checking and updating it?

Collapse
 
damxipo profile image
Damian Cipolat • Edited

yes sure! The link is broken, my bad. this is the link:
github.com/damiancipolat/Functiona...

Collapse
 
yasinaydinnet profile image
Ozgur Yasin Aydin • Edited

Very nice summary.

Btw I think instead of "Comparision" you meant "Comparison"?

Also, my DNS servers (Cloudflare & Google) can't resolve your website's domain, damiancipolat.com or www.damiancipolat.com .

3- Markdown seems to be broken after concatenateAll part.

Collapse
 
kimsean profile image
thedevkim

Thank youu! this will really help building up clean code.