Hacker News new | comments | show | ask | jobs | submit login
Node.js Guide (nodeguide.com)
346 points by gulbrandr 2190 days ago | hide | past | web | 67 comments | favorite



In the "Beginner Guide" section - I would recommend using console.error() instead of console.log() for debugging output because console.error() is blocking while console.log() is not. Nothing is more annoying than your program crashing before it finishes printing debugging output when you are trying to debug a crash!


Good idea, I'll do that.


I was afraid to read the style guide for fear of seeing the preceding comma pattern (I think it's popular in Node because ryah uses it). Thankfully it recommends the trailing comma :)

    var variable, // trailing comma
        anotherVariable,
        thirdVariable;

    var variable 
      , anotherVariable // preceding comma
      , thirdVariable;


Here's an article about why preceding comma is very convenient:

http://ajaxian.com/archives/is-there-something-to-the-crazy-...

More specifically, in which is it easier for you to find the error?

  // error in standard style
  var a = "ape",
    b = "bat",
    c = "cat",
    d = "dog"
    e = "elf",
    f = "fly",
    g = "gnu",
    h = "hat",
    i = "ibu";

  // error in comma-first style
  var a = "ape"
    , b = "bat"
    , c = "cat"
    , d = "dog"
    e = "elf"
    , f = "fly"
    , g = "gnu"
    , h = "hat"
    , i = "ibu"
    ;


Yeah, I understand why, particularly when old IE browsers don't allow a comma trailing the final declaration. I just find it ugly as hell.


Unfortunately trailing commas still break IE7, which I wouldn't yet classify as old enough to ignore.


I'm not ignoring it but my code always runs through JSLint each time its saved and that picks up misplaced commas for me. Also we're not talking about client-side javascript here; fortunately Node.js uses the V8 Javascript engine, not the IE7 one. :)


I'd rather occasionally have comma bugs than make all my code horrendously ugly. Also, most people don't set their tabstop to 2 characters, which means you have to use space key twice in every variable declaration. That's got to be annoying.


Many node projects use soft tabs set to two spaces.


If that's so, why do we not see this in other mainstream languages? While I see the slight advantage of seeing errors, that is the first thing node sees. I use either nodemon or cluster, which both monitor your program on saving your code. When you think you're ready to go, save and see if it has no compile errors.


I don't know if haskell counts as a mainstream language, but it's pretty common to see this pattern in a module's export list. I go back and forth.


Haskell's an odd case; experienced Haskell users are likely to be thinking of the comma as less of a "separator" than a "combinator" constructing a tuple, and preceding-combinator-on-newline is an idiomatic style. Which doesn't disprove your point, I'm just saying it's an edge case. This is after all the language community that interprets a semicolon (as used in most languages) as a combinator too.


I do this all the time on large SQL statements. Otherwise, I rarely use the comma operator, so it hasn't come up.


I was afraid to read the style guide for fear of seeing K&R vs Allman indents/braces. As usual, it was hit on. However, to my amusement, the "Right" way of doing things actually has a syntax error:

  if (true) {
    console.log('winning);
  }


I have been personally screamed at for suggesting One True Brace Style over K&R in response to a request for feedback on an architecture standards document. That was when I learned that corporate architecture teams don't actually want to get feedback when they ask for it.

I find it odd that I have a strong opinion on the topic but have never seen a convincing argument that one way is actually better than another, it's just that one feels right to me and the others don't and I can't articulate but neither can anyone else I've seen.


I don't know about other languages but there are real practical reasons to choose 1TBS in Javascript, consider the following code:

    return {
        key: 'value',
        anotherKey: 'another value'
    }
This is fine and works as expected, now consider the following K&R/Allman style code...

    return
    {
        key: 'value',
        anotherKey: 'another value'
    }
In Javascript this is parsed as `return;` (notice the semi-colon), this is because Javascript does its dreaded automatic semicolon insertion magic.

So, I think that's a pretty good practical reason to prefer 1TBS in Javascript.


I favour a mix of the two in javascript - 1TBS for object literals and anonymous functions, K&R for conditionals and named functions.


Thank you! I didn't actually know this and would have completely missed that bug.


Fixed. Sorry, I was typing most of this on my iPad.


Other than style, is there an advantage to either of them over just declaring each one separately?

  var variable;
  var anotherVariable;
  var thirdVariable;
One issue I see with multiple variable declarations is that a forgotten comma doesn't cause a syntax error, it just causes that variable and any after it to be global variables. Which leads to much nastier javascript bugs.


For Node code, not really. For browser code, usually not really, but for high traffic sites or widely used libraries every character counts.


Y'know, I apparently haven't been plugged in enough to JS to realize that as a valid solution, because Python has spoiled me letting me terminate tuples with a comma (which I find elegant and painless) -- but the preceding comma pattern at least makes it easier to troubleshoot code and doesn't make me feel TOO much like I'm just trying to avoid pissing the interpreter off.


You can do that in Node.js too, just not in MSIE <= 7.


I hate the comma in variable declarations personally I use a new 'var' keyword on every line.


Does the preceding comma style not get in the way of JavaScript's auto semi-colon insertion?


It appears it doesn't, but I'd like to know WHY it doesn't.

Do Javascript parsers look at the next line before judging whether or not to treat the line-ending as an implicit semicolon?

(Do all parsers treat it in the same way? Is it part of the spec?)



Yes. Yes. Yes.


I use the comma-first style in everything (in languages that have this problem) now that I know about it. I was also interested to see it with semicolons in Simon PJ's chapter in Beautiful Code.

I just wish the character was something other than a comma! It looks so wrong in that position.

BTW, your second example should be

    var variable
      , anotherVariable // preceding comma
      , thirdVariable
      ;
Perl and Python don't have the trailing-comma problem in most contexts, but they do have a similar problem with some other infix operators. For example, I'm still not sure whether I should use it for strings:

    var myString = "This string is a bit too long to fit "
                 + "comfortably on a single line, so I "
                 + "have split it across three lines."
                 ;
The problem with this is that the first line looks like a standalone JS statement. Python requires you to wrap the whole thing in parens, which solves that problem:

    readMyString = ( "This string is a bit too long to fit "
                   + "comfortably on a single line, so I "
                   + "have split it across three lines."
                   );
The other language besides JavaScript where I find it useful is SQL:

    create table text_editors ( name varchar
                              , latest_version varchar
                              , list_of_stupid_flaws blob
                              );
I suspect that this approach would fix most of Damien Katz's complaints about Erlang's syntax in http://damienkatz.net/2008/03/what_sucks_abou.html:

Because Erlang's expression terminators vary by context, editing code is much harder than conventional languages. Refactoring -- cutting and pasting and moving code around -- is particularly hard to do without creating a bunch of syntax errors.

His example:

    blah(true) ->
      foo(),
      bar();
    blah(false) ->
      baz().
becomes

    blah(true) 
      -> foo()
       , bar()
       ;
    blah(false) 
      -> baz()
       .
His example transformation of reordering the branches now works correctly simply by cutting and pasting lines, albeit in two chunks (just as it would be in JS), and moreover any error in the process is visually obvious:

    blah(false) 
      -> baz()
       ;
    blah(true) 
      -> foo()
       , bar()
       .
His other transformation, of changing the order of foo() and bar(), still isn't trivial, but it's still visually obvious when you screw it up:

    blah(true) 
       , bar()
      -> foo()
       .


In the specific case of Python string concatenation, you don't need the operator at all:

  >>> x = ( "abc"
  ...       "def" )
  >>> x
  'abcdef'
Erlang also works this way. Note it only works for string literals.

But that's just FYI, it obviously doesn't affect your point.

It's actually slightly strange to me that for everything else Perl does that this doesn't work in Perl.


Oh, thanks! I'd forgotten that C feature of Python. Unfortunately it doesn't work in JS.


The case of Erlang is more or less a matter of preference. I haven't seen any piece of Erlang code with the separator first, except in the case of the if expression:

  if Cond1 -> Exp1
   ; Cond2 -> Exp2
   ; ...   -> ...
   ; CondN -> ExpN
  end
Other than that, meh. I think Erlang just needs to read/write code differently. My blog post on the issue: http://ferd.ca/on-erlang-s-syntax.html


The problem with this is that the first line looks like a standalone JS statement. Python requires you to wrap the whole thing in parens, which solves that problem:

Well, doesn't JS allow you to wrap it in parens if you want?


Why do ryah et al do it?


I am sorry, but event-based programming is the wrong way to tackle the problem of scaling up blocking I/O code. Event-based programming more or less forces one to write in CPS style, which soon becomes a nightmare to reason about. I speak from the experience of having written several thousand lines of such code.

A better solution is to pick a language that has light-weight threads (Haskell, Erlang, ...), and let the language handle the events (and call-stacks!) under the hood. Cf the caffeine/percolator paper (even though they do end up using heavy-weight Java threads).


Something good to know about usecases where node.js is not a good fit:

  The truth is that while we are starting to see good frameworks for node.js, there is nothing as powerful as Rails, CakePHP or Django on the scene yet. If most of your app is simply rendering HTML based on some database, using node.js will not provide many tangible business benefits yet.


Here's some criticism.

Taken from 'convincing the boss':

''' Another great aspect of node.js is the ease at which you can develop soft real time systems. By that I mean stuff like twitter, chat software, sport bets or interfaces to instant messaging networks. '''

Those are not all 'soft real time' applications, especially not twitter. Soft real time here might mean that the usefulness of a result degrades if it misses its deadline. This might be the case of some chat software, but in the case of twitter, I receive very little degradation of service if I just go tomorrow.

The key point here is that you have to be able to have a metric of a deadline and what to do when you fail it. "If we do not get an acknowledgement by 30 ms, we assume the current node is too busy for our needs and retry on a different one" could be an example of this.

''' So don't try to build hard realtime systems in node, that require consistent response times. Erlang is probably a better choice for these kinds of applications. '''

Erlang is made specifically for soft real time applications, not hard real time. You do not want to use Erlang to build things like life or death systems when you need to be precise to the microsecond. It is pretty good when you can miss a deadline, handle that, work your way around it, but it can not offer any guarantee about never missing a deadline. Not only does this section give bad advice about node.js, it also gives bad advice on other languages.

It just feels as if the author meant to say "It is good for interfaces with live updates, which could be slow or lack constancy of response times", not much more.

Later in the same section:

''' Combining this with node's radical model of non-blocking I/O, you have to try very hard to create a sluggish application. '''

My understanding was that you actually have to be careful not to write code that runs for too long, in order to avoid messing up your request times by ruining the cooperative scheduling scheme used in the language.

===

In general, the previous guides seem to be nicer, although I have to question the reason behind advice like 'do not extend the prototypes'. I figure it has to do with the difficulty of keeping things compatible, but if you're giving me advice, tell me why. Do not expect me to blindly follow your standards just because you said so.

In the deployment part, it is shown how to use screen to start and detach the server. Is there any reason why nohup or disown won't do it? it is advised not to use the shown setup for a production system -- it would be nice to know where to look for that.

I'd also generally be interested in knowing how you'd avoid spaghetti callback hell from the approach used in node.js, but that doesn't seem to be part of the guide. This is a work in progress, and I am not holding this against the author.


Hi, I'm the author of the guide.

Thanks for your feedback. You made some great points about real time systems, I'll try to rework that section.

> Do not expect me to blindly follow your standards just because you said so.

This reminds me of school : ). The difference here however is that I don't expect anybody to do anything, and participation is entirely voluntary.

In this case I didn't explain my choice of style because most people in the JS community would consent with it, and there has been lots of discussion about this in the past.

> In the deployment part

That's still a work in progress. I didn't choose nohup because I feel screen is conceptually slightly simpler. However, a real deployment section is coming in the future.

> I'd also generally be interested in knowing how you'd avoid spaghetti callback hell from the approach used in node.js, but that doesn't seem to be part of the guide. This is a work in progress, and I am not holding this against the author.

That will be the subject of a guide by itself as well.


''' In this case I didn't explain my choice of style because most people in the JS community would consent with it, and there has been lots of discussion about this in the past. '''

Then link to the discussions, explain why it is obviously right, etc. Some items like where to put braces can just be a community thing, but "don't use prototype-based features of a prototype language" might warrant more explanations, even if they are obvious.

''' That's still a work in progress. I didn't choose nohup because I feel screen is conceptually slightly simpler. However, a real deployment section is coming in the future. '''

I can understand choosing the conceptually simpler option. If it's not the right one, at least provide a resource pointing you towards the right one.

This might be a bit much to ask, but try to consider the cost of it to the people reading. Will they have to learn a better way on their own? Are you spreading misinformation or just incomplete one? The idea here is to save work to your readers, not you. Readers don't really care what is hard or not; most of the time, they just want great docs. This is a principle I try to apply in Learn You Some Erlang, and so far it has worked well to me. YMMV.

''' That will be the subject of a guide by itself as well. '''

Good to know :)


I'd suggest taking a look at the 'forever' module by indexzero for deployment. It has a bunch of node-specific neat features and keeps your process persistent... https://github.com/indexzero/forever


Why are you writing about "soft real time" when you don't seem to have done any work in RTOS/embedded?

Your listed project is transloadit, which is a file uploader that does some sort of magic I don't care about. (I'm provincial.)

You also appear to be available as a node.js consultant. That's a first for me. I figured the only "node.js consultants" were ryah and anybody you could catch awake on Freenode.

A burgeoning ecosystem is good. It's not good when virtually every proponent of Node.js I run into makes wild claims.

Checked your submissions, I see in this order from chronological proceeding towards the final entropic state of the universe:

1. jQuery >? *

2. Git

3. Node.js

4. Node.js

5. Node.js

6. Transloadit file jobber thingie (written in JS, on Node.js)

7. Javascript (This is what Node.js is written in, FYI)

8. TDD @ Transloadit (written in JS, on Node.js, Church of the GoF)

9. Realtime encoding - over 150x faster

As easily as I could outright crucify you for butchering the word "realtime" here, I'll simply spare you the trouble and do a text-replace that'll fix your solipsism simulator article (blog)

s/realtime/buffered/g

'Fraid that won't work for your video though. You'll have to fix that yourself. Also, please provide full transcripts (linked, in-line, doesn't matter) in future. Not all of us are hearing.

And to cap it:

http://debuggable.com/posts/hacking-a-commercial-airport-wla...

Illustrious real-time hacking, that.

This is why we programmers don't deserve to be called engineers, not yet.

Code is art, wondrously so, but we're lacking a rigor and consistency of competence that could be there.


Why are you trying to discredit everything I have done in the last ~5 years?


haters gonna hate

keep it up!


>Why are you trying to discredit everything I have done in the last ~5 years?

I'm not, I'm trying to instill caution and judgment in the use of terminology that has real meaning.

Don't claim something is real-time when it is not. You are misleading people.

By all means, keep hacking. I have nothing against you or your work.


Incredibly harsh and unnecessary. Check yourself.


re: cutting down on callback nesting / spaghetti code.

It can be hard to avoid; and having the community put together a PEP-8 style "best practices" to avoid creating nested code is one of my fondest dreams.

That said, I've written my fair share of [spaghetti code](https://github.com/chrisdickinson/tempisfugit/blob/master/li...) in Node, mostly because JavaScript seems to lend itself to slapping together nested callbacks without slapping you on the wrist for writing unreadable code.

In my experience, the best way to cut down on spaghetti code is to design your API around the [EventEmitter](http://nodejs.org/api/events.html#events.EventEmitter) object. Consider this adaptation of the linked spaghetti code: https://gist.github.com/f8533ff57844b1e54558

Note that in the application code, there are no nested callbacks -- they're merely concerned with validating the incoming data and passing the baton on to the next responder. Bonus points: the methods are in the order of their ideal execution. Clients using the code can just do the following:

    var validator = new RepoPathValidator(path);
    validator.on('data', function(repoData) {
        // do whatever needs to be done with the repo.
    });

    // redirect all errors to console.error
    validator.on('error', console.error.bind(console));
I'm very fond of using this method to destroy nested code -- I'm not sure how it's thought of in the community at large, though (part of the reason I'm so eager for the community to put together the aforementioned PEP-8 style "best practices" guide!)


I must be missing something, but how is EventEmitter helping you get rid of the nested code in your examples? It looks like changing all the anonymous callbacks to named functions, and then using the function names as the callbacks is what made the code more readable. EventEmitter wasn't necessary to do that, right?


Yes and no -- it's not absolutely necessary; I could've written it similarly without turning the callback-accepting functions into emitter-returning functions. It would have felt gross to do so, though. The downside I see with using straight callbacks that accept error and data arguments is that they conflate the logic of what that callback is actually attempting to do with the error-checking of the calling function. For example, my `baseDirOkay` method shouldn't care whether or not the calling `fs.stat` function succeeded or failed -- it should only care that the data it was passed is or isn't a directory. It shouldn't be called at all if the path was not valid. With an EventEmitter api, I can rely on the emitter itself to tell me whether or not to even call my `baseDirOkay` function, instead of having to conflate that logic with my method.

This seems like a tiny gain in readability, but it means that I don't have to make a decision between putting the error/success logic of `fs.readFile` in my method (where it does not go) and my calling function (where it probably does not go, and where it would incur unnecessary nesting -- and the finagling of the `this` variable that that incurs).

This may just be my taste -- but I find designing around (and reasoning about) EventEmitter-type API's much easier.


> ''' Another great aspect of node.js is the ease at which you can develop soft real time systems. By that I mean stuff like twitter, chat software, sport bets or interfaces to instant messaging networks. '''

Is there any evidence that this is actually true?

> ''' Combining this with node's radical model of non-blocking I/O, you have to try very hard to create a sluggish application. '''

NodeJS's model is hardly radical, it's several decades old. And it's very easy to create sluggish Node, just use a while loop.

EDIT: The relative instability of Node (as a codebase) is also left out it seems.


  > I'd also generally be interested in knowing how you'd avoid spaghetti callback hell
Here's a great article on this, especially the section on how to put your callbacks in sequence:

http://stella.laurenzo.org/2011/03/bulletproof-node-js-codin...



"My understanding was that you actually have to be careful not to write code that runs for too long, in order to avoid messing up your request times by ruining the cooperative scheduling scheme used in the language."

That is my understanding as well - because a long running task will block everything, you have to be MORE careful in node.js than in a traditional threaded environment. I actually think that this model works really well in 10% of applications, and a threaded model is a better choice in 90% of applications.

I also believe 'less mature developers' see, 'wow, server side javascript', get excited by that, and don't put enough attention on the more important architectural differences of node.js


Yes, this is a real pain point, because that's exactly why you need everything to be non-blocking in the libraries you are using with something like node.js (things like twisted in python have exactly the same issue).

Not only do you need non-blocking code for things like database access, but maybe more subtly, you need to be non-blocking for anything which is potentially CPU heavy. Case in point: encoding a payload in say xml or json. If you have a response which are big enough that they need say 20 ms to encode, all response whose processing have started but not yet finished will see a 20 ms additional delay. Now, you can incrementally encode into json by inserting new "scheduling points" at regular intervals, but doing this for say zlib compression, not so easy.

Not that I have a lot of experience, but IMO, async code should be reserved to the least amount of code possible, because everything becomes a bottleneck. And good luck trying to profile your async application with all those callbacks when you have performance issues...


Are there any "traditional" server side JavaScript environments?


I did find this:

http://en.wikipedia.org/wiki/Comparison_of_server-side_JavaS...

which I will probably work through at some point, I'd really like to use JavaScript on the server but I'm not sure if node.js is a good fit.


Am I the only one to wonder why there are no mention of coffee-script at all ?

It seems to me like a very effective and easy way to make programming more efficient and improve code readability.

Moreover,coffee-script handles all OOP concepts that could be needed to use node.


Ugh, don't agree at all with the dismissal of Object.freeze. This introduces immutable values to JS which is great for many kinds of data as well probably opening the door for more optimizations by V8.


Currently doing Object.freeze closes the door for optimizations: object goes into so called slow mode.

See http://jsperf.com/object-freeze results.


http://jsperf.com/object-freeze/3

http://jsperf.com/object-freeze/5

http://jsperf.com/object-freeze/6

A reminder on how immutable objects are meant to be used. When used properly even under attempts to mutate, they run circles around trying to use mutable objects in an immutable manner.


Yeah, I did something stupid in my own test. Probably I was thinking about Object.seal(). Nevertheless your own test revision #3 shows that accesses to frozen properties are roughly 14 times slower.

Revisions #5 and #6 do an allocation in the "hot" testcase so the real cost of property lookup just becomes hidden behind cost of memory management.


Very handy. Working on a project with node.js and need to take more of these suggestions to heart. Callbacks take some getting used to, especially returning data is tricky, but it does make things slicker. Node.js is awesome but oh so fragmented: I use Mongoose and Express, both of which have APIs that have changed, and stuff breaks, with lots of old examples floating around. There are also lots of plugins and libraries which seem to do the same thing (cluster, spark, spark2, etc, etc)


Just what I am looking for, installed node a few hours ago. Does anyone have any express.js resource recommendations?


I would like to echo my gratitude for this guide. I am also in need of a crash course in Node.js, this is really helpful!


(If you're reading Felix) The 'Right' section of Nesting Closures violates the 'Right' section of Named Closures. The outer closure is not named...


Fantastic. Just what i wanted. Thank you so much.


Thank you very much for this guide. I was going to learn Node.js later this month and this will make it much easier.


amazing guide, thank you!




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | DMCA | Apply to YC | Contact

Search: