@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
@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
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
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
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
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
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
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
{ 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
{ 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
net.connect(1337, function () { var agent = new Agent() agent.connect(socket, function (err, api) { api.someMethod(args, function (err, result) { // ... }) }) }) Saturday, October 19, 13
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
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
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
• 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