O documento discute os benefícios e desafios do uso da plataforma Node.js para construir um gateway de pagamentos online. Node.js é adequado para este caso devido à natureza assíncrona e de I/O intensiva da aplicação. Entretanto, o código assíncrono em Node.js pode se tornar complexo e causar problemas, e a plataforma ainda está em desenvolvimento. Abordagens como testes, padronização e microserviços podem ajudar a superar esses desafios.
5. • O problema
• Por que Node.js?
• Problemas de Node.js
Assuntos
6. • O problema
• Por que Node.js?
• Problemas de Node.js
• Node.js“the right way”
Assuntos
7. • O problema
• Por que Node.js?
• Problemas de Node.js
• Node.js“the right way”
• Repensando a infraestrutura (+ Microservices)
Assuntos
8. • O problema
• Por que Node.js?
• Problemas de Node.js
• Node.js“the right way”
• Repensando a infraestrutura (+ Microservices)
• Deployment (+ Continuous Integration)
Assuntos
9. • O problema
• Por que Node.js?
• Problemas de Node.js
• Node.js“the right way”
• Repensando a infraestrutura (+ Microservices)
• Deployment (+ Continuous Integration)
• Conclusões…
Assuntos
17. • Simplicidade: RESTful + JSON
• Ambiente de testes isolado e decente
• Segurança sem comprometer simplicidade (PCI)
Premissas da API
18. • Simplicidade: RESTful + JSON
• Ambiente de testes isolado e decente
• Segurança sem comprometer simplicidade (PCI)
• Uptime de 99,9%
Premissas da API
19. • Simplicidade: RESTful + JSON
• Ambiente de testes isolado e decente
• Segurança sem comprometer simplicidade (PCI)
• Uptime de 99,9%
• Escalabilidade
Premissas da API
21. Por que Node.js?
Request de transação
API RESTful
Sistema antifraude
fraude
legítimaAdquirente
(Cielo, Rede, etc)
sucesso/erro
erro
22. Por que Node.js?
Request de transação
API RESTful
Sistema antifraude
fraude
legítimaAdquirente
(Cielo, Rede, etc)
10.000 ms
3.000
m
s
sucesso/erro
erro
25. Por que Node.js?
(no nosso caso)
• Requests externos demorados (>1.000ms)
• I/O intenso em banco de dados
26. Por que Node.js?
(no nosso caso)
• Requests externos demorados (>1.000ms)
• I/O intenso em banco de dados
• Totalmente assíncrono, single thread e event-based
27. Por que Node.js?
(no nosso caso)
• Requests externos demorados (>1.000ms)
• I/O intenso em banco de dados
• Totalmente assíncrono, single thread e event-based
• Alta carga na aplicação
28. Por que Node.js?
(no nosso caso)
• Requests externos demorados (>1.000ms)
• I/O intenso em banco de dados
• Totalmente assíncrono, single thread e event-based
• Alta carga na aplicação
• Pouco processamento (sem blocking de CPU)
29. Por que Node.js?
(no nosso caso)
“Mas é só usar threads em qualquer
linguagem!..”
30. Por que Node.js?
(no nosso caso)
“Mas é só usar threads em qualquer
linguagem!..”
Não.
31. Por que Node.js?
(no nosso caso)
1.000 requests por segundo com conexão a uma API
externa + I/O no DB = 1.000 threads por segundo
32. Por que Node.js?
(no nosso caso)
1.000 requests por segundo com conexão a uma API
externa + I/O no DB = 1.000 threads por segundo
… se cada request leva em média 10 segundos …
33. Por que Node.js?
(no nosso caso)
1.000 requests por segundo com conexão a uma API
externa + I/O no DB = 1.000 threads por segundo
… se cada request leva em média 10 segundos …
Em 9 segundos, teremos 9.000 threads
34. Por que Node.js?
(no nosso caso)
1.000 requests por segundo com conexão a uma API
externa + I/O no DB = 1.000 threads por segundo
… se cada request leva em média 10 segundos …
Em 9 segundos, teremos 9.000 threads
Isso escala? :P :P :P
36. Por que Node.js?
(no nosso caso)
1.000 requests por segundo com conexão a uma API
externa + I/O no DB = 1 thread
37. Por que Node.js?
(no nosso caso)
1.000 requests por segundo com conexão a uma API
externa + I/O no DB = 1 thread
… se cada request leva em média 10 segundos …
38. Por que Node.js?
(no nosso caso)
1.000 requests por segundo com conexão a uma API
externa + I/O no DB = 1 thread
… se cada request leva em média 10 segundos …
Em 9 segundos, teremos 1 thread
39. Por que Node.js?
(no nosso caso)
1.000 requests por segundo com conexão a uma API
externa + I/O no DB = 1 thread
… se cada request leva em média 10 segundos …
Em 9 segundos, teremos 1 thread
Isso escala? Sim.
40. Por que Node.js?
(no nosso caso)
1.000 requests por segundo com conexão a uma API
externa + I/O no DB = 1 thread
… se cada request leva em média 10 segundos …
Em 9 segundos, teremos 1 thread
Isso escala? Sim.
#eventloopFTW
60. O segredo do Node.js
JavaScript (event loop)
V8
libuv
Sistema operacional
61. O segredo do Node.js
JavaScript (event loop)
V8
libuv
Sistema operacional
I/O
62. O segredo do Node.js
JavaScript (event loop)
V8
libuv
Sistema operacional
I/O
63. O segredo do Node.js
JavaScript (event loop)
V8
libuv
Sistema operacional
I/O
64. O segredo do Node.js
JavaScript (event loop)
V8
libuv
Sistema operacional
I/O
65. O segredo do Node.js
JavaScript (event loop)
V8
libuv
Sistema operacional
……………………………………
I/O
66. O segredo do Node.js
JavaScript (event loop)
V8
libuv
Sistema operacional
……………………………………
operações assíncronas em nível de OS
I/O
67. O segredo do Node.js
JavaScript (event loop)
V8
libuv
Sistema operacional
……………………………………
operações assíncronas em nível de OS
I/O
68. O segredo do Node.js
JavaScript (event loop)
V8
libuv
Sistema operacional
……………………………………
operações assíncronas em nível de OS
I/O
69. O segredo do Node.js
JavaScript (event loop)
V8
libuv
Sistema operacional
……………………………………
operações assíncronas em nível de OS
I/O
70. O segredo do Node.js
JavaScript (event loop)
V8
libuv
Sistema operacional
……………………………………
operações assíncronas em nível de OS
I/O
callback
71. O segredo do Node.js
JavaScript (event loop)
V8
libuv
Sistema operacional
……………………………………
operações assíncronas em nível de OS
I/O
callback
I/O
72. O segredo do Node.js
JavaScript (event loop)
V8
libuv
Sistema operacional
……………………………………
operações assíncronas em nível de OS
……………………………………
I/O
callback
I/O
73. O segredo do Node.js
JavaScript (event loop)
V8
libuv
Sistema operacional
……………………………………
operações assíncronas em nível de OS
……………………………………
I/O
callback
I/O
I/O
74. O segredo do Node.js
JavaScript (event loop)
V8
libuv
Sistema operacional
……………………………………
operações assíncronas em nível de OS
…………………………………………………………………………
I/O
callback
I/O
I/O
75. O segredo do Node.js
JavaScript (event loop)
V8
libuv
Sistema operacional
……………………………………
operações assíncronas em nível de OS
…………………………………………………………………………
I/O
callback
I/O
I/O
callback
76. O segredo do Node.js
JavaScript (event loop)
V8
libuv
Sistema operacional
……………………………………
operações assíncronas em nível de OS
…………………………………………………………………………
I/O
callback
I/O
I/O
callback
callback
77. Node.js escala em I/O bloqueante, não
em utilização de CPU
(threads são boas em processamento paralelo)
81. Código assíncrono (race conditions, callback hell,
testes assíncronos, etc)
db.query("SELECT a FROM users WHERE ...;", function (err, result1) {
db.query("SELECT b FROM users WHERE ...;", function (err, result2) {
db.query("SELECT c FROM users WHERE ...;", function (err, result3) {
db.query("SELECT d FROM users WHERE ...;", function (err, result4) {
db.query("SELECT e FROM users WHERE ...;", function (err, result5) {
console.log("Finished.");
});
});
});
});
});
Um ótimo exemplo do que não fazer: callback hell.
Problemas de Node.js
82. Problemas de Javascript: bizarrices e facilidade em não
seguir padrões e orientação a objetos.
> 0.1+0.2
0.30000000000000004
> typeof NaN
'number'
> NaN === NaN
false
Cortesia do wtfjs.com
Problemas de Node.js
83. Exceptions não tratadas matam o processo.
var name = “Pedro Franceschi";
console.log("Tamanho do primeiro nome: " + name.split(" ")[0].length);
console.log("Tamanho do segundo nome: " + name.split(" ")[1].length);
Problemas de Node.js
$ node test.js
Tamanho do primeiro nome: 5
Tamanho do segundo nome: 10
84. Exceptions não tratadas matam o processo.
var name = “Pedro";
console.log("Tamanho do primeiro nome: " + name.split(" ")[0].length);
console.log("Tamanho do segundo nome: " + name.split(" ")[1].length);
Problemas de Node.js
$ node test.js
Tamanho do primeiro nome: 5
/private/tmp/test.js:4
console.log("Tamanho do segundo nome: " + name.split(" ")[1].length);
^
TypeError: Cannot read property 'length' of undefined
at Object.<anonymous> (/private/tmp/test.js:4:61)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
at startup (node.js:119:16)
at node.js:901:3
86. Problemas de Node.js
• Single thread (escalar horizontalmente e
verticalmente com múltiplas instâncias)
87. Problemas de Node.js
• Single thread (escalar horizontalmente e
verticalmente com múltiplas instâncias)
• Leaks de memória difíceis de detectar (back-end em
C++, variáveis globalizadas, closures, etc)
88. Problemas de Node.js
• Single thread (escalar horizontalmente e
verticalmente com múltiplas instâncias)
• Leaks de memória difíceis de detectar (back-end em
C++, variáveis globalizadas, closures, etc)
• Programadores front-end mexendo em back-end
(“é tudo Javascript!!”)
89. Problemas de Node.js
• Single thread (escalar horizontalmente e
verticalmente com múltiplas instâncias)
• Leaks de memória difíceis de detectar (back-end em
C++, variáveis globalizadas, closures, etc)
• Programadores front-end mexendo em back-end
(“é tudo Javascript!!”)
• Existe a 6 anos, porém ainda é beta (v0.12.0) - e às
vezes você precisa usar unstable em produção
95. Qualidade de vida vs. tempo usando Node
Node é muito
legal!!! Ops… Meu código está
ficando uma zona…
96. Qualidade de vida vs. tempo usando Node
Node é muito
legal!!! Ops… Meu código está
ficando uma zona…
Queria ter feito em
Rails…
97. Qualidade de vida vs. tempo usando Node
Node é muito
legal!!! Ops… Meu código está
ficando uma zona…
Queria ter feito em
Rails…
MVC de verdade +
Promise + Bluebird <3
98. Modules
Node.js “the right way”
var PI = Math.PI;
exports.area = function (r) {
return PI * r * r;
};
exports.circumference = function (r) {
return 2 * PI * r;
};
circle.js
var circle = require('./circle.js');
console.log( 'The area of a circle of radius 4 is ' + circle.area(4));
main.js
99. Node.js “the right way”
describe('Array', function(){
describe('#indexOf()', function(){
it('should return -1 when the value is not present', function(){
[1,2,3].indexOf(5).should.equal(-1);
})
})
describe(‘#indexOf() after one second', function(){
before(function(done){
setTimeout(function(){
done();
}, 1000);
});
it('should return -1 when the value is not present', function(){
[1,2,3].indexOf(5).should.equal(-1);
})
})
});
Testes (JavaScript quebra)
(https://github.com/visionmedia/mocha e https://github.com/visionmedia/should.js/)
105. Node.js “the right way”
Promises (Bluebird)
fs.readFile("file.json", function(err, val) {
if(err) {
console.error("unable to read file");
} else {
try {
val = JSON.parse(val);
console.log(val.success);
} catch(e) {
console.error("invalid json in file");
}
}
});
106. Node.js “the right way”
Promises (Bluebird)
fs.readFile("file.json", function(err, val) {
if(err) {
console.error("unable to read file");
} else {
try {
val = JSON.parse(val);
console.log(val.success);
} catch(e) {
console.error("invalid json in file");
}
}
});
107. Node.js “the right way”
Promises (Bluebird)
fs.readFileAsync("file.json").then(JSON.parse).then(function(val) {
console.log(val.success);
})
.catch(SyntaxError, function(e) {
console.error("invalid json in file");
})
.catch(function(e){
console.error("unable to read file")
});
Assim é bem melhor :)
108. Node.js “the right way”
Lodash
var lines = [
['name', 'type', 'cost'],
['iPhone', 'cellphone', '2000'],
['MacBook', 'computer', '10000'],
['iPad', 'tablet', '1500']
];
var joinedLines = [];
for(var i = 0; i < lines.length; i++) {
joinedLines.push(lines[i].join(','));
}
var csvContent = joinedLines.join('n');
name,type,cost
iPhone,cellphone,2000
MacBook,computer,10000
iPad,tablet,1500
Output
109. Node.js “the right way”
Lodash
var lines = [
['name', 'type', 'cost'],
['iPhone', 'cellphone', '2000'],
['MacBook', 'computer', '10000'],
['iPad', 'tablet', '1500']
];
var joinedLines = [];
for(var i = 0; i < lines.length; i++) {
joinedLines.push(lines[i].join(','));
}
var csvContent = joinedLines.join('n');
name,type,cost
iPhone,cellphone,2000
MacBook,computer,10000
iPad,tablet,1500
Output
110. Node.js “the right way”
Lodash
var lines = [
['name', 'type', 'cost'],
['iPhone', 'cellphone', '2000'],
['MacBook', 'computer', '10000'],
['iPad', 'tablet', '1500']
];
var joinedLines = [];
for(var i = 0; i < lines.length; i++) {
joinedLines.push(lines[i].join(','));
}
var csvContent = joinedLines.join('n');
name,type,cost
iPhone,cellphone,2000
MacBook,computer,10000
iPad,tablet,1500
Output
111. Node.js “the right way”
Assim é bem melhor :)
Lodash
var _ = require('lodash');
var lines = [
['name', 'type', 'cost'],
['iPhone', 'cellphone', '2000'],
['MacBook', 'computer', '10000'],
['iPad', 'tablet', '1500']
];
var csvContent = _.map(lines, function(line){
return line.join(',');
}).join('n');
name,type,cost
iPhone,cellphone,2000
MacBook,computer,10000
iPad,tablet,1500
Output
113. Node.js “the right way”
• Seguir e manter um code style (dica: Google
JavaScript Style Guide)
114. Node.js “the right way”
• Seguir e manter um code style (dica: Google
JavaScript Style Guide)
• Tratamento de erros consistente via Promise (evitar
que processos morram)
115. Node.js “the right way”
• Seguir e manter um code style (dica: Google
JavaScript Style Guide)
• Tratamento de erros consistente via Promise (evitar
que processos morram)
• Manter consistência entre as bibliotecas de Promise
(i.e. usar a mesma do wrapper do database)
116. Node.js “the right way”
• Seguir e manter um code style (dica: Google
JavaScript Style Guide)
• Tratamento de erros consistente via Promise (evitar
que processos morram)
• Manter consistência entre as bibliotecas de Promise
(i.e. usar a mesma do wrapper do database)
• Sem for(var i = 0; i < object.length; i++) - #lodashFTW
119. Node.js “the right way”
utils
• Express.js: lightweight HTTP framework
• Sequelize: ORM de MySQL, PostgreSQL, sqlite3, etc.
120. Node.js “the right way”
utils
• Express.js: lightweight HTTP framework
• Sequelize: ORM de MySQL, PostgreSQL, sqlite3, etc.
• Mongoose: ORM de MongoDB
121. Node.js “the right way”
utils
• Express.js: lightweight HTTP framework
• Sequelize: ORM de MySQL, PostgreSQL, sqlite3, etc.
• Mongoose: ORM de MongoDB
• Commander: wrapper de command line
122. Node.js “the right way”
utils
• Express.js: lightweight HTTP framework
• Sequelize: ORM de MySQL, PostgreSQL, sqlite3, etc.
• Mongoose: ORM de MongoDB
• Commander: wrapper de command line
• Vim: melhor editor de texto :P
126. Infraestrutura do Pagar.me
Router
api.pagar.me
Servidor da API
(Node.js)
ElasticSearchElasticSearch
MySQL
(transações e dados relacionais)
MySQL
(transações e dados relacionais)
Ambiente de testes
(sandbox dos clientes)
Ambiente de produção
Servidor da API
(Node.js)
127. Infraestrutura do Pagar.me
Router
api.pagar.me
Servidor da API
(Node.js)
ElasticSearchElasticSearch
MySQL
(transações e dados relacionais)
MySQL
(transações e dados relacionais)
Ambiente de testes
(sandbox dos clientes)
Ambiente de produção
Servidor da API
(Node.js)
Redis
+
Redis
+
128. Infraestrutura do Pagar.me
Router
api.pagar.me
Servidor da API
(Node.js)
ElasticSearchElasticSearch
MySQL
(transações e dados relacionais)
MySQL
(transações e dados relacionais)
MongoDB
(dados de clientes e não relacionais)
Ambiente de testes
(sandbox dos clientes)
Ambiente de produção
Servidor da API
(Node.js)
Redis
+
Redis
+
130. Por que tantos bancos?
• Separar dados de teste (sandbox dos clientes) dos dados de
produção
131. Por que tantos bancos?
• Separar dados de teste (sandbox dos clientes) dos dados de
produção
• MySQL: dados relacionais (transações, assinaturas, planos,
cartões, etc.)
132. Por que tantos bancos?
• Separar dados de teste (sandbox dos clientes) dos dados de
produção
• MySQL: dados relacionais (transações, assinaturas, planos,
cartões, etc.)
• MongoDB: dados não-relacionais (informações do cliente,
usuários de uma conta, etc.)
133. Por que tantos bancos?
• Separar dados de teste (sandbox dos clientes) dos dados de
produção
• MySQL: dados relacionais (transações, assinaturas, planos,
cartões, etc.)
• MongoDB: dados não-relacionais (informações do cliente,
usuários de uma conta, etc.)
• ElasticSearch: indexação/buscas ultra-rápidas (expondo uma
engine de buscas poderosa para os clientes)
134. Por que tantos bancos?
• Separar dados de teste (sandbox dos clientes) dos dados de
produção
• MySQL: dados relacionais (transações, assinaturas, planos,
cartões, etc.)
• MongoDB: dados não-relacionais (informações do cliente,
usuários de uma conta, etc.)
• ElasticSearch: indexação/buscas ultra-rápidas (expondo uma
engine de buscas poderosa para os clientes)
• Redis: fila para notificações entre serviços
135. Por que tantos bancos?
• Separar dados de teste (sandbox dos clientes) dos dados de
produção
• MySQL: dados relacionais (transações, assinaturas, planos,
cartões, etc.)
• MongoDB: dados não-relacionais (informações do cliente,
usuários de uma conta, etc.)
• ElasticSearch: indexação/buscas ultra-rápidas (expondo uma
engine de buscas poderosa para os clientes)
• Redis: fila para notificações entre serviços
• Não há porque se prender a uma tecnologia quando cada uma
delas resolve uma parte do seu problema
136. Infraestrutura do Pagar.me
Router
api.pagar.me
Servidor da API
(Node.js)
ElasticSearchElasticSearch
MySQL
(transações e dados relacionais)
MySQL
(transações e dados relacionais)
MongoDB
(dados de clientes e não relacionais)
Ambiente de testes
(sandbox dos clientes)
Ambiente de produção
Servidor da API
(Node.js)
Redis
+
Redis
+
137. Infraestrutura do Pagar.me
Router
api.pagar.me
Servidor da API
(Node.js)
ElasticSearchElasticSearch
MySQL
(transações e dados relacionais)
MySQL
(transações e dados relacionais)
MongoDB
(dados de clientes e não relacionais)
Ambiente de testes
(sandbox dos clientes)
Ambiente de produção
Servidor da API
(Node.js)
Redis
+
Redis
+
143. Cliente
node api.js -p 3000
node gateway.js -p 5000
API RESTful (pagar.me/docs)
API RESTful
(serviço interno)
144. Cliente
node api.js -p 3000
node gateway.js -p 5000
API RESTful (pagar.me/docs)
XML, SOAP, ISO 8583, X25, sinal de fumaça… :P
API RESTful
(serviço interno)
145. Cliente
node api.js -p 3000
node gateway.js -p 5000
API RESTful (pagar.me/docs)
XML, SOAP, ISO 8583, X25, sinal de fumaça… :P
~ 550 ms
API RESTful
(serviço interno)
146. Cliente
node api.js -p 3000
node gateway.js -p 5000
API RESTful (pagar.me/docs)~ 500ms
XML, SOAP, ISO 8583, X25, sinal de fumaça… :P
~ 550 ms
API RESTful
(serviço interno)
147. Cliente
node api.js -p 3000
node gateway.js -p 5000
API RESTful (pagar.me/docs)~ 500ms
XML, SOAP, ISO 8583, X25, sinal de fumaça… :P> 5000 ms
~ 550 ms
API RESTful
(serviço interno)
148. Cliente
node api.js -p 3000
node gateway.js -p 5000
node hookshot.js
API RESTful (pagar.me/docs)~ 500ms
XML, SOAP, ISO 8583, X25, sinal de fumaça… :P> 5000 ms
~ 550 ms
API RESTful
(serviço interno)
149. Cliente
node api.js -p 3000
node gateway.js -p 5000
node hookshot.js
API RESTful (pagar.me/docs)~ 500ms
Redis (queue)
XML, SOAP, ISO 8583, X25, sinal de fumaça… :P> 5000 ms
~ 550 ms
API RESTful
(serviço interno)
150. Cliente
node api.js -p 3000
node gateway.js -p 5000
node hookshot.js
API RESTful (pagar.me/docs)~ 500ms
Redis (queue)
XML, SOAP, ISO 8583, X25, sinal de fumaça… :P> 5000 ms
~ 550 ms
API RESTful
(serviço interno)
Request HTTP para
o servidor do cliente
151. Cliente
node api.js -p 3000
node gateway.js -p 5000
node hookshot.js
API RESTful (pagar.me/docs)~ 500ms
Redis (queue)
XML, SOAP, ISO 8583, X25, sinal de fumaça… :P> 5000 ms
~ 550 ms
API RESTful
(serviço interno)
~ 100 ms
Request HTTP para
o servidor do cliente
153. Nível 1
$ node server.js
n00bz… Processo não roda em background
154. Nível 2
$ git pull && npm install && node server.js &
Opa… Agora tem Git, update das dependências pelo NPM e o
processo roda em background
155. Nível 3
$ git pull && npm install && nohup node server.js
Nohup roda o processo mesmo depois do logout do SSH
156. Nível 4
$ git pull && npm install && service node-server restart
Um serviço é responsável por rodar e reiniciar o processo e
salvar os logs do processo
157. Nível 5
$ service node-server restart
Agora o servidor de CI lida com o Git e as dependências
Servidor de Continuous Integration (CI)
+
161. pm2
(https://github.com/Unitech/pm2)
• Roda e gerencia os processos do Node.js (mantém
processo rodando para sempre)
• Reload no código on-the-fly (zero downtime)
• Multi-thread e clusterização sem alterar uma linha de
código
162. pm2
(https://github.com/Unitech/pm2)
• Roda e gerencia os processos do Node.js (mantém
processo rodando para sempre)
• Reload no código on-the-fly (zero downtime)
• Multi-thread e clusterização sem alterar uma linha de
código
• Monitoramento e gerenciamento dos logs
163. pm2
(https://github.com/Unitech/pm2)
• Roda e gerencia os processos do Node.js (mantém
processo rodando para sempre)
• Reload no código on-the-fly (zero downtime)
• Multi-thread e clusterização sem alterar uma linha de
código
• Monitoramento e gerenciamento dos logs
• API RESTful + interface web
164. Nível 6
$ pm2 reload all
Strider é o servidor de CI e o pm2 reinicia o processo on-the-fly,
sem perder nenhum request
Strider (servidor de CI)
+
165. Nível 7 (ChatOps)
$ pm2 reload all
Janky é o servidor de CI, Heaven é o servidor de deployment e o
pm2 reinicia o processo on-the-fly, sem perder nenhum request
Janky (Jenkins) + Heaven + Hubot
+
168. ChatOps
• Todos os commits são testados (via Janky + Jenkins)
• Todas as branches têm um estado (green/no-green)
169. ChatOps
• Todos os commits são testados (via Janky + Jenkins)
• Todas as branches têm um estado (green/no-green)
• Todas as branches green podem ser deployadas (sem
regressão)
170. ChatOps
• Todos os commits são testados (via Janky + Jenkins)
• Todas as branches têm um estado (green/no-green)
• Todas as branches green podem ser deployadas (sem
regressão)
• Tudo acontece integrado ao GitHub
171. ChatOps
• Todos os commits são testados (via Janky + Jenkins)
• Todas as branches têm um estado (green/no-green)
• Todas as branches green podem ser deployadas (sem
regressão)
• Tudo acontece integrado ao GitHub
• Deploy da branch X (via Heaven) para um servidor ou
grupo de servidores
172. ChatOps
• Todos os commits são testados (via Janky + Jenkins)
• Todas as branches têm um estado (green/no-green)
• Todas as branches green podem ser deployadas (sem
regressão)
• Tudo acontece integrado ao GitHub
• Deploy da branch X (via Heaven) para um servidor ou
grupo de servidores
• Tudo acontece numa sala de bate papo com todas as
pessoas relacionadas ao projeto.