Bonnes pratiques de développement avec Node js
Upcoming SlideShare
Loading in...5
×
 

Like this? Share it with your network

Share

Bonnes pratiques de développement avec Node js

on

  • 4,906 views

Présentation faite au #ParisJS du 16 avril 2012

Présentation faite au #ParisJS du 16 avril 2012

Statistics

Views

Total Views
4,906
Views on SlideShare
4,002
Embed Views
904

Actions

Likes
2
Downloads
20
Comments
0

6 Embeds 904

http://www.scoop.it 891
https://twimg0-a.akamaihd.net 4
https://twitter.com 3
http://www.pearltrees.com 3
https://si0.twimg.com 2
http://faavorite.com 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Bonnes pratiques de développement avec Node js Presentation Transcript

  • 1. Bonnes pratiques dedéveloppement avec Node.js François Zaninotto @francoisz http://github.com/fzaninotto
  • 2. Node.js ne suffit paset vous ne pouvez pas réinventer la roue
  • 3. Organisation du code Objectif: éviter le code spaghettiUtiliser un framework pour les applis web visionmedia/express (ou viatropos/tower)Eviter la course aux callbacks caolan/async (ou kriskowal/q)Inclure des routes et monter des sous-applications«Fat model, Skinny controller»Modules de service pour éviter un modèle trop fat
  • 4. // main app.jsvar express = require(express);var app = module.exports = express.createServer();app.configure(function(){ app.use(app.router); // these middlewares are required by some of the mounted apps app.use(express.bodyParser()); app.use(express.methodOverride()); app.use(express.cookieParser()); app.use(express.session({ secret: qdfegfskqdjfhskjdfh }));});// Routesapp.use(/api, require(./app/api/app));app.use(/dashboard, require(./app/dashboard/app));app.get(/, function(reaq, res) { res.redirect(/dashboard/events);});app.listen(3000);
  • 5. // dashboard appvar express = require(express);var app = module.exports = express.createServer();app.configure(function(){ app.use(app.router); app.set(views, __dirname + /views); app.set(view engine, ejs); app.use(express.static(__dirname + /public));});// Routesapp.get(/events, function(req, res) { res.render(events, { route: app.route });});app.get(/checks, function(req, res) { res.render(checks, { route: app.route, info: req.flash(info)});});//...if (!module.parent) { app.listen(3000);}
  • 6. // dashboard appvar express = require(express);var app = module.exports = express.createServer();app.configure(function(){ app.use(app.router); app.set(views, __dirname + /views); app.set(view engine, ejs); app.use(express.static(__dirname + /public));});// Routesapp.get(/events, function(req, res) { res.render(events, { route: app.route });});app.get(/checks, function(req, res) { res.render(checks, { route: app.route, info: req.flash(info)});});//...if (!module.parent) { app.listen(3000);}
  • 7. <!DOCTYPE html><html lang="en"> <head> <meta charset="utf-8"> <title>Uptime</title> <link rel="stylesheet" href="<%= route %>/stylesheets/bootstrap.css"> <link rel="stylesheet" href="<%= route %>/stylesheets/style.css"> </head> <body> <div class="navbar"> <div class="navbar-inner"> <div class="container"> <a class="brand" href="<%= route %>/events">Uptime</a> <ul class="nav pull-left"> <li><a href="<%= route %>/events">Events</a></li> <li><a href="<%= route %>/checks">Checks</a></li> <li><a href="<%= route %>/tags">Tags</a></li> </ul> </div> </div> </div>
  • 8. <!DOCTYPE html><html lang="en"> <head> <meta charset="utf-8"> <title>Uptime</title> <link rel="stylesheet" href="<%= route %>/stylesheets/bootstrap.css"> <link rel="stylesheet" href="<%= route %>/stylesheets/style.css"> </head> <body> <div class="navbar"> <div class="navbar-inner"> <div class="container"> <a class="brand" href="<%= route %>/events">Uptime</a> <ul class="nav pull-left"> <li><a href="<%= route %>/events">Events</a></li> <li><a href="<%= route %>/checks">Checks</a></li> <li><a href="<%= route %>/tags">Tags</a></li> </ul> </div> </div> </div>
  • 9. Standards Felixs Node.js Style Guide (http://nodeguide.com/style.html)Object-Oriented Programming FTW Domain-Driven Design!
  • 10. var mongoose = require(mongoose), Schema = mongoose.Schema, async = require(async);var Check = new Schema({ name : String , type : String , url : String , interval : { type: Number, default: 60000 } , maxTime : { type: Number, default: 1500 } , tags : [String] , lastChanged : Date , lastTested : Date , isUp : Boolean , uptime : { type: Number, default: 0 } , downtime : { type: Number, default: 0 }});Check.plugin(require(../lib/lifecycleEventsPlugin));
  • 11. var mongoose = require(mongoose), Schema = mongoose.Schema, async = require(async);var Check = new Schema({ name : String , type : String , url : String , interval : { type: Number, default: 60000 } , maxTime : { type: Number, default: 1500 } , tags : [String] , lastChanged : Date , lastTested : Date , isUp : Boolean , uptime : { type: Number, default: 0 } , downtime : { type: Number, default: 0 }});Check.plugin(require(../lib/lifecycleEventsPlugin));
  • 12. var mongoose = require(mongoose);var Schema = mongoose.Schema;var async = require(async);var Check = new Schema({ name : String, type : String, url : String, interval : { type: Number, default: 60000 }, maxTime : { type: Number, default: 1500 }, tags : [String], lastChanged : Date, lastTested : Date, isUp : Boolean, uptime : { type: Number, default: 0 }, downtime : { type: Number, default: 0 },});Check.plugin(require(../lib/lifecycleEventsPlugin));
  • 13. Canaux de communication Dans un module Entre applications Client / Serveur ou une application Appels deNotifications Events socket.io méthodesEchanges de Appels de XMLHTTP API HTTP données méthode RequestTraitements Promise AMQP Mentir*asynchrones
  • 14. // server-sidevar socketIo = require(socket.io);var CheckEvent = require(./models/checkEvent);var io = socketIo.listen(app);CheckEvent.on(postInsert, function(event) { io.sockets.emit(CheckEvent, event.toJSON());});
  • 15. // client-side<!DOCTYPE html><html lang="en"> <head> <script src="/socket.io/socket.io.js"></script> <script>var socket = io.connect(http://+location.hostname);</script> </head> <body> <div class="navbar"><ul id="counts"></ul></div> <script> $(document).ready(function() { var updateCounts = function() { $.getJSON(/api/check/count, function(count) { // display counts in navbar }); }; updateCounts(); socket.on(CheckEvent, function() { updateCounts(); $(#count).fadeOut().fadeIn().fadeOut().fadeIn(); }); }); </script> </body></html>
  • 16. Gestions des erreurstry {} catch {} ne marche pas en asynchronefunction (err, results) est la signaturestandard des callbacks asynchrones"Leave early"Utiliser les codes d’erreur HTTP pour les APIs
  • 17. app.delete(/check/:id, function(req, res, next) { Check.findOne({ _id: req.params.id }, function(err, check) { if (err) { return next(err); } if (!check) { return next(new Error(No check with id + req.params.id)); } check.remove(function(err2){ if (err2) { req.flash(error, Error - Check not deleted); res.redirect(/checks); return; } req.flash(info, Check has been deleted); res.redirect(/checks); }); });});
  • 18. Tests UnitairesLibrairies (presque) standard Assertions : visionmedia/should.js (ou node/assert) TDD : visionmedia/mocha (ou caolan/node-unit) BDD : visionmedia/mocha (ou mhevery/jasmine-node)L’asynchrone se teste aussi très bienPas besoin de mocker quand on peut monkey-patcher
  • 19. describe(Connection, function(){ var db = new Connection , tobi = new User(tobi) , loki = new User(loki) , jane = new User(jane); beforeEach(function(done){ db.clear(function(err){ if (err) return done(err); db.save([tobi, loki, jane], done); }); }) describe(#find(), function(){ it(respond with matching records, function(done){ db.find({ type: User }, function(err, res){ if (err) return done(err); res.should.have.length(3); done(); }) }) })})
  • 20. var nock = require(nock);var couchdb = nock(http://myapp.iriscouch.com) .get(/users/1) .reply(200, { _id: "123ABC", _rev: "946B7D1C", username: pgte, email: pedro.teixeira@gmail.com} );
  • 21. Projet open-sourceConfigurable app.configure() pas compatible avec un SCM lorenwest/node-config (ou flatiron/nconf)Extensible Custom events Plugin architecture
  • 22. // in main app.jspath.exists(./plugins/index.js, function(exists) { if (exists) { require(./plugins).init(app, io, config); };});// in plugins/index.jsexports.init = function(app, io, config) { require(./console).init();}
  • 23. module.exports = exports = function lifecycleEventsPlugin(schema) { schema.pre(save, function (next) { var model = this.model(this.constructor.modelName); model.emit(preSave, this); this.isNew ? model.emit(preInsert, this) : model.emit(preUpdate, this); this._isNew_internal = this.isNew; next(); }); schema.post(save, function() { var model = this.model(this.constructor.modelName); model.emit(postSave, this); this._isNew_internal ? model.emit(postInsert, this) : model.emit(postUpdate, this); this._isNew_internal = undefined; }); schema.pre(remove, function (next) { this.model(this.constructor.modelName).emit(preRemove, this); next(); }); schema.post(remove, function() { this.model(this.constructor.modelName).emit(postRemove, this); });};
  • 24. Questions ? François Zaninotto@francoisz http://github.com/fzaninotto