Flávio Almeida MEAN Stack "to be or not to be mean"

Post on 08-Aug-2015

241 views 0 download

Transcript of Flávio Almeida MEAN Stack "to be or not to be mean"

@flaviohalmeida

flavio.almeida@caelum.com.br

FLÁVIO ALMEIDA

JavaC#PythonRubyGroovyJavaScript

Desenvolvedor Java à procura da menor impedância para construção

de aplicações web

Once upon a time…

Impedância?

Impedância

“Discrepância da estrutura dos dados armazenados no banco de dados e as estruturas de dados em memória” - Martin Fowler

Impedância

ESTRUTURA TABULAR E RELACIONAL, SQL

POJO (PLAIN OLD JAVA OBJECTS)

JSON (JAVASCRIPT OBJECT NOTATION)

Isomorphic JavaScript

Back-end e front-end compartilham o mesmo código

JavaScript é considerada a língua franca da web

Língua Franca

É aquela que um grupo multilíngue de pessoas intencionalmente adota ou desenvolve para que todos consigam sistematicamente comunicar-se uns com os outros.

Língua franca ou torre de babel?

ESTRUTURA TABULAR E RELACIONAL, SQL

POJO (PLAIN OLD JAVA OBJECTS)

JSON (JAVASCRIPT OBJECT NOTATION)

"Não são as respostas que movem o mundo, são as perguntas” — Albert Einstein

Testes de unidade

Testes de integração

One commit deploy

Integração contínua(Travis)

Grunt(Automaçã

o)

Bootstrap

Karma(Jasmine)

Protractor

(Selenium)

AngularJS

To be or not to be MEAN?

Tradução da palavra mean

Adjetivos

inferior, insignificante, malvado, mediano, pobre, ruim, sórdido, etc.

Significado do acrônimo MEAN

MongoDBExpressAngularJSNodejs

Contexto Histórico

Contexto Histórico

Era do AJAX 2005

"Nova abordagem de criação de páginas web" - Jesse James Garret

Era do SPA 2005

SINGLE PAGE APPLICATION

"Elementos de interface e lógica da aplicação são criados e executados no cliente" —Steve Yen

Era do Extreme Go Horse2005

2010 Backbone Angular

Era dos Frameworks2009

2011 Batman2012 Ember

a) Popularidade meteóricab) Pioneiro na injeção de dependênciasc) Solução própria para criação de módulosd) Sistema próprio de rotase) Two-way data bindingf) Ferramentas para testes

Era "The Book is on the Table" 2013…

Progressive Enhancement

X SPA

"Pensamos no que deveria ser e fechamos os olhos para o que é" - Michel Maffesoli

SPA's chegaram para ficar, quer você queira ou não

Hoje é a “palavra de ordem“ em aplicações híbridas

Paralelamente…

2009

Bancos que não se baseiam em esquemas (Eric Evans)

N SQL

2009

Banco NoSQL baseado em documento BSON, MUITO semelhante ao JSON, porém com mais tipos

2009

Boa parte da responsabilidade das regras de validação fica nas mãos dos desenvolvedores.

2009

Quero aplicações Web!!!

2010

2011

var mongoose = require('mongoose');

var schema = mongoose.Schema({ nome: { type: String, required: true }, email: { type: String, required: true, index: { unique: true } } }); return mongoose.model('Contato', schema);

2011

2012

VALERI KARPOV

Cunhou o acrônimo MEAN para denotar as tecnologias utilizadas durante uma

competição de hackathron que venceu.

MEAN

2012

VALERI KARPOV

Ascot Project

Bookalokal

Vantagens constatadas durante o Hackathon

SPA desde o início

Menor impedância

API REST

Isomorphic JavaScript*

* não era para você conseguir ler isso!

SPA desde o início

ngRoute (default)

ui-router(extensão)

SPA desde o início

<!— index.html —><html ng-app="minhaApp"> <head> (…) </head> <body> <ng-view> </ng-view> </body></html>

<!-- partials/cadastro.html --><h1>Cadastro de fotos</h1><form> (...)</form>

<!-- partials/listagem.html --><h1>Listagem de fotos</h1>

index.html/#/fotos

index.html/#/fotos/new

SPA desde o inícioangular.module('minhaApp', ['ngRoute']) .config(function($routeProvider) {

$routeProvider.when('/fotos', { templateUrl: 'partials/listagem.html', controller: 'FotosController' });

$routeProvider.when('/fotos/new', { templateUrl: 'partials/cadastro.html', controller: 'FotoController' }); });

Menor impedância

ESTRUTURA TABULAR E RELACIONAL

Autor autor = new Autor();autor.setNome(…);

{ "_id": "1" "nome": "Flávio Almeida"}

OUTROS

Navegador(JSON)

Banco(SQL)

Servidor(Object)

Menor impedância

{ "_id": ObjectId("5303e0649fd139619aeb783e") "nome": "Flávio Almeida"}

{ "_id": "5303e0649fd139619aeb783e" "nome": "Flávio Almeida"}

{ "_id": "5303e0649fd139619aeb783e" "nome": "Flávio Almeida"}

MEAN STACK

Navegador(JSON)

Banco(BSON)

Servidor(JSON)

Menor impedância

$http('/v1/fotos').then(function(fotos){ $scope.fotos = fotos;});

app.get('v1/fotos', function(req, res){ db.collection('contatos').find({}, function(erro, contatos){ if(erro) throw err; res.json(contatos); } });};

Client(Angular

)

Server (API REST)(Express/MongoDB driver)

<img ng-repeat="foto in fotos"

ng-src=“{foto.src}">

Performance

Escalabilidade

Estado no cliente, servidor stateless

Single thread e non-blocking I/O

non-blocking I/O

Tudo roda em paralelo, exceto seu código!

Blocking Vs non-blocking I/O

db.collection('contatos').find({}, function(erro, contatos) { console.log(contatos); });console.log('FIM');

var contatos = db.collection('contatos').find({});console.log(contatos);console.log('FIM');

Pseudo Blocking I/O

Non-blocking I/O

Mas na prática, é tudo essa maravilha?

Não há um Scaffold consolidado

mean.ioVS

mean.js

Você já implementou um DAO, não importa a linguagem?

DAO patterndao.porNome = function(nomeProcurado, cb) { db.collection('contatos') .findOne({nome : procurado}, function(erro, contato) { if (erro) cb('Não foi possível…', null); cb(null, contato); });};dao.dependenteDoContato = function(contato, cb) { db.collection('dependentes') .find({contatoId : contato_id}, function(erro, dependente) { if (erro) cb('Não foi possível…', null); cb(null, dependente) ; });};dao.adicionaBeneficio = function(dependente, cb) { db.collection('beneficios') .insert(dependente, function(erro) { if (erro) cb('Não foi possível…’, null); cb(null, true); });};

Callback HELL

dao.porNome('Flávio Almeida', function(erro, contato) { if(erro) throw console.log(erro); dao.dependenteDoContato(contato, function(erro, dependente) { if(erro) throw console.log(erro); dao.adicionaBeneficio(dependente, function(erro, adicionado){ if(erro) throw console.log(erro); if (adicionado) console.log('Benefício adicionado'); }); });});

Callback HELL

dao.porNome('Flávio Almeida', function(erro, contato) { if(erro) throw console.log(erro); dao.dependenteDoContato(contato, function(erro, dependente) { if(erro) throw console.log(erro); dao.adicionaBeneficio(dependente, function(erro, adicionado){ if(erro) throw console.log(erro); if (adicionado) console.log('Benefício adicionado'); }); });});

Synchronous Heaven

try { var contato = dao.porNome('Flávio Almeida'); var dependente = dao.depententeDoContato(contato); console.log(dao.adicionaBeneficio(dependente));} catch(erro) { console.log(erro);}

Callback HELL

No cliente (browser) acontece a mesma coisa!

Mas tem cura doutor?

Só se você fizer uma promessa!

Callback HELL

dao.porNome('Flávio Almeida', function(erro, contato) { if(erro) throw console.log(erro); dao.dependenteDoContato(contato, function(erro, dependente) { if(erro) throw console.log(erro); dao.adicionaBeneficio(dependente, function(erro, adicionado){ if(erro) throw console.log(erro); if (adicionado) console.log('Benefício adicionado'); }); });});

Promise Pattern

dao.porNome('Flávio Almeida').then(dao.depententeDoContato).then(dao.adicionaBeneficio).then(function(adicionado) { if (adicionado) console.log('Benefício adicionado’);}).catch(function(erro) { console.log(erro); });

DAO pattern

dao.porNome = function(nomeProcurado, cb) { db.collection('contatos') .findOne({nome : procurado}, function(erro, contato) { if (erro) cb('Não foi possível…', null); cb(null, contato); });};dao.dependenteDoContato = function(contato, cb) { db.collection('dependentes') .find({contatoId : contato_id}, function(erro, dependente) { if (erro) cb('Não foi possível…’, null); cb(null, dependente) ; });};(…)

DAO + Promise Pattern

dao.porNome = function(nomeProcurado) { return Q.Promise(function(resolve, reject) { db.collection('contatos') .findOne({nome : procurado}, function(erro, contato) { if (erro) reject(erro); resolve(contato); }); });};dao.dependenteDoContato = function(contato) { return Q.Promise(function(resolve, reject) { db.collection('dependentes') .find({contatoId : contato_id}, function(erro, dependente) { if (erro) reject(erro); resolve(dependente) ; }); }); };(...)

Promise Pattern

dao.porNome('Flávio Almeida').then(dao.depententeDoContato).then(dao.adicionaBeneficio).then(function(adicionado) { if (adicionado) console.log('Benefício adicionado');}).catch(function(erro) { console.log(erro); });

Synchronous Heaven

try { var contato = dao.porNome('Flávio Almeida'); var dependente = dao.depententeDoContato(contato); console.log(dao.adicionaBeneficio(dependente));} catch(erro) { console.log(erro);}

Mas eu ainda quero o paraíso!

Promise Pattern

dao.porNome('Flávio Almeida').then(dao.depententeDoContato).then(dao.adicionaBeneficio).then(function(adicionado) { if (adicionado) console.log('Benefício adicionado’);}).catch(function(erro) { console.log(erro); });

Q.async(function*() {try { var contato = yield dao.porNome('Flávio Almeida'); var dependente = yield dao.depententeDoContato(contato); console.log(yield dao.adicionaBeneficio(dependente));} catch(erro) { console.log(erro);}}).done();

É quase um paraíso

Synchronous Heaven

try { var contato = dao.porNome('Flávio Almeida'); var dependente = dao.depententeDoContato(contato); console.log(dao.adicionaBeneficio(dependente));} catch(erro) { console.log(erro);}

Permite suspender a execução no meio de uma função para mais tarde retomá-la

Generator

Generatorfunction * meuGerador() { var num1 = 1; var num2 = 2; var num3 = 3; yield num1; yield num2; yield num3;}

var gerador = meuGerador();console.log(gerador.next().value); // 1console.log(gerador.next().value) // 2console.log(gerador.next().value) // 3console.log(gerador.next().value) // undefined

Generators e Promises

Q.async(function*() {try { var contato = yield dao.porNome('Flávio Almeida'); var dependente = yield dao.depententeDoContato(contato); console.log(yield dao.adicionaBeneficio(dependente));} catch(erro) { console.log(erro);}}).done();

Synchronous Heaven

try { var contato = dao.porNome('Flávio Almeida'); var dependente = dao.depententeDoContato(contato); console.log(dao.adicionaBeneficio(dependente));} catch(erro) { console.log(erro);}

Mas eu ainda quero o paraíso!

Synchronous Heaven

try { var contato = dao.porNome('Flávio Almeida'); var dependente = dao.depententeDoContato(contato); console.log(dao.adicionaBeneficio(dependente));} catch(erro) { console.log(erro);}

try { var contato = yield dao.porNome('Flávio Almeida'); var dependente = yield dao.depententeDoContato(contato); console.log(yield dao.adicionaBeneficio(dependente));} catch(erro) { console.log(erro);}

Generators e Promises

E as ferramentas de BI do cliente?

Injection Free!

Injection Free

// Controller ExpressJS

controller.removeContato = function(req, res) { var _id = req.params.id; Contato.remove({'_id' : _id}).exec() .then(function() { res.status(204).end(); }, function(err) { return console.error(erro); } );};

{"_id" : 5}

{"_id" : { "$ne" : null}}

Injection Free???

// Controller ExpressJS

controller.removeContato = function(req, res) { var _id = req.params.id; Contato.remove({'_id' : _id}).exec() .then(function() { res.status(204).end(); }, function(err) { return console.error(erro); } );};

{"_id" : { "$ne" : null}}

Agora, Injection Free

// Controller ExpressJS

var sanitize = require(‘mongo-sanitize');

controller.removeContato = function(req, res) { var _id = sanitize(req.params.id); Contato.remove({'_id' : _id}).exec() .then(function() { res.status(204).end(); }, function(err) { return console.error(erro); } );};

Carlinhos Aguiar, document replace é uma …

PÉSSIMA IDEIA, SÍLVIO!

Document Replace

controller.salvaContato = function(req, res) { var _id = req.body._id; Contato.findByIdAndUpdate(_id, req.body).exec() .then( // código omitido );

Document Replace

controller.salvaContato = function(req, res) { var _id = req.body._id; var dados = { "nome" : req.body.nome, "email" : req.body.email }; Contato.findByIdAndUpdate(_id, dados).exec()

Pince os dados…

Sistema de Módulos

AMD CommonJSES6

http://addyosmani.com/writing-modular-js/

Sistema de Módulos

AMD CommonJSES6

http://addyosmani.com/writing-modular-js/

A luta deixa deixa de ser pela menor "impedância "e passa a ser por uma

standardization dentro do ecossistema JavaScript.

MANK

Alternativas à MEAN Stack

MRKN

MyEAN

METEOR

Obrigado!

@flaviohalmeida

flavio.almeida@caelum.com.br

FLÁVIO ALMEIDA

Perguntas?