Common Mistakes That Node.js Developers Make
Node.js gave us cutting-edge web applications with two-way, real-time connections where both the client and server could communicate with each other. A stark contrast to the conventional web response paradigm where only the client initiates communication. It’s quite similar to what Ruby On Rails and ASP.NET have to offer. Powered by Google’s extremely fast V8, it leverages JavaScript, the lightweight built-in web server as the primary language and has a plethora of Plugins managed through the Node Package Manager, allowing one to custom-build applications to meet their needs. Most of this sounds like any other good technology, but it comes with certain features which have made it a popular choice among developers to build a broad spectrum of web applications.
Now what we often tend to overlook in the debate around the advantages and disadvantages of different programming languages is that most of the criticism revolving around certain issues stems from the incorrect use of the language. Often the criticism is centered around safe code writing practices and how complicated Node.js can get. Even so, the platform has been around for a while and has been used to build a huge number of sophisticated and robust web services. However, like any other platform, Node.js is susceptible to developer issues and problems. Today, we will take a look at some of the common mistakes developers new to Node.js often make.
Common Mistakes That Node.js Developers Make
1. Blocking the event loop
Being a single-threaded environment, no two parts of your application can run in parallel. Simply put, since Node.js runs on a single thread, anything which blocks the event loop, blocks everything. Here, concurrency is achieved by handling input-output operations asynchronously. For example, what allows Node.js to focus on some other part of the application is a request to the database engine, from Node.js to fetch some document. However, all it takes to block the event loop is a piece of CPU-bound code in a Node.js instance with many clients connected, making all the clients wait. There is no clear-cut solution to this problem, other than to address each case individually. The primary idea is to not do CPU intensive work within the front facing Node.js instances, the ones clients connect to concurrently.
2. Invoking callbacks, multiple times
JavaScript is known to rely on callbacks. Back in the day, callbacks were the only way asynchronous elements of your code communicated with each other in Node.js, until promises came into the picture. Package developers still design their APIs around callbacks, and so callbacks are still very much in use. A common mistake developers make while using callbacks is calling them more than once. See, a callback is not the end point of the current function. Some developers choose to add a return before the call back to avoid multiple invocations. In most functions that are asynchronous, the return statement has almost no significance and so helps in avoiding this problem. Keeping an eye out for this error is all it takes to avoid it.
3. Call backs don’t run synchronously, don’t expect them to
Asynchronous programming with callbacks isn’t unique to JavaScript and Node.js. Nevertheless, they have a huge hand in its popularity. We are used to the predictable order of execution with other programming languages, where unless an instruction is given to jump between statements, two statements will execute one after another. Even so, these are often limited to conditional statements, function invocations, and loop statements. Now in JavaScript, with callbacks a particular function, probably won’t run well until the task it’s waiting on is finished. The current function will execute and run until the end without stopping. Node.js developers have to ensure, the next task which has to happen after the call, has to be invoked from within it.
4. Asynchronous error handling
It looks like callbacks are to blame for most issues. Again, the problem here is with asynchronous behavior. See, if the V8 engine is the heart of your Node.js, callbacks are the veins enabling a balanced, non-blocking flow of asynchronous control across modules and applications. The “error-first” callback protocol was introduced to ensure callbacks could work at scale. Now, JavaScript the language behind it can throw and catch exceptions in try-catch blocks. But, in an asynchronous situation, try-catch will not behave as you expect it to. If for instance, you want to protect a huge chunk of code with lots of asynchronous activity with one big try-catch block, it might not work. You see the scope containing the try-catch block might’ve long gone out of context for it to be still, able to catch the errors thrown from inside the callback. This is why most Node.Js developers follow the pattern for all the arguments to the callback function, wherein the first argument of all callbacks is reserved for an error object.
5. Deeply nesting callbacks
Or “callback hell” as it is often referred to is not just a Node.js issue. The more complex the task is, the worse the issue can get. By nesting callbacks in such a way, we end up with hard to read, error-prone, and hard to maintain code. Hence, most use “callback hell” as a key point in disfavor of Node.js, but most of these people see callback nesting as unavoidable. But you see, this is not the case. There are enough solutions out there to keep your code nice and tidy, such as using control flow modules like async, promises and generators.
6. Using console.log for debugging purposes
In Node.js, “console.log” lets you print just about anything to the console. It will print any object you pass it as a JavaScript object literal. It accepts and prints any arbitrary number of arguments, all neatly space-separated. So we understand why as a developer when something goes bad it's tempting just to insert console.log in some places and debug. Once you’ve figured out the problem, you can remove the console.log debugging leftovers and move on. The problem here is the next developer, who might just be you, might come along and repeat the process. This is why modules like debug exist. Make use of the debug function instead and just leave it there instead of inserting and deleting “console.log.” When the next developer tries to figure out the problem, he or she just start the application using the DEBUG environment variable.
7. There isn't any integer data type in JavaScript
Numbers are floating points in JavaScript. Numbers big enough to strain the limits of float are not usually encountered, so you wouldn’t expect this to be a problem. Which is exactly when mistakes related to this end up happening. The moment the limits of the float are breached, trouble beings and calculations go wrong. Moreover, the operators work differently with floats and integers. Keeping this in mind could ensure you don’t have a problem with the way your function is supposed to work and get the desired results. You might not be dealing with large numbers often, but if you do, there are enough big integer libraries, which implement the necessary mathematical operations on large precision numbers.
8. Not testing religiously
Your application isn’t done if you haven’t written any tests for it. It’s in the rule book, and there’s no excuse for skipping this one, considering the many tools which exist to make the process easier. In case you are not sure how to get started with writing tests you can either browse popular Node projects on Github or find tutorials online.
9. Zero monitoring or profiling
Not monitoring or profiling a Node applications leaves you in the dark. A supervisor program monitor which can orchestrate your program is a highly useful thing to have whether your Node.js code is in production mode or running in your local development environment. There are proprietary services which take care of this stuff for you, such as the ones from New Relic, StrongLoop or Concurix, AppDynamics. Whatever you choose make sure you are always aware of the status of your application at all times.
Our product development experts are eager to learn more about your project and deliver an experience your customers and stakeholders love.