Your SlideShare is downloading. ×
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
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,116

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,116
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

×