Slide 1

Slide 1 text

@gimenete @backbeamio http://backbeam.io Alberto Gimeno Desafíos y lecciones aprendidas haciendo grandes aplicaciones con Node.js Saturday, October 19, 13

Slide 2

Slide 2 text

Quién soy...? @gimenete @backbeamio Alberto Gimeno Saturday, October 19, 13

Slide 3

Slide 3 text

Quién soy...? @gimenete @backbeamio Alberto Gimeno • Alberto Gimeno @gimenete Saturday, October 19, 13

Slide 4

Slide 4 text

Quién soy...? @gimenete @backbeamio Alberto Gimeno • Alberto Gimeno @gimenete • Programador, emprendedor Saturday, October 19, 13

Slide 5

Slide 5 text

Quién soy...? @gimenete @backbeamio Alberto Gimeno • Alberto Gimeno @gimenete • Programador, emprendedor • Usando nodejs desde 2010 Saturday, October 19, 13

Slide 6

Slide 6 text

Quién soy...? @gimenete @backbeamio Alberto Gimeno • Alberto Gimeno @gimenete • Programador, emprendedor • Usando nodejs desde 2010 • Emprendiendo desde 2005 Saturday, October 19, 13

Slide 7

Slide 7 text

@gimenete @backbeamio Alberto Gimeno • http://backbeam.io • 100% Node.js • ~40k líneas de código Saturday, October 19, 13

Slide 8

Slide 8 text

JavaScript el más odiado y amado a la vez @gimenete @backbeamio Alberto Gimeno Saturday, October 19, 13

Slide 9

Slide 9 text

JavaScript el más odiado y amado a la vez @gimenete @backbeamio Alberto Gimeno • Un lenguaje, múltiples runtimes Saturday, October 19, 13

Slide 10

Slide 10 text

JavaScript el más odiado y amado a la vez @gimenete @backbeamio Alberto Gimeno • Un lenguaje, múltiples runtimes • Un lenguaje dinámico como cualquier otro, salvo que está por todas partes Saturday, October 19, 13

Slide 11

Slide 11 text

JavaScript el más odiado y amado a la vez @gimenete @backbeamio Alberto Gimeno • Un lenguaje, múltiples runtimes • Un lenguaje dinámico como cualquier otro, salvo que está por todas partes • Con sus WAT?! Como cualquier otro Saturday, October 19, 13

Slide 12

Slide 12 text

Encapsulación sin this ni prototype @gimenete @backbeamio Alberto Gimeno function parser() { ! var obj = {} // variables y métodos "públicos" ! var n = 1 // variables "privadas" ! // función "privada" ! function foo() {} ! // método público ! obj.bar = function () {} ! return obj } Saturday, October 19, 13

Slide 13

Slide 13 text

Flujo de ejecución @gimenete @backbeamio Alberto Gimeno var arr = [1, 2, 3] for (var i = 0; i < arr.length; i++) { somethingAsync(arr[i], function() { console.log(arr[i]) }) } Saturday, October 19, 13

Slide 14

Slide 14 text

Flujo de ejecución @gimenete @backbeamio Alberto Gimeno var arr = [1, 2, 3] for (var i = 0; i < arr.length; i++) { somethingAsync(arr[i], function() { console.log(arr[i]) }) } $ node example.js undefined undefined undefined Saturday, October 19, 13

Slide 15

Slide 15 text

Flujo de ejecución @gimenete @backbeamio Alberto Gimeno var arr = [1, 2, 3] for (var i = 0; i < arr.length; i++) { somethingAsync(arr[i], function() { console.log(arr[i]) }) } $ node example.js undefined undefined undefined Saturday, October 19, 13

Slide 16

Slide 16 text

Flujo de ejecución @gimenete @backbeamio Alberto Gimeno var arr = [1, 2, 3] for (var i = 0; i < arr.length; i++) { var item = arr[i] somethingAsync(item, function() { console.log(item) }) } Saturday, October 19, 13

Slide 17

Slide 17 text

Flujo de ejecución @gimenete @backbeamio Alberto Gimeno $ node example.js 3 3 3 var arr = [1, 2, 3] for (var i = 0; i < arr.length; i++) { var item = arr[i] somethingAsync(item, function() { console.log(item) }) } Saturday, October 19, 13

Slide 18

Slide 18 text

Flujo de ejecución @gimenete @backbeamio Alberto Gimeno $ node example.js 3 3 3 var arr = [1, 2, 3] for (var i = 0; i < arr.length; i++) { var item = arr[i] somethingAsync(item, function() { console.log(item) }) } Saturday, October 19, 13

Slide 19

Slide 19 text

Flujo de ejecución @gimenete @backbeamio Alberto Gimeno var arr = [1, 2, 3] async.eachSeries(arr, function(item, next) { console.log(item) somethingAsync(item, next) }, function() { console.log('done!') }) Saturday, October 19, 13

Slide 20

Slide 20 text

Flujo de ejecución @gimenete @backbeamio Alberto Gimeno $ node example.js 1 2 3 done! var arr = [1, 2, 3] async.eachSeries(arr, function(item, next) { console.log(item) somethingAsync(item, next) }, function() { console.log('done!') }) Saturday, October 19, 13

Slide 21

Slide 21 text

Flujo de ejecución @gimenete @backbeamio Alberto Gimeno $ node example.js 1 2 3 done! var arr = [1, 2, 3] async.eachSeries(arr, function(item, next) { console.log(item) somethingAsync(item, next) }, function() { console.log('done!') }) Hay otras muchas funciones: each(), eachLimit(), map, filter,... https://github.com/caolan/async Saturday, October 19, 13

Slide 22

Slide 22 text

Flujo de ejecución: combatir la pirámide @gimenete @backbeamio Alberto Gimeno function f1(cb) { ... } function f2(cb) { ... } async.series([f1, f2], function() { console.log('done!') }) Saturday, October 19, 13

Slide 23

Slide 23 text

¿Promesas? @gimenete @backbeamio Alberto Gimeno Saturday, October 19, 13

Slide 24

Slide 24 text

¿Promesas? @gimenete @backbeamio Alberto Gimeno • ✗ No resuelven la pirámide de la muerte Saturday, October 19, 13

Slide 25

Slide 25 text

¿Promesas? @gimenete @backbeamio Alberto Gimeno • ✗ No resuelven la pirámide de la muerte • ✓Desacoplan y gestionan el flujo Saturday, October 19, 13

Slide 26

Slide 26 text

¿Promesas? @gimenete @backbeamio Alberto Gimeno • ✗ No resuelven la pirámide de la muerte • ✓Desacoplan y gestionan el flujo • ✗ Nada que no puedas hacer con async Saturday, October 19, 13

Slide 27

Slide 27 text

¿Promesas? @gimenete @backbeamio Alberto Gimeno • ✗ No resuelven la pirámide de la muerte • ✓Desacoplan y gestionan el flujo • ✗ Nada que no puedas hacer con async • ✗ Añaden dependencias, incompatibilidades, y complejidades Saturday, October 19, 13

Slide 28

Slide 28 text

¿Promesas? @gimenete @backbeamio Alberto Gimeno • ✗ No resuelven la pirámide de la muerte • ✓Desacoplan y gestionan el flujo • ✗ Nada que no puedas hacer con async • ✗ Añaden dependencias, incompatibilidades, y complejidades http://gimenete.tumblr.com/post/47528626262/los-programadores-no- necesitamos-vanas-promesas Saturday, October 19, 13

Slide 29

Slide 29 text

Lidiando con el asincronismo @gimenete @backbeamio Alberto Gimeno function absolute(n, cb) { if (n >= 0) { cb(null, n) } cb(null, -n) } Saturday, October 19, 13

Slide 30

Slide 30 text

Lidiando con el asincronismo @gimenete @backbeamio Alberto Gimeno function absolute(n, cb) { if (n >= 0) { cb(null, n) } cb(null, -n) } ✗ La función no termina aquí, cb llamado dos veces! Saturday, October 19, 13

Slide 31

Slide 31 text

Solución: return @gimenete @backbeamio Alberto Gimeno function absolute(n, cb) { if (n >= 0) { return cb(null, n) } cb(null, -n) } Saturday, October 19, 13

Slide 32

Slide 32 text

Solución: return @gimenete @backbeamio Alberto Gimeno function absolute(n, cb) { if (n >= 0) { return cb(null, n) } cb(null, -n) } Podemos poner return delante y el código queda más compacto Saturday, October 19, 13

Slide 33

Slide 33 text

Funciones falsamente asíncronas (ej: la anterior :) @gimenete @backbeamio Alberto Gimeno function absolute(n, cb) { if (n >= 0) { return cb(null, n) } cb(null, -n) } absolute(-3, function(err, n) { console.log('foo') }) console.log('bar') Saturday, October 19, 13

Slide 34

Slide 34 text

Funciones falsamente asíncronas (ej: la anterior :) @gimenete @backbeamio Alberto Gimeno ¿Qué aparece primero en la consola? function absolute(n, cb) { if (n >= 0) { return cb(null, n) } cb(null, -n) } absolute(-3, function(err, n) { console.log('foo') }) console.log('bar') Saturday, October 19, 13

Slide 35

Slide 35 text

Funciones falsamente asíncronas (ej: la anterior :) @gimenete @backbeamio Alberto Gimeno function absolute(n, cb) { process.nextTick(function() { if (n >= 0) { return cb(null, n) } cb(null, -n) }) } absolute(-3, function(err, n) { console.log('foo') }) console.log('bar') Saturday, October 19, 13

Slide 36

Slide 36 text

Funciones falsamente asíncronas (ej: la anterior :) @gimenete @backbeamio Alberto Gimeno function absolute(n, cb) { process.nextTick(function() { if (n >= 0) { return cb(null, n) } cb(null, -n) }) } absolute(-3, function(err, n) { console.log('foo') }) console.log('bar') Si quieres usar el callback por lo que sea, mantén el comportamiento usando nextTick() o setInmediate() Saturday, October 19, 13

Slide 37

Slide 37 text

Lidiando con el asincronismo @gimenete @backbeamio Alberto Gimeno function find(arr, cb) { async.each(arr, function(item, next) { if (item > 3) { return cb(null, item) } next() }, function() { return cb(null) }) } Saturday, October 19, 13

Slide 38

Slide 38 text

Lidiando con el asincronismo @gimenete @backbeamio Alberto Gimeno function find(arr, cb) { async.each(arr, function(item, next) { if (item > 3) { return cb(null, item) } next() }, function() { return cb(null) }) } ✗ No hemos llamado a next() y el bucle no termina Saturday, October 19, 13

Slide 39

Slide 39 text

Organización del código. Problema 1: requires() @gimenete @backbeamio Alberto Gimeno var data = require('../core/data') var users = require('../core/users') var log = require('../core/log') var billing = require('../core/billing') var stats = require('../core/stats') Saturday, October 19, 13

Slide 40

Slide 40 text

Organización del código. Problema 1: requires() @gimenete @backbeamio Alberto Gimeno var data = require('../core/data') var users = require('../core/users') var log = require('../core/log') var billing = require('../core/billing') var stats = require('../core/stats') ✗ require() por todas partes Saturday, October 19, 13

Slide 41

Slide 41 text

Organización del código. Problema 2: arrastrar argumentos @gimenete @backbeamio Alberto Gimeno core.data.query(user, project, projectSettings, entity, query, params, callback) Saturday, October 19, 13

Slide 42

Slide 42 text

Solución @gimenete @backbeamio Alberto Gimeno // index.js exports.init = function() { var core = {} core.data = require('./core-data').init(core) core.users = require('./core-users').init(core) core.log = require('./core-log').init(core) core.billing = require('./core-billing').init(core) core.stats = require('./core-stats').init(core) return core } // core-data.js exports.init = function(core) { core.data = {} core.data.list = function() { ... } return core.data } /* uso */ var core = require('./core') core.data.query(...) Saturday, October 19, 13

Slide 43

Slide 43 text

Solución @gimenete @backbeamio Alberto Gimeno // index.js exports.init = function() { var core = {} core.data = require('./core-data').init(core) core.users = require('./core-users').init(core) core.log = require('./core-log').init(core) core.billing = require('./core-billing').init(core) core.stats = require('./core-stats').init(core) return core } // core-data.js exports.init = function(core) { core.data = {} core.data.list = function() { ... } return core.data } /* uso */ var core = require('./core') core.data.query(...) ✓Todos los módulos reciben “core” en su init() Saturday, October 19, 13

Slide 44

Slide 44 text

Solución @gimenete @backbeamio Alberto Gimeno // index.js exports.init = function() { var core = {} core.data = require('./core-data').init(core) core.users = require('./core-users').init(core) core.log = require('./core-log').init(core) core.billing = require('./core-billing').init(core) core.stats = require('./core-stats').init(core) return core } // core-data.js exports.init = function(core) { core.data = {} core.data.list = function() { ... } return core.data } /* uso */ var core = require('./core') core.data.query(...) ✓Todos los módulos reciben “core” en su init() ✓Sólo un require() Saturday, October 19, 13

Slide 45

Slide 45 text

Integrándolo en express @gimenete @backbeamio Alberto Gimeno app.use(function(req, res, next) { req.core = core.init() next() }) app.get('/foo/bar', authenticate, function(req, res) { var core = req.core }) Guardamos “core” en la request Saturday, October 19, 13

Slide 46

Slide 46 text

Integrándolo en express @gimenete @backbeamio Alberto Gimeno app.use(function(req, res, next) { req.core = core.init() next() }) app.get('/foo/bar', authenticate, function(req, res) { var core = req.core }) Guardamos “core” en la request ✓ Podemos acceder en todos los controladores Saturday, October 19, 13

Slide 47

Slide 47 text

Solución: middleware @gimenete @backbeamio Alberto Gimeno app.use(function(req, res, next) { req.core = core.init() res.on('header', function() { // para evitar referencias cíclicas delete req.core }) next() }) app.get('/foo/bar', authenticate, function(req, res) { var core = req.core var user = core.users.current }) Saturday, October 19, 13

Slide 48

Slide 48 text

Solución: middleware @gimenete @backbeamio Alberto Gimeno app.use(function(req, res, next) { req.core = core.init() res.on('header', function() { // para evitar referencias cíclicas delete req.core }) next() }) app.get('/foo/bar', authenticate, function(req, res) { var core = req.core var user = core.users.current }) Sólo necesario si guardamos “req” para evitar referencias cíclicas Saturday, October 19, 13

Slide 49

Slide 49 text

Solución: middleware @gimenete @backbeamio Alberto Gimeno app.use(function(req, res, next) { req.core = core.init() res.on('header', function() { // para evitar referencias cíclicas delete req.core }) next() }) app.get('/foo/bar', authenticate, function(req, res) { var core = req.core var user = core.users.current }) ✓Accedemos al estado sin arrastrar argumentos Sólo necesario si guardamos “req” para evitar referencias cíclicas Saturday, October 19, 13

Slide 50

Slide 50 text

Resultado @gimenete @backbeamio Alberto Gimeno Saturday, October 19, 13

Slide 51

Slide 51 text

Resultado @gimenete @backbeamio Alberto Gimeno • El middleware (ej: autenticación) tiene acceso al core. Saturday, October 19, 13

Slide 52

Slide 52 text

Resultado @gimenete @backbeamio Alberto Gimeno • El middleware (ej: autenticación) tiene acceso al core. • Los controladores llaman a 1 método del core. Saturday, October 19, 13

Slide 53

Slide 53 text

Resultado @gimenete @backbeamio Alberto Gimeno • El middleware (ej: autenticación) tiene acceso al core. • Los controladores llaman a 1 método del core. • El core queda independiente de expressjs. Saturday, October 19, 13

Slide 54

Slide 54 text

Resultado @gimenete @backbeamio Alberto Gimeno • El middleware (ej: autenticación) tiene acceso al core. • Los controladores llaman a 1 método del core. • El core queda independiente de expressjs. • Estructura de directorios Saturday, October 19, 13

Slide 55

Slide 55 text

Resultado @gimenete @backbeamio Alberto Gimeno • El middleware (ej: autenticación) tiene acceso al core. • Los controladores llaman a 1 método del core. • El core queda independiente de expressjs. • Estructura de directorios • core/core-*.js Saturday, October 19, 13

Slide 56

Slide 56 text

Resultado @gimenete @backbeamio Alberto Gimeno • El middleware (ej: autenticación) tiene acceso al core. • Los controladores llaman a 1 método del core. • El core queda independiente de expressjs. • Estructura de directorios • core/core-*.js • web/web-*.js Saturday, October 19, 13

Slide 57

Slide 57 text

Resultado @gimenete @backbeamio Alberto Gimeno • El middleware (ej: autenticación) tiene acceso al core. • Los controladores llaman a 1 método del core. • El core queda independiente de expressjs. • Estructura de directorios • core/core-*.js • web/web-*.js • api/api-*.js Saturday, October 19, 13

Slide 58

Slide 58 text

Problema: los argumentos siguen creciendo @gimenete @backbeamio Alberto Gimeno core.data.query(entity, q, cb) core.data.query(entity, q, params, cb) core.data.query(entity, q, params, limit, offset, cb) /* TypeError: undefined is not a function */ core.data.query('user', 'sort by name', function() { ... }) Saturday, October 19, 13

Slide 59

Slide 59 text

Problema: los argumentos siguen creciendo @gimenete @backbeamio Alberto Gimeno core.data.query(entity, q, cb) core.data.query(entity, q, params, cb) core.data.query(entity, q, params, limit, offset, cb) /* TypeError: undefined is not a function */ core.data.query('user', 'sort by name', function() { ... }) ✗ Si aumentamos los argumentos y no cambiamos todas las llamadas cb = undefined Saturday, October 19, 13

Slide 60

Slide 60 text

Los argumentos de las callbacks también pueden crecer @gimenete @backbeamio Alberto Gimeno cb(err) cb(err, objs, total) cb(err, objs, distances, total) cb(err, objs, distances, total, fromCache) Saturday, October 19, 13

Slide 61

Slide 61 text

Los argumentos de las callbacks también pueden crecer @gimenete @backbeamio Alberto Gimeno Y pueden ser inconsistentes: callbacks parecidos con los argumentos en diferentes posiciones cb(err) cb(err, objs, total) cb(err, objs, distances, total) cb(err, objs, distances, total, fromCache) Saturday, October 19, 13

Slide 62

Slide 62 text

Solución 1: agrupar argumentos en objetos @gimenete @backbeamio Alberto Gimeno // options core.data.query(options, cb) // result cb(err, result) Saturday, October 19, 13

Slide 63

Slide 63 text

Solución 2: objetos patrón comando @gimenete @backbeamio Alberto Gimeno // creamos el objeto var parser = new Parser(str) // configuramos el comportamiento parser.strict = true parser.ignoreComments = true parser.processShebang = true // ejecutamos parser.parse(cb) Saturday, October 19, 13

Slide 64

Slide 64 text

Solución 3: objetos patrón comando con llamadas encadenadas @gimenete @backbeamio Alberto Gimeno core.data.query.list(q, params).run(cb) core.data.query.geo(q, params).limit(100).run(cb) Saturday, October 19, 13

Slide 65

Slide 65 text

Solución 3: objetos patrón comando con llamadas encadenadas @gimenete @backbeamio Alberto Gimeno core.data.query.list(q, params).run(cb) core.data.query.geo(q, params).limit(100).run(cb) list() y geo() devuelven objetos con métodos run() y limit(). limit() devuelve this Saturday, October 19, 13

Slide 66

Slide 66 text

Excepciones @gimenete @backbeamio Alberto Gimeno Saturday, October 19, 13

Slide 67

Slide 67 text

Excepciones @gimenete @backbeamio Alberto Gimeno • Una excepción no gestionada te mata el thread en ejecución Saturday, October 19, 13

Slide 68

Slide 68 text

Excepciones @gimenete @backbeamio Alberto Gimeno • Una excepción no gestionada te mata el thread en ejecución • Pero JavaScript es single-thread... fuck! Saturday, October 19, 13

Slide 69

Slide 69 text

¿¿Dos filosofías?? @gimenete @backbeamio Alberto Gimeno Saturday, October 19, 13

Slide 70

Slide 70 text

¿¿Dos filosofías?? @gimenete @backbeamio Alberto Gimeno 1. Dejar que falle y reiniciar el servicio Saturday, October 19, 13

Slide 71

Slide 71 text

¿¿Dos filosofías?? @gimenete @backbeamio Alberto Gimeno 1. Dejar que falle y reiniciar el servicio 2. No fallar nunca Saturday, October 19, 13

Slide 72

Slide 72 text

¿¿Dos filosofías?? @gimenete @backbeamio Alberto Gimeno 1. Dejar que falle y reiniciar el servicio 2. No fallar nunca 3. Mejor no fallar nunca pero estar preparado: forever, monit Saturday, October 19, 13

Slide 73

Slide 73 text

Capturar errores: uncaughtException @gimenete @backbeamio Alberto Gimeno process.on('uncaughtException', function(err) { console.log('Caught exception: ' + err); process.exit(1); }); Saturday, October 19, 13

Slide 74

Slide 74 text

Capturar errores: uncaughtException @gimenete @backbeamio Alberto Gimeno process.on('uncaughtException', function(err) { console.log('Caught exception: ' + err); process.exit(1); }); Usar sólo para notificar el error (log). Termina el proceso ya que An unhandled exception means your application - and by extension node.js itself - is in an undefined state. Blindly resuming means anything could happen. http://nodejs.org/api/process.html#process_event_uncaughtexception Saturday, October 19, 13

Slide 75

Slide 75 text

Domains (desde node v0.8) @gimenete @backbeamio Alberto Gimeno Saturday, October 19, 13

Slide 76

Slide 76 text

Domains (desde node v0.8) @gimenete @backbeamio Alberto Gimeno ¿En serio? Saturday, October 19, 13

Slide 77

Slide 77 text

Domains (desde node v0.8) @gimenete @backbeamio Alberto Gimeno Domain error handlers are not a substitute for closing down your process when an error occurs. http://nodejs.org/api/ domain.html#domain_warning_don_t_ignore_errors ¿En serio? Saturday, October 19, 13

Slide 78

Slide 78 text

on(‘error’, cb) @gimenete @backbeamio Alberto Gimeno Si no gestionas el evento “error” las excepciones son lanzadas (throw) Saturday, October 19, 13

Slide 79

Slide 79 text

on(‘error’, cb) @gimenete @backbeamio Alberto Gimeno Error: socket hang up at createHangUpError (http.js:1360:15) at ServerResponse.OutgoingMessage._writeRaw (http.js:507:26) at ServerResponse.OutgoingMessage._send (http.js:476:15) at ServerResponse.OutgoingMessage.write (http.js:744:12) Si no gestionas el evento “error” las excepciones son lanzadas (throw) Saturday, October 19, 13

Slide 80

Slide 80 text

Saturday, October 19, 13

Slide 81

Slide 81 text

Saturday, October 19, 13

Slide 82

Slide 82 text

@gimenete @backbeamio Alberto Gimeno http.createServer(function (req, res) { req.on('error', errorHandler) res.on('error', errorHandler) req.socket.on('error', errorHandler) req.connection.on('error', errorHandler) app(req, res) }) Saturday, October 19, 13

Slide 83

Slide 83 text

@gimenete @backbeamio Alberto Gimeno No es solución completa: error “max listeners”. TODO: añadir listener sólo si no añadido http.createServer(function (req, res) { req.on('error', errorHandler) res.on('error', errorHandler) req.socket.on('error', errorHandler) req.connection.on('error', errorHandler) app(req, res) }) Saturday, October 19, 13

Slide 84

Slide 84 text

Excepciones: no más try-catch / throw? @gimenete @backbeamio Alberto Gimeno Saturday, October 19, 13

Slide 85

Slide 85 text

Excepciones: no más try-catch / throw? @gimenete @backbeamio Alberto Gimeno • No del todo Saturday, October 19, 13

Slide 86

Slide 86 text

Excepciones: no más try-catch / throw? @gimenete @backbeamio Alberto Gimeno • No del todo • JSON.parse() te la puede jugar. Ej: un webservice caído (twitter whale). Pon un try-catch SIEMPRE Saturday, October 19, 13

Slide 87

Slide 87 text

NPM @gimenete @backbeamio Alberto Gimeno Saturday, October 19, 13

Slide 88

Slide 88 text

NPM @gimenete @backbeamio Alberto Gimeno • npm outdated // npmedge Saturday, October 19, 13

Slide 89

Slide 89 text

NPM @gimenete @backbeamio Alberto Gimeno • npm outdated // npmedge • npm shrinkwrap Saturday, October 19, 13

Slide 90

Slide 90 text

NPM @gimenete @backbeamio Alberto Gimeno • npm outdated // npmedge • npm shrinkwrap • npm install Saturday, October 19, 13

Slide 91

Slide 91 text

NPM @gimenete @backbeamio Alberto Gimeno • npm outdated // npmedge • npm shrinkwrap • npm install • Qué mola también: mirar el código de los módulos Saturday, October 19, 13

Slide 92

Slide 92 text

Módulos esenciales @gimenete @backbeamio Alberto Gimeno Saturday, October 19, 13

Slide 93

Slide 93 text

Módulos esenciales @gimenete @backbeamio Alberto Gimeno • async Saturday, October 19, 13

Slide 94

Slide 94 text

Módulos esenciales @gimenete @backbeamio Alberto Gimeno • async • request Saturday, October 19, 13

Slide 95

Slide 95 text

Módulos esenciales @gimenete @backbeamio Alberto Gimeno • async • request • underscore Saturday, October 19, 13

Slide 96

Slide 96 text

Módulos esenciales @gimenete @backbeamio Alberto Gimeno • async • request • underscore • apn, nodemailer, shelljs Saturday, October 19, 13

Slide 97

Slide 97 text

JavaScript: Meta programación y extensibilidad @gimenete @backbeamio Alberto Gimeno Saturday, October 19, 13

Slide 98

Slide 98 text

JavaScript: Meta programación y extensibilidad @gimenete @backbeamio Alberto Gimeno • eval() // no es el demonio si se usa bien Saturday, October 19, 13

Slide 99

Slide 99 text

JavaScript: Meta programación y extensibilidad @gimenete @backbeamio Alberto Gimeno • eval() // no es el demonio si se usa bien • new Function() // mejor pero básicamente lo mismo Saturday, October 19, 13

Slide 100

Slide 100 text

JavaScript: Meta programación y extensibilidad @gimenete @backbeamio Alberto Gimeno • eval() // no es el demonio si se usa bien • new Function() // mejor pero básicamente lo mismo • módulo vm // sandboxing Saturday, October 19, 13

Slide 101

Slide 101 text

¿JavaScript más rápido que C? @gimenete @backbeamio Alberto Gimeno // convertir esto... function parseRow(columns, parser) { var row = {}; for (var i = 0; i < columns.length; i++) { row[columns[i].name] = parser.readColumnValue(); } } // en esto... var code = 'return {\n'; columns.forEach(function(column) { code += '"' + column.name + '":' + 'parser.readColumnValue(),\n'; }); code += '};\n'; var parseRow = new Function('columns', 'parser', code); https://github.com/felixge/faster-than-c Saturday, October 19, 13

Slide 102

Slide 102 text

Módulo vm: maravillosas posibilidades @gimenete @backbeamio Alberto Gimeno Saturday, October 19, 13

Slide 103

Slide 103 text

Módulo vm: maravillosas posibilidades @gimenete @backbeamio Alberto Gimeno • Haz tu app scriptable. hooks? Saturday, October 19, 13

Slide 104

Slide 104 text

Módulo vm: maravillosas posibilidades @gimenete @backbeamio Alberto Gimeno • Haz tu app scriptable. hooks? • Ej: imagina hooks directamente en github Saturday, October 19, 13

Slide 105

Slide 105 text

Módulo vm: maravillosas posibilidades @gimenete @backbeamio Alberto Gimeno • Haz tu app scriptable. hooks? • Ej: imagina hooks directamente en github • IFTTT pero en tu propia app (mandar SMS, notificaciones push, lógica condicional,...) Saturday, October 19, 13

Slide 106

Slide 106 text

Módulo vm: maravillosas posibilidades @gimenete @backbeamio Alberto Gimeno • Haz tu app scriptable. hooks? • Ej: imagina hooks directamente en github • IFTTT pero en tu propia app (mandar SMS, notificaciones push, lógica condicional,...) TODO: limitar uso de CPU y evitar bucles infinitos en los scripts Saturday, October 19, 13

Slide 107

Slide 107 text

Introspecciona tu propia app @gimenete @backbeamio Alberto Gimeno Saturday, October 19, 13

Slide 108

Slide 108 text

Introspecciona tu propia app @gimenete @backbeamio Alberto Gimeno • Módulo vm. Ejecuta scripts sin reiniciar Saturday, October 19, 13

Slide 109

Slide 109 text

Introspecciona tu propia app @gimenete @backbeamio Alberto Gimeno • Módulo vm. Ejecuta scripts sin reiniciar • replify https://github.com/dshaw/replify Saturday, October 19, 13

Slide 110

Slide 110 text

Introspecciona tu propia app @gimenete @backbeamio Alberto Gimeno • Módulo vm. Ejecuta scripts sin reiniciar • replify https://github.com/dshaw/replify • Agente Smith Saturday, October 19, 13

Slide 111

Slide 111 text

Agente smith servidor @gimenete @backbeamio Alberto Gimeno var api = { someMethod: function (args, callback) { // ... callback(null, result) } } net.createServer(function (socket) { var agent = new Agent(api) agent.connect(socket, function (err, api) { }) }).listen(1337, function () { console.log("Agent server listening on port 1337") }) Saturday, October 19, 13

Slide 112

Slide 112 text

Agente smith cliente @gimenete @backbeamio Alberto Gimeno var socket = net.connect(1337, function () { var agent = new Agent() agent.connect(socket, function (err, api) { api.someMethod(args, function (err, result) { // ... }) }) }) Saturday, October 19, 13

Slide 113

Slide 113 text

Multiproceso / multitarea @gimenete @backbeamio Alberto Gimeno Saturday, October 19, 13

Slide 114

Slide 114 text

Multiproceso / multitarea @gimenete @backbeamio Alberto Gimeno • Módulo cluster Saturday, October 19, 13

Slide 115

Slide 115 text

Multiproceso / multitarea @gimenete @backbeamio Alberto Gimeno • Módulo cluster • node-fibers Saturday, October 19, 13

Slide 116

Slide 116 text

Multiproceso / multitarea @gimenete @backbeamio Alberto Gimeno • Módulo cluster • node-fibers • compute-cluster Saturday, October 19, 13

Slide 117

Slide 117 text

Multiproceso / multitarea @gimenete @backbeamio Alberto Gimeno • Módulo cluster • node-fibers • compute-cluster https://github.com/lloyd/node-compute-cluster Saturday, October 19, 13

Slide 118

Slide 118 text

Despliegues y multiproceso @gimenete @backbeamio Alberto Gimeno Saturday, October 19, 13

Slide 119

Slide 119 text

Despliegues y multiproceso @gimenete @backbeamio Alberto Gimeno • Módulo cluster Saturday, October 19, 13

Slide 120

Slide 120 text

Despliegues y multiproceso @gimenete @backbeamio Alberto Gimeno • Módulo cluster • Crea un proxy inteligente Saturday, October 19, 13

Slide 121

Slide 121 text

Despliegues y multiproceso @gimenete @backbeamio Alberto Gimeno • Módulo cluster • Crea un proxy inteligente • A partir de http-proxy Saturday, October 19, 13

Slide 122

Slide 122 text

Despliegues y multiproceso @gimenete @backbeamio Alberto Gimeno • Módulo cluster • Crea un proxy inteligente • A partir de http-proxy • ej: SSL en caliente (SNICallback) Saturday, October 19, 13

Slide 123

Slide 123 text

Despliegues sin downtimes ni dropped connections @gimenete @backbeamio Alberto Gimeno Saturday, October 19, 13

Slide 124

Slide 124 text

Despliegues sin downtimes ni dropped connections @gimenete @backbeamio Alberto Gimeno 1. Proxy “inteligente” con agente smith Saturday, October 19, 13

Slide 125

Slide 125 text

Despliegues sin downtimes ni dropped connections @gimenete @backbeamio Alberto Gimeno 1. Proxy “inteligente” con agente smith 2. Lanza instancia Saturday, October 19, 13

Slide 126

Slide 126 text

Despliegues sin downtimes ni dropped connections @gimenete @backbeamio Alberto Gimeno 1. Proxy “inteligente” con agente smith 2. Lanza instancia 3. Cuando esté lista conecta al proxy y cambia el puerto Saturday, October 19, 13

Slide 127

Slide 127 text

Despliegues sin downtimes ni dropped connections @gimenete @backbeamio Alberto Gimeno 1. Proxy “inteligente” con agente smith 2. Lanza instancia 3. Cuando esté lista conecta al proxy y cambia el puerto 4. Mata la instancia vieja tras 1 minuto Saturday, October 19, 13

Slide 128

Slide 128 text

Testing y desarrollo @gimenete @backbeamio Alberto Gimeno Saturday, October 19, 13

Slide 129

Slide 129 text

Testing y desarrollo @gimenete @backbeamio Alberto Gimeno • Mocha + istanbul (mocha-istanbul) para cobertura Saturday, October 19, 13

Slide 130

Slide 130 text

Testing y desarrollo @gimenete @backbeamio Alberto Gimeno • Mocha + istanbul (mocha-istanbul) para cobertura • Haz que tu servicio pueda arrancarse desde un test Saturday, October 19, 13

Slide 131

Slide 131 text

Testing y desarrollo @gimenete @backbeamio Alberto Gimeno • Mocha + istanbul (mocha-istanbul) para cobertura • Haz que tu servicio pueda arrancarse desde un test • require(‘./app’).start(1337) Saturday, October 19, 13

Slide 132

Slide 132 text

Testing y desarrollo @gimenete @backbeamio Alberto Gimeno • Mocha + istanbul (mocha-istanbul) para cobertura • Haz que tu servicio pueda arrancarse desde un test • require(‘./app’).start(1337) • require(‘./app’).stop() Saturday, October 19, 13

Slide 133

Slide 133 text

Testing y desarrollo @gimenete @backbeamio Alberto Gimeno • Mocha + istanbul (mocha-istanbul) para cobertura • Haz que tu servicio pueda arrancarse desde un test • require(‘./app’).start(1337) • require(‘./app’).stop() • Usa process.env.NODE_ENV = ‘production’ / ‘development’ Saturday, October 19, 13

Slide 134

Slide 134 text

Más recomendaciones sobre Node.js en producción @gimenete @backbeamio Alberto Gimeno Saturday, October 19, 13

Slide 135

Slide 135 text

Más recomendaciones sobre Node.js en producción @gimenete @backbeamio Alberto Gimeno • node-measured + graphite Saturday, October 19, 13

Slide 136

Slide 136 text

Más recomendaciones sobre Node.js en producción @gimenete @backbeamio Alberto Gimeno • node-measured + graphite • logs: bunyan, raygun (servicio externo) Saturday, October 19, 13

Slide 137

Slide 137 text

Más recomendaciones sobre Node.js en producción @gimenete @backbeamio Alberto Gimeno • node-measured + graphite • logs: bunyan, raygun (servicio externo) • node-toobusy Saturday, October 19, 13

Slide 138

Slide 138 text

Más recomendaciones sobre Node.js en producción @gimenete @backbeamio Alberto Gimeno • node-measured + graphite • logs: bunyan, raygun (servicio externo) • node-toobusy https://hacks.mozilla.org/2013/01/building-a-node-js-server-that-wont-melt-a-node-js-holiday-season-part-5/ Building A Node.JS Server That Won’t Melt Saturday, October 19, 13

Slide 139

Slide 139 text

¡¡Gracias!! @gimenete @backbeamio Alberto Gimeno @gimenete @backbeamio Saturday, October 19, 13