Debugging Tips for Node.js

‘This is supposed to work’. Every developer has felt this way countless times when building applications. Things don't always work as expected, and this is usually due to one error or the other. It could be a syntax error (about which Node.js would yell at you during compilation) or could be a logical error (the expected result is not achieved, Node.js knows nothing about this, so it won't yell).

While some errors are very descriptive (and clearly inform you what went wrong), some are not. It's our responsibility as developers to dig deep to the cause of the problem (logging things to the console, temporarily deleting lines, and so on). Our applications must work perfectly.

In this article, we'll look at debugging tips (more than console.log) for Node.js applications to help us discover why things aren't working the way they should.

What Is Debugging?

Debugging is the act of removing bugs from an application or software. These bugs can be generated at different points in time in the application's execution.

Debugging an application in development mode comes with fewer worries but a bug in an application in production comes with the fear of ruining the user's experience. However, there are effective approaches to debugging in production.

Tips for Debugging Node.js Applications

1. Leveraging the Debugger Tool

Instead of applying console.logs in various parts of your application (some which may never be reached) to discover where a bug is coming from, you can use debugger in Node.js to create breakpoints. 

When Node.js comes across such breakpoints, it pauses, retaining the state of the application at that time. Let's see that in action.

Say we have a file called test.js with the following code:

console.log('hello')

function hi() {

    debugger;

    consol.log('hi')

    debugger;

}

hi();

console.log('hi')

To run this file with Node.js, run the following command:

node inspect test.js

The inspect command would work with the debugger statements. Without inspect, the code would run as it normally should.

The expected results are:

1. Beginning statement

This is the beginning of the application. Upon entering `cont` (which means continue execution) Node.js prints out 'hello', then stops at the first breakpoint. See that in the next process.

2. The first debugger

Upon entering cont again, Node.js attempts to continue execution.

3. Getting to the second debugger

And then, the reference error.

This is a very small example and it's a syntax error, but it shows how the tool works. This tool can also be used for logical errors in which you'll place the debugger at positions where you want to know the current state of the application.

2. Debugging in Chrome

Debugging is easier on web browsers compared to the terminal. The web browser has more features with a usable GUI (the Dev tools) to properly track requests, create breakpoints, and do many debugging strategies.

Node.js provides us with that feature. To achieve this, the --inspect flag is used. Do not mistake this for inspect above which creates an interactive shell on the terminal. You can learn more about the flag in Node.js documentation.

3. Apply Tests to Your Applications

Adding tests is stressful. Most of it involves almost recreating the whole application - determining user interactions and the results gotten, validations, and a lot more. But, the benefit outweighs the stress. 

With tests, developers can specify ways in which the application should work. This specification would be very helpful during debugging as it would help the developers easily.

Say, for example, a developer adds a new code supposedly to add a new feature and that feature complicates the application in some way. With tests, it would be easy to detect the source of the new bug experienced.

There are various unit testing frameworks to help get started with applying tests to your application. Also, end-to-end tests are a great testing strategy on Node.js applications.

4. Use Logs

Logs here are more than console.logs. You can use other console methods to clearly state the kind of message or display the log in a different format. An example is putting a console.error in a catch block to clearly signify that some operation couldn't be carried out.

Logs can be used for various reasons - analysis of how an application runs, tracking states in the application and also debugging. For an application in production, it becomes harder to watch or manage your logs as you'll always need to sign in into the server where your application is hosted and evaluate the messages logged.

Thankfully, there are logging management tools like Rookout that help manage your logs and send them to a specified location.

Here's an image that describes logs and target locations:

5. Use IDEs to Make Your Life Easier

There are a lot of editors with different features and they are continuously getting better. Some of them (like Visual Studio Code) provide debugging features for Node.js applications. With some configurations, extensions, and commands, you can easily interact with Node.js application during runtime and discover potential or critical errors.

Rookout also has a web-based IDE with many features for debugging, including non-breaking breakpoints. The image below shows a brief usage of the IDE:

From the image, you’ll notice how quick it is to add breakpoints in your application and log different messages without having to alter your code (adding console.log s) at all. This makes debugging much easier. 

Conclusion

Bugs are unexpected results in an application and debugging can be tedious, but as developers we want to deliver the best tools for our users. Putting the above tips into use is a great start to ensuring error-free applications.

Disclaimer:  I received a request to try Rookout’s debugging tool. The fact I got it this request has not influenced the review in anyway.