SlideShare ist ein Scribd-Unternehmen logo
1 von 26
Downloaden Sie, um offline zu lesen
Bonnes pratiques de
développement avec Node.js
              François Zaninotto
     @francoisz http://github.com/fzaninotto
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
Node.js ne suffit pas
et vous ne pouvez pas réinventer la roue
Organisation du code
        Objectif: éviter le code spaghetti
Utiliser 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
// main app.js
var 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' }));
});

// Routes
app.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);
// dashboard app
var 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'));
});

// Routes
app.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);
}
// dashboard app
var 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'));
});

// Routes
app.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);
}
<!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>
<!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>
Standards
     Felix's Node.js Style Guide
 (http://nodeguide.com/style.html)


Object-Oriented Programming FTW


     Domain-Driven Design!
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'));
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'));
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'));
Canaux de communication
                Dans un module
                                  Entre applications Client / Serveur
               ou une application

                   Appels de
Notifications                           Events            socket.io
                   méthodes

Echanges de        Appels de                            XMLHTTP
                                     API HTTP
  données          méthode                               Request

Traitements
                    Promise            AMQP              Mentir*
asynchrones
// server-side
var 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());
});
// 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>
Gestions des erreurs
try {} catch {} ne marche pas en asynchrone
function (err, results) est la signature
standard des callbacks asynchrones
"Leave early"
Utiliser les codes d’erreur HTTP pour les APIs
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');
    });
  });
});
Tests Unitaires
Librairies (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 bien
Pas besoin de mocker quand on peut monkey-patcher
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();
           })
        })
     })
})
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'}
  );
Projet open-source
Configurable
  app.configure()   pas compatible avec un SCM
  lorenwest/node-config (ou flatiron/nconf)

Extensible
  Custom events
  Plugin architecture
// in main app.js
path.exists('./plugins/index.js', function(exists) {
  if (exists) {
     require('./plugins').init(app, io, config);
  };
});

// in plugins/index.js
exports.init = function(app, io, config) {
  require('./console').init();
}
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);
   });
};
Questions ?


         François Zaninotto
@francoisz http://github.com/fzaninotto

Weitere ähnliche Inhalte

Was ist angesagt?

Containers & Dependency in Ember.js
Containers & Dependency in Ember.jsContainers & Dependency in Ember.js
Containers & Dependency in Ember.jsMatthew Beale
 
soft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.jssoft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.jssoft-shake.ch
 
"Auth for React.js APP", Nikita Galkin
"Auth for React.js APP", Nikita Galkin"Auth for React.js APP", Nikita Galkin
"Auth for React.js APP", Nikita GalkinFwdays
 
Reactive, component 그리고 angular2
Reactive, component 그리고  angular2Reactive, component 그리고  angular2
Reactive, component 그리고 angular2Jeado Ko
 
HTML5: friend or foe (to Flash)?
HTML5: friend or foe (to Flash)?HTML5: friend or foe (to Flash)?
HTML5: friend or foe (to Flash)?Remy Sharp
 
Ember.js - A JavaScript framework for creating ambitious web applications
Ember.js - A JavaScript framework for creating ambitious web applications  Ember.js - A JavaScript framework for creating ambitious web applications
Ember.js - A JavaScript framework for creating ambitious web applications Juliana Lucena
 
Django + Vue, JavaScript de 3ª generación para modernizar Django
Django + Vue, JavaScript de 3ª generación para modernizar DjangoDjango + Vue, JavaScript de 3ª generación para modernizar Django
Django + Vue, JavaScript de 3ª generación para modernizar DjangoJavier Abadía
 
Mastering Spring Boot's Actuator with Madhura Bhave
Mastering Spring Boot's Actuator with Madhura BhaveMastering Spring Boot's Actuator with Madhura Bhave
Mastering Spring Boot's Actuator with Madhura BhaveVMware Tanzu
 
Workshop 14: AngularJS Parte III
Workshop 14: AngularJS Parte IIIWorkshop 14: AngularJS Parte III
Workshop 14: AngularJS Parte IIIVisual Engineering
 
Developing web-apps like it's 2013
Developing web-apps like it's 2013Developing web-apps like it's 2013
Developing web-apps like it's 2013Laurent_VB
 
TestWorks conf Dry up your angularjs unit tests using mox - Mike Woudenberg
TestWorks conf Dry up your angularjs unit tests using mox - Mike WoudenbergTestWorks conf Dry up your angularjs unit tests using mox - Mike Woudenberg
TestWorks conf Dry up your angularjs unit tests using mox - Mike WoudenbergXebia Nederland BV
 
Aplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com BackboneAplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com BackboneRafael Felix da Silva
 
And the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack SupportAnd the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack SupportBen Scofield
 
Asynchronous programming done right - Node.js
Asynchronous programming done right - Node.jsAsynchronous programming done right - Node.js
Asynchronous programming done right - Node.jsPiotr Pelczar
 
Good karma: UX Patterns and Unit Testing in Angular with Karma
Good karma: UX Patterns and Unit Testing in Angular with KarmaGood karma: UX Patterns and Unit Testing in Angular with Karma
Good karma: UX Patterns and Unit Testing in Angular with KarmaExoLeaders.com
 
Viking academy backbone.js
Viking academy  backbone.jsViking academy  backbone.js
Viking academy backbone.jsBert Wijnants
 
FwDays 2021: Metarhia Technology Stack for Node.js
FwDays 2021: Metarhia Technology Stack for Node.jsFwDays 2021: Metarhia Technology Stack for Node.js
FwDays 2021: Metarhia Technology Stack for Node.jsTimur Shemsedinov
 
Asynchronous Programming FTW! 2 (with AnyEvent)
Asynchronous Programming FTW! 2 (with AnyEvent)Asynchronous Programming FTW! 2 (with AnyEvent)
Asynchronous Programming FTW! 2 (with AnyEvent)xSawyer
 

Was ist angesagt? (20)

Containers & Dependency in Ember.js
Containers & Dependency in Ember.jsContainers & Dependency in Ember.js
Containers & Dependency in Ember.js
 
soft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.jssoft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.js
 
"Auth for React.js APP", Nikita Galkin
"Auth for React.js APP", Nikita Galkin"Auth for React.js APP", Nikita Galkin
"Auth for React.js APP", Nikita Galkin
 
Reactive, component 그리고 angular2
Reactive, component 그리고  angular2Reactive, component 그리고  angular2
Reactive, component 그리고 angular2
 
HTML5: friend or foe (to Flash)?
HTML5: friend or foe (to Flash)?HTML5: friend or foe (to Flash)?
HTML5: friend or foe (to Flash)?
 
Ember.js - A JavaScript framework for creating ambitious web applications
Ember.js - A JavaScript framework for creating ambitious web applications  Ember.js - A JavaScript framework for creating ambitious web applications
Ember.js - A JavaScript framework for creating ambitious web applications
 
Django + Vue, JavaScript de 3ª generación para modernizar Django
Django + Vue, JavaScript de 3ª generación para modernizar DjangoDjango + Vue, JavaScript de 3ª generación para modernizar Django
Django + Vue, JavaScript de 3ª generación para modernizar Django
 
Java script for web developer
Java script for web developerJava script for web developer
Java script for web developer
 
Mastering Spring Boot's Actuator with Madhura Bhave
Mastering Spring Boot's Actuator with Madhura BhaveMastering Spring Boot's Actuator with Madhura Bhave
Mastering Spring Boot's Actuator with Madhura Bhave
 
Workshop 14: AngularJS Parte III
Workshop 14: AngularJS Parte IIIWorkshop 14: AngularJS Parte III
Workshop 14: AngularJS Parte III
 
Developing web-apps like it's 2013
Developing web-apps like it's 2013Developing web-apps like it's 2013
Developing web-apps like it's 2013
 
TestWorks conf Dry up your angularjs unit tests using mox - Mike Woudenberg
TestWorks conf Dry up your angularjs unit tests using mox - Mike WoudenbergTestWorks conf Dry up your angularjs unit tests using mox - Mike Woudenberg
TestWorks conf Dry up your angularjs unit tests using mox - Mike Woudenberg
 
Aplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com BackboneAplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com Backbone
 
And the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack SupportAnd the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack Support
 
Asynchronous programming done right - Node.js
Asynchronous programming done right - Node.jsAsynchronous programming done right - Node.js
Asynchronous programming done right - Node.js
 
Good karma: UX Patterns and Unit Testing in Angular with Karma
Good karma: UX Patterns and Unit Testing in Angular with KarmaGood karma: UX Patterns and Unit Testing in Angular with Karma
Good karma: UX Patterns and Unit Testing in Angular with Karma
 
Viking academy backbone.js
Viking academy  backbone.jsViking academy  backbone.js
Viking academy backbone.js
 
FwDays 2021: Metarhia Technology Stack for Node.js
FwDays 2021: Metarhia Technology Stack for Node.jsFwDays 2021: Metarhia Technology Stack for Node.js
FwDays 2021: Metarhia Technology Stack for Node.js
 
Ruby - Design patterns tdc2011
Ruby - Design patterns tdc2011Ruby - Design patterns tdc2011
Ruby - Design patterns tdc2011
 
Asynchronous Programming FTW! 2 (with AnyEvent)
Asynchronous Programming FTW! 2 (with AnyEvent)Asynchronous Programming FTW! 2 (with AnyEvent)
Asynchronous Programming FTW! 2 (with AnyEvent)
 

Ähnlich wie Bonnes pratiques de développement avec Node js

Future Decoded - Node.js per sviluppatori .NET
Future Decoded - Node.js per sviluppatori .NETFuture Decoded - Node.js per sviluppatori .NET
Future Decoded - Node.js per sviluppatori .NETGianluca Carucci
 
How and why i roll my own node.js framework
How and why i roll my own node.js frameworkHow and why i roll my own node.js framework
How and why i roll my own node.js frameworkBen Lin
 
node.js and the AR.Drone: building a real-time dashboard using socket.io
node.js and the AR.Drone: building a real-time dashboard using socket.ionode.js and the AR.Drone: building a real-time dashboard using socket.io
node.js and the AR.Drone: building a real-time dashboard using socket.ioSteven Beeckman
 
09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)
09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)
09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)Igor Bronovskyy
 
Dependency Management with RequireJS
Dependency Management with RequireJSDependency Management with RequireJS
Dependency Management with RequireJSAaronius
 
Javascript Frameworks for Joomla
Javascript Frameworks for JoomlaJavascript Frameworks for Joomla
Javascript Frameworks for JoomlaLuke Summerfield
 
Asynchronous Interfaces
Asynchronous InterfacesAsynchronous Interfaces
Asynchronous Interfacesmaccman
 
Node js introduction
Node js introductionNode js introduction
Node js introductionAlex Su
 
Javascript MVC & Backbone Tips & Tricks
Javascript MVC & Backbone Tips & TricksJavascript MVC & Backbone Tips & Tricks
Javascript MVC & Backbone Tips & TricksHjörtur Hilmarsson
 
Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011Chris Alfano
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applicationsTom Croucher
 
Burn down the silos! Helping dev and ops gel on high availability websites
Burn down the silos! Helping dev and ops gel on high availability websitesBurn down the silos! Helping dev and ops gel on high availability websites
Burn down the silos! Helping dev and ops gel on high availability websitesLindsay Holmwood
 
Rich Portlet Development in uPortal
Rich Portlet Development in uPortalRich Portlet Development in uPortal
Rich Portlet Development in uPortalJennifer Bourey
 
前端MVC 豆瓣说
前端MVC 豆瓣说前端MVC 豆瓣说
前端MVC 豆瓣说Ting Lv
 
Primefaces Nextgen Lju
Primefaces Nextgen LjuPrimefaces Nextgen Lju
Primefaces Nextgen LjuSkills Matter
 
Primefaces Nextgen Lju
Primefaces Nextgen LjuPrimefaces Nextgen Lju
Primefaces Nextgen LjuSkills Matter
 
Tools for Making Machine Learning more Reactive
Tools for Making Machine Learning more ReactiveTools for Making Machine Learning more Reactive
Tools for Making Machine Learning more ReactiveJeff Smith
 

Ähnlich wie Bonnes pratiques de développement avec Node js (20)

Future Decoded - Node.js per sviluppatori .NET
Future Decoded - Node.js per sviluppatori .NETFuture Decoded - Node.js per sviluppatori .NET
Future Decoded - Node.js per sviluppatori .NET
 
Spine.js
Spine.jsSpine.js
Spine.js
 
How and why i roll my own node.js framework
How and why i roll my own node.js frameworkHow and why i roll my own node.js framework
How and why i roll my own node.js framework
 
node.js and the AR.Drone: building a real-time dashboard using socket.io
node.js and the AR.Drone: building a real-time dashboard using socket.ionode.js and the AR.Drone: building a real-time dashboard using socket.io
node.js and the AR.Drone: building a real-time dashboard using socket.io
 
09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)
09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)
09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)
 
Dependency Management with RequireJS
Dependency Management with RequireJSDependency Management with RequireJS
Dependency Management with RequireJS
 
JS everywhere 2011
JS everywhere 2011JS everywhere 2011
JS everywhere 2011
 
Rails is not just Ruby
Rails is not just RubyRails is not just Ruby
Rails is not just Ruby
 
Javascript Frameworks for Joomla
Javascript Frameworks for JoomlaJavascript Frameworks for Joomla
Javascript Frameworks for Joomla
 
Asynchronous Interfaces
Asynchronous InterfacesAsynchronous Interfaces
Asynchronous Interfaces
 
Node js introduction
Node js introductionNode js introduction
Node js introduction
 
Javascript MVC & Backbone Tips & Tricks
Javascript MVC & Backbone Tips & TricksJavascript MVC & Backbone Tips & Tricks
Javascript MVC & Backbone Tips & Tricks
 
Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
 
Burn down the silos! Helping dev and ops gel on high availability websites
Burn down the silos! Helping dev and ops gel on high availability websitesBurn down the silos! Helping dev and ops gel on high availability websites
Burn down the silos! Helping dev and ops gel on high availability websites
 
Rich Portlet Development in uPortal
Rich Portlet Development in uPortalRich Portlet Development in uPortal
Rich Portlet Development in uPortal
 
前端MVC 豆瓣说
前端MVC 豆瓣说前端MVC 豆瓣说
前端MVC 豆瓣说
 
Primefaces Nextgen Lju
Primefaces Nextgen LjuPrimefaces Nextgen Lju
Primefaces Nextgen Lju
 
Primefaces Nextgen Lju
Primefaces Nextgen LjuPrimefaces Nextgen Lju
Primefaces Nextgen Lju
 
Tools for Making Machine Learning more Reactive
Tools for Making Machine Learning more ReactiveTools for Making Machine Learning more Reactive
Tools for Making Machine Learning more Reactive
 

Mehr von Francois Zaninotto

Vous aimez les legos ? React est fait pour vous !
Vous aimez les legos ? React est fait pour vous !Vous aimez les legos ? React est fait pour vous !
Vous aimez les legos ? React est fait pour vous !Francois Zaninotto
 
La blockchain, quand l'individu sert au collectif... malgré lui
La blockchain, quand l'individu sert au collectif... malgré luiLa blockchain, quand l'individu sert au collectif... malgré lui
La blockchain, quand l'individu sert au collectif... malgré luiFrancois Zaninotto
 
Le jeu vidéo à la rescousse du web
Le jeu vidéo à la rescousse du webLe jeu vidéo à la rescousse du web
Le jeu vidéo à la rescousse du webFrancois Zaninotto
 
Frameworks : A history of violence
Frameworks : A history of violenceFrameworks : A history of violence
Frameworks : A history of violenceFrancois Zaninotto
 
La migration continue vers Symfony
La migration continue vers SymfonyLa migration continue vers Symfony
La migration continue vers SymfonyFrancois Zaninotto
 
La programmation asynchrone... et les pates
La programmation asynchrone... et les patesLa programmation asynchrone... et les pates
La programmation asynchrone... et les patesFrancois Zaninotto
 
Simplify your professional web development with symfony
Simplify your professional web development with symfonySimplify your professional web development with symfony
Simplify your professional web development with symfonyFrancois Zaninotto
 

Mehr von Francois Zaninotto (12)

Vous aimez les legos ? React est fait pour vous !
Vous aimez les legos ? React est fait pour vous !Vous aimez les legos ? React est fait pour vous !
Vous aimez les legos ? React est fait pour vous !
 
GraphQL, l'avenir du REST ?
GraphQL, l'avenir du REST ?GraphQL, l'avenir du REST ?
GraphQL, l'avenir du REST ?
 
La blockchain, quand l'individu sert au collectif... malgré lui
La blockchain, quand l'individu sert au collectif... malgré luiLa blockchain, quand l'individu sert au collectif... malgré lui
La blockchain, quand l'individu sert au collectif... malgré lui
 
Le jeu vidéo à la rescousse du web
Le jeu vidéo à la rescousse du webLe jeu vidéo à la rescousse du web
Le jeu vidéo à la rescousse du web
 
Frameworks : A history of violence
Frameworks : A history of violenceFrameworks : A history of violence
Frameworks : A history of violence
 
Php 100k
Php 100kPhp 100k
Php 100k
 
La migration continue vers Symfony
La migration continue vers SymfonyLa migration continue vers Symfony
La migration continue vers Symfony
 
La programmation asynchrone... et les pates
La programmation asynchrone... et les patesLa programmation asynchrone... et les pates
La programmation asynchrone... et les pates
 
Ce bon vieux propel
Ce bon vieux propelCe bon vieux propel
Ce bon vieux propel
 
Symfony2 meets propel 1.5
Symfony2 meets propel 1.5Symfony2 meets propel 1.5
Symfony2 meets propel 1.5
 
Developing for Developers
Developing for DevelopersDeveloping for Developers
Developing for Developers
 
Simplify your professional web development with symfony
Simplify your professional web development with symfonySimplify your professional web development with symfony
Simplify your professional web development with symfony
 

Kürzlich hochgeladen

Secure your environment with UiPath and CyberArk technologies - Session 1
Secure your environment with UiPath and CyberArk technologies - Session 1Secure your environment with UiPath and CyberArk technologies - Session 1
Secure your environment with UiPath and CyberArk technologies - Session 1DianaGray10
 
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPA
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPAAnypoint Code Builder , Google Pub sub connector and MuleSoft RPA
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPAshyamraj55
 
Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)Commit University
 
Machine Learning Model Validation (Aijun Zhang 2024).pdf
Machine Learning Model Validation (Aijun Zhang 2024).pdfMachine Learning Model Validation (Aijun Zhang 2024).pdf
Machine Learning Model Validation (Aijun Zhang 2024).pdfAijun Zhang
 
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1DianaGray10
 
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019IES VE
 
NIST Cybersecurity Framework (CSF) 2.0 Workshop
NIST Cybersecurity Framework (CSF) 2.0 WorkshopNIST Cybersecurity Framework (CSF) 2.0 Workshop
NIST Cybersecurity Framework (CSF) 2.0 WorkshopBachir Benyammi
 
Salesforce Miami User Group Event - 1st Quarter 2024
Salesforce Miami User Group Event - 1st Quarter 2024Salesforce Miami User Group Event - 1st Quarter 2024
Salesforce Miami User Group Event - 1st Quarter 2024SkyPlanner
 
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...DianaGray10
 
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDEADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDELiveplex
 
UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6DianaGray10
 
UiPath Solutions Management Preview - Northern CA Chapter - March 22.pdf
UiPath Solutions Management Preview - Northern CA Chapter - March 22.pdfUiPath Solutions Management Preview - Northern CA Chapter - March 22.pdf
UiPath Solutions Management Preview - Northern CA Chapter - March 22.pdfDianaGray10
 
Building Your Own AI Instance (TBLC AI )
Building Your Own AI Instance (TBLC AI )Building Your Own AI Instance (TBLC AI )
Building Your Own AI Instance (TBLC AI )Brian Pichman
 
AI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity WebinarAI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity WebinarPrecisely
 
Empowering Africa's Next Generation: The AI Leadership Blueprint
Empowering Africa's Next Generation: The AI Leadership BlueprintEmpowering Africa's Next Generation: The AI Leadership Blueprint
Empowering Africa's Next Generation: The AI Leadership BlueprintMahmoud Rabie
 
UiPath Studio Web workshop series - Day 7
UiPath Studio Web workshop series - Day 7UiPath Studio Web workshop series - Day 7
UiPath Studio Web workshop series - Day 7DianaGray10
 
9 Steps For Building Winning Founding Team
9 Steps For Building Winning Founding Team9 Steps For Building Winning Founding Team
9 Steps For Building Winning Founding TeamAdam Moalla
 
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...UbiTrack UK
 
Videogame localization & technology_ how to enhance the power of translation.pdf
Videogame localization & technology_ how to enhance the power of translation.pdfVideogame localization & technology_ how to enhance the power of translation.pdf
Videogame localization & technology_ how to enhance the power of translation.pdfinfogdgmi
 

Kürzlich hochgeladen (20)

Secure your environment with UiPath and CyberArk technologies - Session 1
Secure your environment with UiPath and CyberArk technologies - Session 1Secure your environment with UiPath and CyberArk technologies - Session 1
Secure your environment with UiPath and CyberArk technologies - Session 1
 
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPA
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPAAnypoint Code Builder , Google Pub sub connector and MuleSoft RPA
Anypoint Code Builder , Google Pub sub connector and MuleSoft RPA
 
Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)
 
Machine Learning Model Validation (Aijun Zhang 2024).pdf
Machine Learning Model Validation (Aijun Zhang 2024).pdfMachine Learning Model Validation (Aijun Zhang 2024).pdf
Machine Learning Model Validation (Aijun Zhang 2024).pdf
 
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
 
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
 
NIST Cybersecurity Framework (CSF) 2.0 Workshop
NIST Cybersecurity Framework (CSF) 2.0 WorkshopNIST Cybersecurity Framework (CSF) 2.0 Workshop
NIST Cybersecurity Framework (CSF) 2.0 Workshop
 
Salesforce Miami User Group Event - 1st Quarter 2024
Salesforce Miami User Group Event - 1st Quarter 2024Salesforce Miami User Group Event - 1st Quarter 2024
Salesforce Miami User Group Event - 1st Quarter 2024
 
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
 
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDEADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
 
UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6
 
UiPath Solutions Management Preview - Northern CA Chapter - March 22.pdf
UiPath Solutions Management Preview - Northern CA Chapter - March 22.pdfUiPath Solutions Management Preview - Northern CA Chapter - March 22.pdf
UiPath Solutions Management Preview - Northern CA Chapter - March 22.pdf
 
Building Your Own AI Instance (TBLC AI )
Building Your Own AI Instance (TBLC AI )Building Your Own AI Instance (TBLC AI )
Building Your Own AI Instance (TBLC AI )
 
AI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity WebinarAI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity Webinar
 
Empowering Africa's Next Generation: The AI Leadership Blueprint
Empowering Africa's Next Generation: The AI Leadership BlueprintEmpowering Africa's Next Generation: The AI Leadership Blueprint
Empowering Africa's Next Generation: The AI Leadership Blueprint
 
UiPath Studio Web workshop series - Day 7
UiPath Studio Web workshop series - Day 7UiPath Studio Web workshop series - Day 7
UiPath Studio Web workshop series - Day 7
 
9 Steps For Building Winning Founding Team
9 Steps For Building Winning Founding Team9 Steps For Building Winning Founding Team
9 Steps For Building Winning Founding Team
 
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
 
Videogame localization & technology_ how to enhance the power of translation.pdf
Videogame localization & technology_ how to enhance the power of translation.pdfVideogame localization & technology_ how to enhance the power of translation.pdf
Videogame localization & technology_ how to enhance the power of translation.pdf
 
20150722 - AGV
20150722 - AGV20150722 - AGV
20150722 - AGV
 

Bonnes pratiques de développement avec Node js

  • 1. Bonnes pratiques de développement avec Node.js François Zaninotto @francoisz http://github.com/fzaninotto
  • 4. Node.js ne suffit pas et vous ne pouvez pas réinventer la roue
  • 5. Organisation du code Objectif: éviter le code spaghetti Utiliser 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
  • 6. // main app.js var 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' })); }); // Routes app.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);
  • 7. // dashboard app var 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')); }); // Routes app.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); }
  • 8. // dashboard app var 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')); }); // Routes app.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); }
  • 9. <!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>
  • 10. <!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>
  • 11. Standards Felix's Node.js Style Guide (http://nodeguide.com/style.html) Object-Oriented Programming FTW Domain-Driven Design!
  • 12. 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'));
  • 13. 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'));
  • 14. 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'));
  • 15. Canaux de communication Dans un module Entre applications Client / Serveur ou une application Appels de Notifications Events socket.io méthodes Echanges de Appels de XMLHTTP API HTTP données méthode Request Traitements Promise AMQP Mentir* asynchrones
  • 16. // server-side var 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()); });
  • 17. // 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>
  • 18. Gestions des erreurs try {} catch {} ne marche pas en asynchrone function (err, results) est la signature standard des callbacks asynchrones "Leave early" Utiliser les codes d’erreur HTTP pour les APIs
  • 19. 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'); }); }); });
  • 20. Tests Unitaires Librairies (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 bien Pas besoin de mocker quand on peut monkey-patcher
  • 21. 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(); }) }) }) })
  • 22. 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'} );
  • 23. Projet open-source Configurable app.configure() pas compatible avec un SCM lorenwest/node-config (ou flatiron/nconf) Extensible Custom events Plugin architecture
  • 24. // in main app.js path.exists('./plugins/index.js', function(exists) { if (exists) { require('./plugins').init(app, io, config); }; }); // in plugins/index.js exports.init = function(app, io, config) { require('./console').init(); }
  • 25. 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); }); };
  • 26. Questions ? François Zaninotto @francoisz http://github.com/fzaninotto