@jan_grz Blog

How to help the IDE help you do your job

August 10, 2016

3 simple tips to improve your Javascript experience

A powerful IDE is a great tool, it can boost your productivity, and provide useful insights. In some languages, like Java, writing code without an IDE is nearly impossible. Dynamic languages, including JavaScript are a harder material for an IDE. Fortunately Node.js code can benefit from nearly all the important IDE blessings, such as navigating between components, detecting usages, refactorings and even finding trivial bugs, here are some tips how to leverage the full power of the IDE.

Rule 1: Do not play with require or import - be predictable with it.

This rule will help you jumping between modules and finding usages. Put all your dependencies on the top of the file, and try to put the exports at the end. Using require or import anywhere else than on top is strange and probably not very wise. Always use a string literal inside require or import.


/**
 * Read directories
 */

var fs = require('fs');
var path = require('path');
//...
fs.readdirSync(dirPath).forEach(function (file) {
    var job_fname = dirPath + '/' + file;
    var job_name = path.basename(job_fname, '.js');

    exports[job_name] = require(job_fname); //HAHA! CHECKMATE IDE!
});

*This is a very bad example from a real project. The author was using require in the middle of the file, inside a for loop, and with a variable instead of a string literal - it made the whole module practically unreadable for the IDE.*

The problem could be solved by using a package like indexr.


Avoid writing any kind of wrapper for require or import that changes paths origin - it may be tempting to use something like this to get absolute paths in your project instead of relative paths full of ../.., but it will make the IDE completely blind (I have also seen it). If you see too long chains of ../.., it probably means that your project has a problem with modularity and should be split into smaller parts.


Choose names for your files wisely. Avoid index.js - it would make refactorings painful. Try to make the file names unique in the project - it would be easier to navigate. So if your customer code is named /routes/customer.js don’t name your tests like thistest/routes/customer.js - something like test/routes/customer_test.js would be much better.

Rule 2: Use object properties, methods or symbols instead of string literals

Magic strings, especially event names, can be a real pain. If you try to find or refactor them you will end up messing with file names, comments and templates.


const events = {
    /**
     * Emitted when underlying connection died
     */
    error: 'error',

    /**
     * Emitted when data is ready to read
     */
    data: 'data',

    /**
     * Emitted when connection has been established
     */
    connected: 'connected'
};


Container.on(events.data, (data)=>{
    //
});

Gather your events into an object and use them as properties. It would be much easier to document the events, refactor their names and also find any usages.


Here is an interesing example from Make it discrete and processable chapter of the excellent article by Christian Mackeprang on Congnitive Load of Code

ServiceLocator.get('CustomerService'); // bad

If you give away the dynamic nature of ServiceLocator and write it in more fixed way, with well named and type-annotated functions that return your Services - the IDE will let you navigate to the service, and see who else is using it.

class ServiceLocator {
    /**
     * @returns {CustomerService} service;
     */
    getCustomerService() {  // good
        return customerServiceInstance;
    }
}

Rule 3: Embrace the power of JSDoc

Properly used JSDoc will give you some of the benefits of static typing without the pains. Documented code will be easier to call and refactor, and foremost more understandable for both your colleagues and the IDE. I highly recommend using types to annotate function parameters, this way you can catch many trivial bugs.

JSDoc helps detect type mismatch Here JSDoc &IDE help you detect that invalid type is passed


IDE can check types of params and give you instant feedback, it is also smart enough to generate the JSDocs, so all you have to do is fill in some types.

JSDoc helps detect invalud number of arguments Here JSDoc & IDE remind you that you have forgotten one parameter


Documenting documenting the callback types is also a good idea, especially of the functions that are going to be public in given module.

Callback type annotation JSDoc allows you to detect bugs while writing code


Finally, you can declare custom types, for example for objects that are used in many places in the same module. Documenting a custom type’s properties will allow you tab completion and type checking.

Custom types Tab-completion will speed you up and help avoid typos

Summary

Ariadne and Theseus

The IDE will be your guide when you most need it.


Jan Grzesik- a Team Lead, Full Stack Engineer, maker - living in Kraków, Poland

Copyright © 2022