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

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Bonnes pratiques de développement avec Node js

5,074

Published on

Présentation faite au #ParisJS du 16 avril 2012

Présentation faite au #ParisJS du 16 avril 2012

Published in: Technology
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
5,074
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
21
Comments
0
Likes
2
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

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

×