Successfully reported this slideshow.
@flaviohalmeida
flavio.almeida@caelum.com.br
FLÁVIO ALMEIDA
Java
C#
Python
Ruby
Groovy
JavaScript
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”
- Marti...
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
si...
Língua franca ou torre de babel?
ESTRUTURA TABULAR E RELACIONAL, SQL
POJO (PLAIN OLD JAVA OBJECTS)
JSON (JAVASCRIPT OBJECT...
"Não são as respostas que
movem o mundo, são
as perguntas”
— Albert Einstein
Testes de unidade
Testes de integraçãoOne commit deploy
Integração contínua
(Travis)
Grunt
(Automação)
Bootstrap
Karma
(Ja...
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
MongoDB
Express
AngularJS
Nodejs
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"...
Era do Extreme Go Horse
2005
2010
Backbone
Angular
Era dos Frameworks
2009
2011
Batman
2012
Ember
a) Popularidade meteórica
b) Pioneiro na injeção de dependências
c) Solução própria para criação de módulos
d) Sistema pró...
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: ...
2012
VALERI KARPOV
Cunhou o acrônimo MEAN para denotar as
tecnologias utilizadas durante uma competição
de hackathron que ...
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 pa...
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>
</htm...
SPA desde o início
angular.module('minhaApp', ['ngRoute'])
.config(function($routeProvider) {
$routeProvider.when('/fotos'...
Menor impedância
ESTRUTURA TABULAR E RELACIONAL
Autor autor = new Autor();
autor.setNome(…);
{
"_id": "1"
"nome": "Flávio ...
Menor impedância
{
"_id": ObjectId("5303e0649fd139619aeb783e")
"nome": "Flávio Almeida"
}
{
"_id": "5303e0649fd139619aeb78...
Menor impedância
$http('/v1/fotos')
.then(function(fotos){
$scope.fotos = fotos;
});
app.get('v1/fotos', function(req, res...
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);
}
);
con...
Mas na prática, é tudo
essa maravilha?
Não há um Scaffold
consolidado
mean.io
VS
mean.js
Você já implementou um DAO, não importa a
linguagem?
DAO pattern
dao.porNome = function(nomeProcurado, cb) {
db.collection('contatos')
.findOne({nome : procurado}, function(er...
Callback HELL
dao.porNome('Flávio Almeida', function(erro, contato) {
if(erro) throw console.log(erro);
dao.dependenteDoCo...
Callback HELL
dao.porNome('Flávio Almeida', function(erro, contato) {
if(erro) throw console.log(erro);
dao.dependenteDoCo...
Synchronous Heaven
try {
var contato = dao.porNome('Flávio Almeida');
var dependente = dao.depententeDoContato(contato);
c...
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.dependenteDoCo...
Promise Pattern
dao.porNome('Flávio Almeida')
.then(dao.depententeDoContato)
.then(dao.adicionaBeneficio)
.then(function(a...
DAO pattern
dao.porNome = function(nomeProcurado, cb) {
db.collection('contatos')
.findOne({nome : procurado}, function(er...
DAO + Promise Pattern
dao.porNome = function(nomeProcurado) {
return Q.Promise(function(resolve, reject) {
db.collection('...
Promise Pattern
dao.porNome('Flávio Almeida')
.then(dao.depententeDoContato)
.then(dao.adicionaBeneficio)
.then(function(a...
Synchronous Heaven
try {
var contato = dao.porNome('Flávio Almeida');
var dependente = dao.depententeDoContato(contato);
c...
Promise Pattern
dao.porNome('Flávio Almeida')
.then(dao.depententeDoContato)
.then(dao.adicionaBeneficio)
.then(function(a...
Q.async(function*() {
try {
var contato = yield dao.porNome('Flávio Almeida');
var dependente = yield dao.depententeDoCont...
Synchronous Heaven
try {
var contato = dao.porNome('Flávio Almeida');
var dependente = dao.depententeDoContato(contato);
c...
Permite suspender a execução no meio de uma
função para mais tarde retomá-la
Generator
Generator
function * meuGerador() {
var num1 = 1;
var num2 = 2;
var num3 = 3;
yield num1;
yield num2;
yield num3;
}
var ge...
Generators e Promises
Q.async(function*() {
try {
var contato = yield dao.porNome('Flávio Almeida');
var dependente = yiel...
Synchronous Heaven
try {
var contato = dao.porNome('Flávio Almeida');
var dependente = dao.depententeDoContato(contato);
c...
Synchronous Heaven
try {
var contato = dao.porNome('Flávio Almeida');
var dependente = dao.depententeDoContato(contato);
c...
try {
var contato = yield dao.porNome('Flávio Almeida');
var dependente = yield dao.depententeDoContato(contato);
console....
E as ferramentas de BI do cliente?
Injection Free!
Injection Free
// Controller ExpressJS
controller.removeContato = function(req, res)
{
var _id = req.params.id;
Contato.re...
{"_id" : { "$ne" : null}}
Injection Free???
// Controller ExpressJS
controller.removeContato = function(req, res)
{
var _i...
{"_id" : { "$ne" : null}}
Agora, Injection Free
// Controller ExpressJS
var sanitize = require(‘mongo-sanitize');
controll...
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...
Document Replace
controller.salvaContato = function(req, res) {
var _id = req.body._id;
var dados = {
"nome" : req.body.no...
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?
Flávio Almeida MEAN Stack "to be or not to be mean"
Flávio Almeida MEAN Stack "to be or not to be mean"
Flávio Almeida MEAN Stack "to be or not to be mean"
Flávio Almeida MEAN Stack "to be or not to be mean"
Flávio Almeida MEAN Stack "to be or not to be mean"
Flávio Almeida MEAN Stack "to be or not to be mean"
Flávio Almeida MEAN Stack "to be or not to be mean"
Flávio Almeida MEAN Stack "to be or not to be mean"
Flávio Almeida MEAN Stack "to be or not to be mean"
Flávio Almeida MEAN Stack "to be or not to be mean"
Flávio Almeida MEAN Stack "to be or not to be mean"
Flávio Almeida MEAN Stack "to be or not to be mean"
Flávio Almeida MEAN Stack "to be or not to be mean"
Flávio Almeida MEAN Stack "to be or not to be mean"
Flávio Almeida MEAN Stack "to be or not to be mean"
Flávio Almeida MEAN Stack "to be or not to be mean"
Flávio Almeida MEAN Stack "to be or not to be mean"
Próximos SlideShares
Carregando em…5
×

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

843 visualizações

Publicada em

Slides da palestra "to be or not to be MEAN" de Flávio Almeida. A MEAN Stack é uma solução completa para desenvolvimento de Single Page Applications (SPA) na plataforma Node.js utilizando AngularJS para views dinâmicas, Express para construir API's REST de alto nível e MongoDB para persistência. A combinação desse quarteto resulta na onipresença da linguagem JavaScript em todas as camadas da aplicação. Mas será que essa característica é o grande diferencial da stack? Que outros benefícios ela oferece para o desenvolvimento profissional de aplicações? Há limitações?

Publicada em: Tecnologia
  • Seja o primeiro a comentar

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

  1. 1. @flaviohalmeida flavio.almeida@caelum.com.br FLÁVIO ALMEIDA
  2. 2. Java C# Python Ruby Groovy JavaScript
  3. 3. Desenvolvedor Java à procura da menor impedância para construção de aplicações web Once upon a time…
  4. 4. Impedância?
  5. 5. Impedância “Discrepância da estrutura dos dados armazenados no banco de dados e as estruturas de dados em memória” - Martin Fowler
  6. 6. Impedância ESTRUTURA TABULAR E RELACIONAL, SQL POJO (PLAIN OLD JAVA OBJECTS) JSON (JAVASCRIPT OBJECT NOTATION)
  7. 7. Isomorphic JavaScript Back-end e front-end compartilham o mesmo código
  8. 8. JavaScript é considerada a língua franca da web
  9. 9. 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.
  10. 10. Língua franca ou torre de babel? ESTRUTURA TABULAR E RELACIONAL, SQL POJO (PLAIN OLD JAVA OBJECTS) JSON (JAVASCRIPT OBJECT NOTATION)
  11. 11. "Não são as respostas que movem o mundo, são as perguntas” — Albert Einstein
  12. 12. Testes de unidade Testes de integraçãoOne commit deploy Integração contínua (Travis) Grunt (Automação) Bootstrap Karma (Jasmine) Protractor (Selenium) AngularJS
  13. 13. To be or not to be MEAN?
  14. 14. Tradução da palavra mean Adjetivos inferior, insignificante, malvado, mediano, pobre, ruim, sórdido, etc.
  15. 15. Significado do acrônimo MEAN MongoDB Express AngularJS Nodejs
  16. 16. Contexto Histórico
  17. 17. Contexto Histórico
  18. 18. Era do AJAX 2005 "Nova abordagem de criação de páginas web" - Jesse James Garret
  19. 19. 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
  20. 20. Era do Extreme Go Horse 2005
  21. 21. 2010 Backbone Angular Era dos Frameworks 2009 2011 Batman 2012 Ember
  22. 22. a) Popularidade meteórica b) Pioneiro na injeção de dependências c) Solução própria para criação de módulos d) Sistema próprio de rotas e) Two-way data binding f) Ferramentas para testes
  23. 23. Era "The Book is on the Table" 2013…
  24. 24. Progressive Enhancement X SPA
  25. 25. "Pensamos no que deveria ser e fechamos os olhos para o que é" - Michel Maffesoli
  26. 26. SPA's chegaram para ficar, quer você queira ou não Hoje é a “palavra de ordem“ em aplicações híbridas
  27. 27. Paralelamente…
  28. 28. 2009 Bancos que não se baseiam em esquemas (Eric Evans) N SQL
  29. 29. 2009 Banco NoSQL baseado em documento BSON, MUITO semelhante ao JSON, porém com mais tipos
  30. 30. 2009 Boa parte da responsabilidade das regras de validação fica nas mãos dos desenvolvedores.
  31. 31. 2009
  32. 32. Quero aplicações Web!!!
  33. 33. 2010
  34. 34. 2011
  35. 35. 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
  36. 36. 2012 VALERI KARPOV Cunhou o acrônimo MEAN para denotar as tecnologias utilizadas durante uma competição de hackathron que venceu.
  37. 37. MEAN
  38. 38. 2012 VALERI KARPOV Ascot Project Bookalokal
  39. 39. 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!
  40. 40. SPA desde o início ngRoute (default) ui-router (extensão)
  41. 41. 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>
  42. 42. SPA desde o início angular.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' }); });
  43. 43. 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)
  44. 44. 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)
  45. 45. 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}">
  46. 46. Performance Escalabilidade Estado no cliente, servidor stateless Single thread e non-blocking I/O
  47. 47. non-blocking I/O Tudo roda em paralelo, exceto seu código!
  48. 48. 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
  49. 49. Mas na prática, é tudo essa maravilha?
  50. 50. Não há um Scaffold consolidado mean.io VS mean.js
  51. 51. Você já implementou um DAO, não importa a linguagem?
  52. 52. 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.adicionaBeneficio = function(dependente, cb) { db.collection('beneficios') .insert(dependente, function(erro) { if (erro) cb('Não foi possível…’, null); cb(null, true); }); };
  53. 53. 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'); }); }); });
  54. 54. 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'); }); }); });
  55. 55. 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); }
  56. 56. Callback HELL No cliente (browser) acontece a mesma coisa!
  57. 57. Mas tem cura doutor?
  58. 58. Só se você fizer uma promessa!
  59. 59. 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'); }); }); });
  60. 60. 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); });
  61. 61. 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) ; }); }; (…)
  62. 62. 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) ; }); }); }; (...)
  63. 63. 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); });
  64. 64. 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!
  65. 65. 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); });
  66. 66. 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
  67. 67. 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); }
  68. 68. Permite suspender a execução no meio de uma função para mais tarde retomá-la Generator
  69. 69. Generator function * meuGerador() { var num1 = 1; var num2 = 2; var num3 = 3; yield num1; yield num2; yield num3; } var gerador = meuGerador(); console.log(gerador.next().value); // 1 console.log(gerador.next().value) // 2 console.log(gerador.next().value) // 3 console.log(gerador.next().value) // undefined
  70. 70. 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();
  71. 71. 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!
  72. 72. 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); }
  73. 73. 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
  74. 74. E as ferramentas de BI do cliente?
  75. 75. Injection Free!
  76. 76. 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}
  77. 77. {"_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); } ); };
  78. 78. {"_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); } ); };
  79. 79. Carlinhos Aguiar, document replace é uma …
  80. 80. PÉSSIMA IDEIA, SÍLVIO!
  81. 81. Document Replace controller.salvaContato = function(req, res) { var _id = req.body._id; Contato.findByIdAndUpdate(_id, req.body).exec() .then( // código omitido );
  82. 82. 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…
  83. 83. Sistema de Módulos AMD CommonJSES6 http://addyosmani.com/writing-modular-js/
  84. 84. Sistema de Módulos AMD CommonJSES6 http://addyosmani.com/writing-modular-js/
  85. 85. A luta deixa deixa de ser pela menor "impedância "e passa a ser por uma standardization dentro do ecossistema JavaScript.
  86. 86. MANK Alternativas à MEAN Stack MRKN MyEAN METEOR
  87. 87. Obrigado!
  88. 88. @flaviohalmeida flavio.almeida@caelum.com.br FLÁVIO ALMEIDA Perguntas?

×