Best PracticesFelix Geisendörfer           Munich Node.js User Group 01.12.2011 (v1)
(@)felixge(.de)Twitter / GitHub / IRC    Felix Geisendörfer     (Berlin, Germany)
Callbacks
A terrible Example:var fs = require(fs);function readJSON(path, cb) {  fs.readFile(path, utf8, function(err, data) {    cb...
Error Delegationvar fs = require(fs);function readJSON(path, cb) {  fs.readFile(path, utf8, function(err, data) {    if (e...
Exception Handlingvar fs = require(fs);function readJSON(path, cb) {  fs.readFile(path, utf8, function(err, data) {    if ...
Error parameter firstvar fs = require(fs);function readJSON(path, cb) {  fs.readFile(path, utf8, function(err, data) {    i...
Not your errorvar fs = require(fs);function readJSON(path, cb) {  fs.readFile(path, utf8, function(err, data) {    if (err...
Another common mistakefunction readJSONFiles(files, cb) {  var results   = {};  var remaining = files.length;    files.for...
Only call back oncefunction readJSONFiles(files, cb) {  var results   = {};  var remaining = files.length;    files.forEac...
Nested Callbacks
db.query(SELECT A ..., function() {  db.query(SELECT B ..., function() {    db.query(SELECT C ..., function() {      db.qu...
iPhone 4 owners?
You are holding it wrong!
Just kidding
Control Flow Libs var async = require(async); async.series({   queryA: function(next) {      db.query(SELECT A ..., next);...
Split code into more       methods
Maybe node.js is not a good tool for your     problem?
Exceptions(Dealing with Death)
Exceptionsthrow new Error(oh no);  Explicit, useful to crash your program
Exceptionsnode.js:134      throw e; // process.nextTick error, or error event on first tick      ^Error: oh no   at Object....
Exceptionsfunction MyClass() {}MyClass.prototype.myMethod = function() {   setTimeout(function() {     this.myOtherMethod(...
Exceptions/Users/felix/implicit.js:5  this.myOtherMethod();      ^TypeError: Object #<Object> has no method myOtherMethod ...
Global Catchprocess.on(uncaughtException, function(err) {  console.error(uncaught exception:  + err.stack);});
Please be careful    with this!
Global catch gone wrong// Deep inside the database driver you are usingcb(null, rows);this._executeNextQueuedQuery();// In...
If you have to:process.on(uncaughtException, function(err) {  // You could use node-airbake for this  sendErrorToLog(funct...
Even Better       Processes die.          Accept it.Deal with it on a higher level.
Deployment
Novice$ node server.js
Advanced Beginner   $ node server.js &
Competent$ screen$ node server.js
Proficient#!/bin/bashwhile :do   node server.js   echo "Server crashed!"   sleep 1done
Expert#!upstartdescription "myapp"author      "felix"start on (local-filesystems and net-device-upIFACE=eth0)stop on shutd...
Innovation$ git push joyent master$ git push nodejitsu master$ git push heroku master
Questions?   @felixge
Thank you!
Node.js  - Best practices
Upcoming SlideShare
Loading in...5
×

Node.js - Best practices

52,743

Published on

Second talk given at the munich node.js user group meeting on Dec 1, 2011.

Published in: Technology
2 Comments
202 Likes
Statistics
Notes
No Downloads
Views
Total Views
52,743
On Slideshare
0
From Embeds
0
Number of Embeds
19
Actions
Shares
0
Downloads
1,077
Comments
2
Likes
202
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • \n
  • If you&amp;#x2019;re function works like this, I will not use it\n
  • Otherwise JSON.parse(undefined) -&gt; SyntaxError: Unexpected token ILLEGAL \n
  • Otherwise invalid JSON -&gt; SyntaxError: Unexpected token ILLEGAL\n
  • Otherwise I always have to -&gt; if (json instanceof Error) ...\n
  • Subtle: Do not catch errors inside your callback -&gt; very unexpected results\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Fake photograph btw.: http://www.snopes.com/photos/politics/bushbook.asp\n
  • Nested callbacks are an actual concern in the node community\n
  • \n
  • \n
  • \n
  • \n
  • Please DO NOT EVER use exceptions for control flow.\n\nLike so many things in JS, JSON.parse() throwing exceptions is bullshit.\n
  • \n
  • \n
  • \n
  • Also known as Stage 3 / Bargaining stage in K&amp;#xFC;bler-Ross model of &amp;#x201C;The Five Stages of Grief&amp;#x201D;\n
  • \n
  • If rows.length === 0 the exception triggered from accessing rows[0].id will STALL your database driver. Not good!\n
  • \n
  • Higher level could be upstart / monit / etc.\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Node.js - Best practices

    1. 1. Best PracticesFelix Geisendörfer Munich Node.js User Group 01.12.2011 (v1)
    2. 2. (@)felixge(.de)Twitter / GitHub / IRC Felix Geisendörfer (Berlin, Germany)
    3. 3. Callbacks
    4. 4. A terrible Example:var fs = require(fs);function readJSON(path, cb) { fs.readFile(path, utf8, function(err, data) { cb(JSON.parse(data)); });}
    5. 5. Error Delegationvar fs = require(fs);function readJSON(path, cb) { fs.readFile(path, utf8, function(err, data) { if (err) return cb(err); cb(JSON.parse(data)); });}
    6. 6. Exception Handlingvar fs = require(fs);function readJSON(path, cb) { fs.readFile(path, utf8, function(err, data) { if (err) return cb(err); try { cb(JSON.parse(data)); } catch (err) { cb(err); } });}
    7. 7. Error parameter firstvar fs = require(fs);function readJSON(path, cb) { fs.readFile(path, utf8, function(err, data) { if (err) return cb(err); try { cb(null, JSON.parse(data)); } catch (err) { cb(err); } });}
    8. 8. Not your errorvar fs = require(fs);function readJSON(path, cb) { fs.readFile(path, utf8, function(err, data) { if (err) return cb(err); try { var json = JSON.parse(data); } catch (err) { return cb(err); } cb(null, json); });}
    9. 9. Another common mistakefunction readJSONFiles(files, cb) { var results = {}; var remaining = files.length; files.forEach(function(file) { readJSON(file, function(err, json) { if (err) return cb(err); results[file] = json; if (!--remaining) cb(null, results); }); });}
    10. 10. Only call back oncefunction readJSONFiles(files, cb) { var results = {}; var remaining = files.length; files.forEach(function(file) { readJSON(file, function(err, json) { if (err) { cb(err); cb = function() {}; return; } results[file] = json; if (!--remaining) cb(null, results); }); });}
    11. 11. Nested Callbacks
    12. 12. db.query(SELECT A ..., function() { db.query(SELECT B ..., function() { db.query(SELECT C ..., function() { db.query(SELECT D ..., function() { db.query(SELECT E ..., function() { db.query(SELECT F ..., function() { db.query(SELECT G ..., function() { db.query(SELECT H ..., function() { db.query(SELECT I ..., function() { }); }); }); }); }); }); }); });});
    13. 13. iPhone 4 owners?
    14. 14. You are holding it wrong!
    15. 15. Just kidding
    16. 16. Control Flow Libs var async = require(async); async.series({ queryA: function(next) { db.query(SELECT A ..., next); }, queryB: function(next) { db.query(SELECT A ..., next); }, queryC: function(next) { db.query(SELECT A ..., next); } // ... }, function(err, results) { });
    17. 17. Split code into more methods
    18. 18. Maybe node.js is not a good tool for your problem?
    19. 19. Exceptions(Dealing with Death)
    20. 20. Exceptionsthrow new Error(oh no); Explicit, useful to crash your program
    21. 21. Exceptionsnode.js:134 throw e; // process.nextTick error, or error event on first tick ^Error: oh no at Object.<anonymous> (/Users/felix/explicit.js:1:69) at Module._compile (module.js:411:26) at Object..js (module.js:417:10) at Module.load (module.js:343:31) at Function._load (module.js:302:12) at Array.<anonymous> (module.js:430:10) at EventEmitter._tickCallback (node.js:126:26) Output on stderr
    22. 22. Exceptionsfunction MyClass() {}MyClass.prototype.myMethod = function() { setTimeout(function() { this.myOtherMethod(); }, 10);};MyClass.prototype.myOtherMethod = function() {};(new MyClass).myMethod(); Implicit, usually undesirable / bugs
    23. 23. Exceptions/Users/felix/implicit.js:5 this.myOtherMethod(); ^TypeError: Object #<Object> has no method myOtherMethod at Object._onTimeout (/Users/felix/implicit.js:5:10) at Timer.callback (timers.js:83:39) Incomplete stack trace : (
    24. 24. Global Catchprocess.on(uncaughtException, function(err) { console.error(uncaught exception: + err.stack);});
    25. 25. Please be careful with this!
    26. 26. Global catch gone wrong// Deep inside the database driver you are usingcb(null, rows);this._executeNextQueuedQuery();// In your codedb.query(SELECT ..., function(err, rows) { console.log(First row: + row[0].id);});
    27. 27. If you have to:process.on(uncaughtException, function(err) { // You could use node-airbake for this sendErrorToLog(function() { // Once the error was logged, kill the process console.error(err.stack); process.exit(1); });});
    28. 28. Even Better Processes die. Accept it.Deal with it on a higher level.
    29. 29. Deployment
    30. 30. Novice$ node server.js
    31. 31. Advanced Beginner $ node server.js &
    32. 32. Competent$ screen$ node server.js
    33. 33. Proficient#!/bin/bashwhile :do node server.js echo "Server crashed!" sleep 1done
    34. 34. Expert#!upstartdescription "myapp"author "felix"start on (local-filesystems and net-device-upIFACE=eth0)stop on shutdownrespawn # restart when job diesrespawn limit 5 60 # give up restart after 5respawns in 60 secondsscript exec sudo -u www-data /path/to/server.js >> /var/log/myapp.log 2>&1end script
    35. 35. Innovation$ git push joyent master$ git push nodejitsu master$ git push heroku master
    36. 36. Questions? @felixge
    37. 37. Thank you!
    1. A particular slide catching your eye?

      Clipping is a handy way to collect important slides you want to go back to later.

    ×