SlideShare a Scribd company logo
Bonnes pratiques de
développement avec Node.js
              François Zaninotto
     @francoisz http://github.com/fzaninotto
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

More Related Content

What's hot

Containers & Dependency in Ember.js
Containers & Dependency in Ember.jsContainers & Dependency in Ember.js
Containers & Dependency in Ember.js
Matthew 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.js
soft-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 Galkin
Fwdays
 
Reactive, component 그리고 angular2
Reactive, component 그리고  angular2Reactive, component 그리고  angular2
Reactive, component 그리고 angular2
Jeado 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 Django
Javier Abadía
 
Java script for web developer
Java script for web developerJava script for web developer
Java script for web developer
Chalermpon Areepong
 
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
VMware Tanzu
 
Workshop 14: AngularJS Parte III
Workshop 14: AngularJS Parte IIIWorkshop 14: AngularJS Parte III
Workshop 14: AngularJS Parte III
Visual 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 2013
Laurent_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 Woudenberg
Xebia Nederland BV
 
Aplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com BackboneAplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com Backbone
Rafael 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 Support
Ben Scofield
 
Asynchronous programming done right - Node.js
Asynchronous programming done right - Node.jsAsynchronous programming done right - Node.js
Asynchronous programming done right - Node.js
Piotr 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 Karma
ExoLeaders.com
 
Viking academy backbone.js
Viking academy  backbone.jsViking academy  backbone.js
Viking academy backbone.js
Bert 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.js
Timur Shemsedinov
 
Ruby - Design patterns tdc2011
Ruby - Design patterns tdc2011Ruby - Design patterns tdc2011
Ruby - Design patterns tdc2011
Rafael Felix da Silva
 
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
 

What's hot (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)
 

Similar to 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 .NET
Gianluca 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.io
Steven 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
 
Rails is not just Ruby
Rails is not just RubyRails is not just Ruby
Rails is not just Ruby
Marco Otte-Witte
 
Javascript Frameworks for Joomla
Javascript Frameworks for JoomlaJavascript Frameworks for Joomla
Javascript Frameworks for JoomlaLuke Summerfield
 
Asynchronous Interfaces
Asynchronous InterfacesAsynchronous Interfaces
Asynchronous Interfaces
maccman
 
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 websites
Lindsay Holmwood
 
Rich Portlet Development in uPortal
Rich Portlet Development in uPortalRich Portlet Development in uPortal
Rich Portlet Development in uPortal
Jennifer Bourey
 
前端MVC 豆瓣说
前端MVC 豆瓣说前端MVC 豆瓣说
前端MVC 豆瓣说Ting Lv
 
Primefaces Nextgen Lju
Primefaces Nextgen LjuPrimefaces Nextgen Lju
Primefaces Nextgen Lju
Skills 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 Reactive
Jeff Smith
 

Similar to 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
 

More from 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
 
GraphQL, l'avenir du REST ?
GraphQL, l'avenir du REST ?GraphQL, l'avenir du REST ?
GraphQL, l'avenir du REST ?
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é lui
Francois 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 web
Francois Zaninotto
 
Frameworks : A history of violence
Frameworks : A history of violenceFrameworks : A history of violence
Frameworks : A history of violence
Francois Zaninotto
 
Php 100k
Php 100kPhp 100k
La migration continue vers Symfony
La migration continue vers SymfonyLa migration continue vers Symfony
La migration continue vers Symfony
Francois Zaninotto
 
La programmation asynchrone... et les pates
La programmation asynchrone... et les patesLa programmation asynchrone... et les pates
La programmation asynchrone... et les pates
Francois Zaninotto
 
Ce bon vieux propel
Ce bon vieux propelCe bon vieux propel
Ce bon vieux propel
Francois Zaninotto
 
Symfony2 meets propel 1.5
Symfony2 meets propel 1.5Symfony2 meets propel 1.5
Symfony2 meets propel 1.5
Francois Zaninotto
 
Developing for Developers
Developing for DevelopersDeveloping for Developers
Developing for Developers
Francois 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 symfony
Francois Zaninotto
 

More from 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
 

Recently uploaded

IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptxIOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
Abida Shariff
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
Prayukth K V
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
DanBrown980551
 
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMsTo Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
Paul Groth
 
Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*
Frank van Harmelen
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
Kari Kakkonen
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
Laura Byrne
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
Cheryl Hung
 
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualitySoftware Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Inflectra
 
When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
Elena Simperl
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
Elena Simperl
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
Alison B. Lowndes
 
Essentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with ParametersEssentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with Parameters
Safe Software
 
Leading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdfLeading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdf
OnBoard
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
James Anderson
 
ODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User GroupODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User Group
CatarinaPereira64715
 
PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)
Ralf Eggert
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
ThousandEyes
 
How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
Product School
 

Recently uploaded (20)

IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptxIOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
 
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMsTo Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
 
Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
 
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualitySoftware Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
 
When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
 
Essentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with ParametersEssentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with Parameters
 
Leading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdfLeading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdf
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
 
ODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User GroupODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User Group
 
PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
 
How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
 

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
  • 2.
  • 3.
  • 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