SlideShare uma empresa Scribd logo
1 de 26
Baixar para ler offline
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

Mais conteúdo relacionado

Mais procurados

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
 

Mais procurados (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)
 

Semelhante a 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
 

Semelhante a 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
 

Mais de 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
 

Mais de 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
 

Último

Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfRankYa
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningLars Bell
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionDilum Bandara
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 

Último (20)

Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdf
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine Tuning
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An Introduction
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 

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