Inspired by 5 Things You Should Stop Doing With jQuery by Burke Holland, I decided to open a discussion and highlight seven things you should immediately stop doing with Node.js:
- Stop using callbacks
- Stop using
*
for versions - Stop using
console.log
for debugging - Stop using
GET
andPOST
for everything - Stop using semicolons
- Stop using comma-first style
- Stop limiting your connections with default
maxSockets
value
Stop Using Callbacks in Node.js
Callbacks are the bread and butter (or the meat and veggies for paleo lifestyle readers) of the JavaScript/Node.js language and the main pattern. However, you should stop using callbacks for nesting code of multiple methods unless you want to end up with the Callback Hell.
Async is for the win. Particularly its series()
and waterfall()
methods.
To illustrate the drastic difference, here is an example in which we perform multiple operations with callbacks to find a user, then find posts that belong to the user:
codeA(function(a){
codeB(function(b){
codeC(function(c){
codeD(function(d){
// Final callback code
})
})
})
})
The series
example:
async.series([
function(callback){
// code a
callback(null, 'a')
},
function(callback){
// code b
callback(null, 'b')
},
function(callback){
// code c
callback(null, 'c')
},
function(callback){
// code d
callback(null, 'd')
}],
// optional callback
function(err, results){
// results is ['a', 'b', 'c', 'd']
// final callback code
}
)
The waterfall
example:
async.waterfall([
function(callback){
// code a
callback(null, 'a', 'b')
},
function(arg1, arg2, callback){
// arg1 is equals 'a' and arg2 is 'b'
// Code c
callback(null, 'c')
},
function(arg1, callback){
// arg1 is 'c'
// code d
callback(null, 'd');
}], function (err, result) {
// result is 'd'
}
)
Stop Using WildCard *
for Versions with Node.js
The wildcard *
instead of the version number in package.json
seems like a good idea — an automatic update in the near future. Wrong! You should use exact version numbers to prevent any third-party module changes from breaking your app and waking up you in the middle of the night wondering what went south.
This is especially true if you don’t commit your node_modules
folder or don’t use shrinkwrap.
A bad example from HackHall package.json
circa summer 2013:
{
"name": "hackhall",
"version": "0.0.1",
"private": true,
"main": "server",
"scripts": {
"start": "node server"
},
"dependencies": {
"express": ">=2.2.0",
"jade": "*",
"mongodb": "*",
"mongoose":"",
"oauth":"*"
},
"devDependencies":{
"mocha": "",
"superagent":""
},
"engines": {
"node": ">=0.6"
}
}
A good example from the Practical Node.js book [2014, Apress]:
{
"name": "blog-express",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node app.js",
"test": "mocha test"
},
"dependencies": {
"express": "3.4.5",
"jade": "0.35.0",
"mongoskin": "~0.6.1",
"stylus": "~0.40.3",
"mocha": "1.16.2",
"superagent": "0.15.7",
"expect.js": "0.2.0"
}
}
If you don’t want to go to NPM website every time to check the version, you can use $ npm install package_name --save
which will save the version number in the package.json.
If the module is installed already you can:
- Type
$ npm ls
- Open the package folder and copy the version number form
package.json
Stop Using console.log
for Debugging Node.js Apps
What is the best debugger? Right, it’s console.log
! It’s fast, non-interrupting and gives us any information we ask for (like the value of a pesky variable). Then why should you stop using it? Because real debuggers like Node Inspector provide not only the value of a variable you just hard-coded, but also give you a dynamic ability to look around, inside the process.
For example, I might have a condition (where resubmit is a boolean) that is not acting right:
if (resubmit && post.published && user.plan.paid && post.isVisible) {
// code A
} else {
// code B
}
With console.log
I can type only console.log(resubmit)
, or console.log(resubmit, ...)
some other variables. But, with debugger, I can poke around and print anything I have access to in that scope. If that is not enough, I’ll step over or step in the Code A or B as show in the example.
Stop Using GET
and POST
for Everything in Node.js servers
Stop using GET
and POST
for all of your incoming HTTP requests. Representational state transfer application programming interface methodology (RESTful API) has PUT
and DELETE
so use them for updates and deletions (wiki).
For example in this Express.js route, instead of using POST to update a record, you can use PUT:
app.post('/comments/update/:id', routes.comments.update)
app.put('/comments/:id', routes.comments.update)
For more information, take a look at REST API Tutorial.
Stop Using Semicolons with Node.js
Semicolons are actually optional, because ECMAScript (the standard for Node.js and browser JavaScript implementations) has an automatic semicolon-insertion feature (ASI). Here’s the draft of the ECMAScript 6 (ES6) documentation about ASI.
The gist is that semicolons are optional and except for two cases: in front of the IIFE and inside of the for
loop.
The problem with using semicolons:
- Extra characters to type: In a 1,000-line file there will be at least 1,000 extra symbols
- Inconsistency: When semicolons are missed due to neglect, the code base still works but becomes inconsistent (solvable by linting, but that’s an extra build step)
Some popular Node.js projects have been written with a semicolon-less style:
Are you still doubtful because Doug Crockford told you that you had to use semicolons? Then maybe you should read An Open Letter to JavaScript Leaders Regarding Semicolons.
Stop Using Comma-First Style
Okay, this topic is very subjective and probably not that important, but I want to voice my dislike for the comma-first style. Please, stop the madness!
The style in question is often seen when one might write arrays and objects with a comma at the beginning of lines instead of at the end. For example, we can define an array:
var arr = [ 'nodejs'
, 'python'
, 'ruby'
, 'php'
, 'java'
]
Or in a more traditional style it would look like this:
var arr = [ 'nodejs',
'python',
'ruby',
'php',
'java'
]
Please, don’t do the former. I don’t care how much better it might be for catching missing commas. The comma-first style just look ridiculous, because we would never use this style in our normal language writing. Nobody writes like this:
Paleo lifestyle is good for ,adult men ,adult women ,children ,and elderly people.
In my humble opinion, comma-first style is hard for the brain to adapt and just plain silly.
Stop Limiting Your Connections with Default MaxSockets Value
The default maxSockets
value is 5 and it determines the limit on number of sockets per host (official docs).
To avoid bottlenecking your system just use something like this:
var http = require('http')
http.globalAgent.maxSockets = 10
Or, if you want to make it unlimited:
require('http').globalAgent.maxSockets = Infinity
Here is a good comparison article Node.js Connection Pooling.
Another approach is to disable pooling all together (agent: false
) like LinkedIn did or Substack recommends in his hyperquest module.
Conclusion About Things to Stop Doing with Node.js
Of course, this list of seven things you should immediately stop doing with Node.js is subjective, but it was born out of careful and ongoing observation, as well as some painful real-world experience (i.e., *
in package.json
). What is on your list of things not to do with Node.js?
Honestly, these are bad advices, the callbacks sometimes play well, I don’t have anything against the first coma style although I don’t use that style.
Not using semicolons? Try to minify your code or use the enclosure compiler. Have a nice day. Also relying on an auto insert feature is a bad, that is not mastering your code it is just lazyness.
Below code will fail, without semicolon if *last line.
Why?
<<<<<<<<<<<<<<<<>>>>>>>>>>>>>
nope. just use prettier.
about the semicolons part:
“The source
a = b + c
(d + e).print()
is not transformed by automatic semicolon insertion, because the parenthesized expression that begins the second line can be interpreted as an argument list for a function call:
a = b + c(d + e).print()
In the circumstance that an assignment statement must begin with a left parenthesis, it is a good idea for the programmer to provide an explicit semicolon at the end of the preceding statement rather than to rely on automatic semicolon insertion.”
same will happen with
var x = 12
var y = 13
var z = x + y;
[‘item1’, ‘item2’, ‘item3’]
.forEach(item => {
console.log(item)
})
without the semicolon after ‘y’
and ASI is going to bite you back with something like this
return
{
hello: ‘hola’
}
:)
Stating ‘stop using callbacks’ is pretty funny.
Promises is good way. Have great pattern to use them, to decompose into functions:
https://github.com/EugeneHerasymchuk/avoiding_callback_hell
PUT and DELETE methods are not secure, unsafe and should never be allowed on public-facing websites. A hacker can easily upload a reverse shell to your server and fully compromise all your network and data. Educate your developers in Application Security – read and understand OWASP Top 10 Security Risks!
Use Node’s method-overrides to convert PUT/DELETE to POST.
1.
“You should purposely depend on Automatic Semicolon Insertion” is TERRIBLE advice. It’s much more reliable to just put semicolons where they belong, rather than depend on your WHOLE TEAM knowing the complete rules regarding Automatic Semicolon Insertion.
“It’s less typing” is not compelling whatsoever. Programmers are not typists! Typing is the least of what a programmer does in their everyday job. You spend most of your time thinking, reading, and discussing, not typing. Reducing mental effort is far more important than reducing typing, and consistent semicolon use accomplishes this.
2.
Async may be better than nested callback hell, but it’s not the One True Answer (TM) (nor are promises). Right now, ES6 generators + iterators look the most promising; making async code look synchronous. Again, less mental effort, in reading it, understanding it, tracing the path of execution with a debugger…..
But this is 2016. In 2020 there may be a superior pattern and we shouldn’t declare one thing “FTW, everyone do this!” and be done with it.
Your examples are highly contrived. Real world code has the callbacks in the middle, sometimes multiple times (for errors).
Number 1 is clearly not worded correctly. The fix to “Don’t use callbacks” is to use a different pattern that still uses callbacks?? This should be rewritten to “Don’t nest callbacks”. Whether you use async module or just a smart non nested pattern, it is fine. I honestly expected that topic one was going to be about using promises. (which I personally like for chaining logic) :-)
Anything fancy like “don’t use semi-colons” or “let’s put commas at the front because git” should die a quick death.
In collaborative development, the most important thing is that others can follow your code.
In sincerely hope developers do not follow your advice. I find your suggestion to not use semicolons because linting is “an extra build step” absolutely absurd. Any respectable developer is going to have a respectable IDE which lints automatically. You use semicolons not because they are necessary, but because they are instrumental in helping people understand your code. Node without semicolons is paren hell. In fact, I think it is so ridiculous that when a developer submitted final code to me without semicolons, he was fired on the spot.
On the other hand, I have nothing against comma-first notation. There is absolutely zero loss of readability or function (unlike your semicolon suggestion) and commas first clearly are easier to reorganize.
i have get response in data
router.route(‘/merchant/demo/:merchantid’)
.get(function(req,res)
{
Earn_Burn.find({‘merchantid’: req.params.merchantid},function(err,row)
{
if(err){
res.json({error:err,status:’error’,message:’error to earn and burn data’});
}
else if(row!=null) {
var arr=[];
row.forEach(function(obj) {
//console.log(obj);
//res.json(obj);
var data ;
EndUser.findOne({‘_id’:obj.userid},function(err,rows){
if (rows!=null) {
data={totalvisits:obj.totalvisits,totalpoints:obj.totalpoints,name:rows.name,status:’success’};
arr.push(data);
//var myCallback = function(data) {
//console.log(‘data: ‘+data);
// };
//data += 1;
//return data;
console.log(‘Push Done’);
// console.log(arr);
//pushdata(arr);
//res.json(arr);
}
else{
res.json({message:’data not available’,status:’Failed’});
}
//res.end();
});
//console.log(arr);
//console.log(‘Outside Query’);
},done);
function done(){
//console.log(arr);
res.json(arr);
}
}else{
res.json({message:’data does not exist’,status:’Failed’});
}
});
})
Excellent post!
You should update it to include the new ES6 Generators that make it possible to write synchronous-looking JS code, avoiding callbacks and multiple functions altogether:
http://kenrick.me/blog/es6-generators-in-express.html
Elad
Callbacks are much more readable than async’s series. Just make sure that you don’t nest them:
CodeA(HandleA)
function HandleA(a){ codeB(HandleB) }
function HandleB(b){ codeC(HandleC) }
function HandleC(c){ codeD(HandleD) }
function HandleD(d){
// Final callback code
}
Perfectly readable right? And no, function definitions are not part of the control flow, so you can reference them regardless of where they’re defined.
Regarding this comma first thing! I think the idea is to easily copy and paste elements, without having to worry with the last commas.
I have a solution for that so that the last comma is not forgotten:
one can do something like this:
var myObj = {
foo: ‘bar’,
foo1: ‘bar1’,
foo2: ‘bar2’,
foo3: ‘bar3’,
comma: ‘fix’
}
and
var myArr = [
‘foo’,
‘foo2’,
‘foo3’,
‘foo4’,
‘commafix’
];
Is it silly?
“Another approach is to disable pooling all together (agent: false) like”
This has some serious implications. This disables persistent connections. If 65000 connections are made before the the first one exits TIME_WAIT (2 minutes i think) you basically run out of client ports.
Train wreck!
I grow weary of the comma, semicolon, open-paren wars. Yet they occur again and again. It is the one area of style where people’s personal preferences are allowed to be enshrined into the final product. This is folly.
People have a variety of reasons why they like one style or another. I think it is like cleaning one’s bedroom. Some keep theirs neat and clean all the time, some are completely chaotic, (and that’s completely fine and comfortable for them.) Some people have ritualistic ways of cleaning and organizing things that is borne out of abuse or mental illness.
However, here’s the bottom line. Code is a blueprint. It is the way, first and foremost, we communicate ideas about program structure with OTHER PEOPLE. So, just as one would not publish a whitepaper, manuscript, or novel with strange and bizarre usages of grammar and punctuation, so too must people realize that code must also be delivered in the most readable and easily understandable format possible. So I would like to see these odd, grammatically jarring usages of commas, semicolons, parens and braces ended. But I know it will never happen…
Excellent list! I especially agree with stopping using callbacks. I don’t know how much code I’ve written and had that problem. Async makes things so much easier.
The semicolon removal is not a good advice at all. And I don’t buy any of the arguments of the pedant blogger you linked.
I agree with everything, except the comma first and semicolon.
Comma first is helpful for debugging, sometimes you need to make your code easy to debug.
As far as the semicolons, there are many features in each language, using them all will make you very unhappy as not a single one ever works in all situations. Adding a semicolon is a standard that most devs are used to.
A good and sensible list, although async still uses callbacks, they’re just arranged differently. Perhaps you should say to stop nesting callbacks.
Funny, because the “An Open Letter to JavaScript Leaders Regarding Semicolons” article you link to just contradicts your “Stop Using Comma-First Style” plea… (I fully agree with the latter, ugly practice.)
When I see:
I am horrified… It is ugly, and annoying to have to remember to put a semi-colon in front of array literals or parenthesized expressions or some similar exception (but I never put binary operators at the start of a line, anyway, I break my lines after them).
I also fully agree with using PUT and DELETE. An API without them feels incomplete.
I don’t use “*” in package.json, but sometime I use ^ or ~. The latter is probably the most innocuous, particularly if you have a CI server and a full set of integration tests, no?
I don’t code against node.js (only using its tools), so some other advices are a bit irrelevant for me. But they sound good, anyway.
Note: console.log or equivalent can be still useful, because sometime you don’t want just an instant value, but want to get an overall picture (a trace) of the run of an application, across events, complex calls, etc.
I agree with the commas-last style, except I would put the first element on a new line. This makes the formatting of array literals consistent with the way we already format object literals.
eg.
var arrayLiteral = [
1,
2,
3,
];
var objectLiteral = {
"1": 1,
"2": 2,
"3": 3
};
The “delete a line” argument is not valid, because if you delete the first line you’ll still have a problem. In other words, you transferring the problematic line from the last item to the first. You are NOT eliminating the issue by using different comma placement.
After looking at your two examples of different comma placement, I think the second looks more ridiculous. I like how the commas are in a straight line in the first. It’s also better for versioning. If you delete a line, the comma goes with it – and no other lines are shown as being modified.