Lidando com o Caos: testando código PLSQL em projeto crítico
Preparar essa palestra me trouxe
de volta um sentimento…
INSEGURANÇA
parece bobagem, mas não é…
Imagina entrar num projeto…
CRÍTICOPROJETO
Reestruturar Logistica
Integração de vários sistemas
Prazo Apertado
Onde você…
NADA do
NEGÓCIO
NEM dos SISTEMAS
ENVOLVIDOS
Tabelas e mais Tabelas
Pra piorar…
Não
2006
2006+10 anos
Mas daí…
Me deram a BOA Notícia!
Líder Técnico
E quando fomos apresentados…
Olá, tudo bom? Meu nome Rafael. Novo desenvolvedor no projeto.
Olá, tudo bom? Meu nome Rafael. Novo desenvolvedor no projeto.
Opa, sou Dudu. O líder técnico do projeto.
Olá, tudo bom? Meu nome Rafael. Novo desenvolvedor no projeto.
Opa, sou Dudu. O líder técnico do projeto.
300, viu?
Olá, tudo bom? Meu nome Rafael. Novo desenvolvedor no projeto.
Opa, sou Dudu. O líder técnico do projeto.
300, viu?
ahn!!? 300? 300 o que?
Olá, tudo bom? Meu nome Rafael. Novo desenvolvedor no projeto.
Opa, sou Dudu. O líder técnico do projeto.
300, viu?
ahn!!? 300? 300 o que?
R$300.000 por hora se o sistema parar!
R$300k/h
E assim eu me senti de novo…
ESTAGIÁRIO
Me veio vários questionamentos…
Será que posso ajudar no projeto?
Minha experiência vai ajudar em algo?
Lidando com o Caos: testando código PLSQL em projeto crítico
@rponte
Eduardo Menezes
Lidando com o Caos: testando código PLSQL em projeto crítico
Esclarecendo o que o Rafael falou…
Líder Técnico
Líder Técnico
R$300k/h
Falei besteira pro Rafael…
R$5.5mi/h
E a empresa na qual rola o projeto é…
4.6bi/ano$ * Lucro Liquido - 2015
E este PROJETO tem por finalidade…
Reestruturar Logistica
Utilizando tecnologias como…
Mas sem dúvida…
Parte importante dessa integração
ficou com…
Para quem não conhece PL/SQL…
Integer tamanho(String texto) { // retorna tamanho return texto.length();}
Java
function tamanho(texto varchar2) return number isbegin -- retorna tamanho return lENGTH(texto);end;
PL/SQL
Apesar de ser uma linguagem simples
Quando o assunto é PROCESSAR DADOS…
PODEROSA
Afinal…
function tamanho(texto varchar2) return number isbegin -- retorna tamanho return lENGTH(texto);end;
E na MDIAS trabalhamos com GRANDES VOLUMES DE DADOS
Não dá pra ignorar isso!
PERFORMANCE
Mas PL/SQL tem seus problemas…
Milhares de Linhas
Fácil ter procedures com 5-10k linhas de
código
Ferramentas Precárias
Esqueça IDEs sofisticadas como
Eclipse
Regras de Negócio
Não tem a mesma clareza de linguagens
OO
E isso era um grande problema…
Regras de Negócio Complexas
Pra piorar…
A metade da equipe não dominava o
negócio
Agora imagina…
PL/SQL
PL/SQL +
PL/SQL +Regras Complexas
Batemos com 2 desafios sérios…
MANUTENÇÃO do código
CORRETUDE das regras de negócio
CORRETUDE das regras de negócio
Como representar as regras em código corretamente?
Documentação
Quadro-branco
Programação em Par
Programação em Par
MANUTENÇÃO do código
Como escrever código de qualidade?
Como escrever código fácil de ler e manter?
Guia de Estilo
Padronização do Código
Padronização ajuda; estilo ajuda. Mas
precisamos ir mais longe…
BEGIN IF is_frete_calc(cliente) THEN processa_entrega(cliente); notifica_cliente(cliente); END IF;END;
Funções Pequenas
BEGIN IF is_frete_calc(cliente) THEN processa_entrega(cliente); notifica_cliente(cliente); END IF;END;
Funções Pequenas
BEGIN IF is_frete_calc(cliente) THEN processa_entrega(cliente); notifica_cliente(cliente); END IF;END;
Funções Pequenas
BEGIN IF is_frete_calc(cliente) THEN processa_entrega(cliente); notifica_cliente(cliente); END IF;END;
Funções Pequenas
e claro…
BEGIN IF is_frete_calc(cliente) THEN processa_entrega(cliente); notifica_cliente(cliente); END IF;END;
Funções Pequenas
com NOMES LEGÍVEIS!
BONS NOMES
MAIOR CLAREZA=
BONS NOMES MENOS
COMENTÁRIOS NO CÓDIGO
=
Só isso é suficiente?
Não
Precisamos EXECUTAR o código
para ter certeza
Mas como executar?
Manualmente?
BEGIN processa_entrega(cliente); END;
ou…
Usa equipe de QA…
só que…
e ai?
Testes Automatizados
function tamanho(texto varchar2) return number isbegin -- retorna tamanho return lENGTH(texto);end;
Não existem boas ferramentas de testes
Mas nosso time é…
function tamanho(texto varchar2) return number isbegin -- retorna tamanho return lENGTH(texto);end;
Executa procedure
Executa procedure
Devolve resultado
Executa procedure
Devolve resultado
PL/SQL Calcular Frete
-- Calcula Fretefunction calc_frete(uf varchar2) return number isbegin if uf = 'SP' then return 30.0; end if;
return 20.20;end;
PL/SQL
-- Calcula Fretefunction calc_frete(uf varchar2) return number isbegin if uf = 'SP' then return 30.0; end if;
return 20.20;end;
PL/SQL
-- Calcula Fretefunction calc_frete(uf varchar2) return number isbegin if uf = 'SP' then return 30.0; end if;
return 20.20;end;
PL/SQL
-- Calcula Fretefunction calc_frete(uf varchar2) return number isbegin if uf = 'SP' then return 30.0; end if;
return 20.20;end;
PL/SQL
-- Calcula Fretefunction calc_frete(uf varchar2) return number isbegin if uf = 'SP' then return 30.0; end if;
return 20.20;end;
PL/SQL
-- Calcula Fretefunction calc_frete(uf varchar2) return number isbegin if uf = 'SP' then return 30.0; end if;
return 20.20;end;
PL/SQL
-- Calcula Fretefunction calc_frete(uf varchar2) return number isbegin if uf = 'SP' then return 30.0; end if;
return 20.20;end;
PL/SQL
-- Calcula Fretefunction calc_frete(uf varchar2) return number isbegin if uf = 'SP' then return 30.0; end if;
return 20.20;end;
PL/SQL
JAVA Calcular Frete
class FreteService {
public Double calcula(String uf) {String sql = "{? = call calc_frete(?)}”;Connection c = // abre conexãoCallableStatement cs = c.prepareCall(sql);
cs.registerOutParameter(1, Types.VARCHAR);cs.setString(2, uf);
cs.execute();
return cs.getDouble(1);}
}
Java
class FreteService {
public Double calcula(String uf) {String sql = "{? = call calc_frete(?)}”;Connection c = // abre conexãoCallableStatement cs = c.prepareCall(sql);
cs.registerOutParameter(1, Types.VARCHAR);cs.setString(2, uf);
cs.execute();
return cs.getDouble(1);}
}
Java
class FreteService {
public Double calcula(String uf) {String sql = "{? = call calc_frete(?)}”;Connection c = // abre conexãoCallableStatement cs = c.prepareCall(sql);
cs.registerOutParameter(1, Types.VARCHAR);cs.setString(2, uf);
cs.execute();
return cs.getDouble(1);}
}
Java
class FreteService {
public Double calcula(String uf) {String sql = "{? = call calc_frete(?)}";Connection c = // abre conexãoCallableStatement cs = c.prepareCall(sql);
cs.registerOutParameter(1, Types.VARCHAR);cs.setString(2, uf);
cs.execute();
return cs.getDouble(1);}
}
Java
class FreteService {
public Double calcula(String uf) {String sql = "{? = call calc_frete(?)}";Connection c = // abre conexãoCallableStatement cs = c.prepareCall(sql);
cs.registerOutParameter(1, Types.VARCHAR);cs.setString(2, uf);
cs.execute();
return cs.getDouble(1);}
}
Java
class FreteService {
public Double calcula(String uf) {String sql = "{? = call calc_frete(?)}";Connection c = // abre conexãoCallableStatement cs = c.prepareCall(sql);
cs.registerOutParameter(1, Types.DOUBLE);cs.setString(2, uf);
cs.execute();
return cs.getDouble(1);}
}
Java
class FreteService {
public Double calcula(String uf) {String sql = "{? = call calc_frete(?)}";Connection c = // abre conexãoCallableStatement cs = c.prepareCall(sql);
cs.registerOutParameter(1, Types.DOUBLE);cs.setString(2, uf);
cs.execute();
return cs.getDouble(1);}
}
Java
class FreteService {
public Double calcula(String uf) {String sql = "{? = call calc_frete(?)}";Connection c = // abre conexãoCallableStatement cs = c.prepareCall(sql);
cs.registerOutParameter(1, Types.DOUBLE);cs.setString(2, uf);
cs.execute();
return cs.getDouble(1);}
}
Java
class FreteService {
public Double calcula(String uf) {String sql = "{? = call calc_frete(?)}";Connection c = // abre conexãoCallableStatement cs = c.prepareCall(sql);
cs.registerOutParameter(1, Types.DOUBLE);cs.setString(2, uf);
cs.execute(); // executa function
return cs.getDouble(1);}
}
Java
class FreteService {
public Double calcula(String uf) {String sql = "{? = call calc_frete(?)}";Connection c = // abre conexãoCallableStatement cs = c.prepareCall(sql);
cs.registerOutParameter(1, Types.DOUBLE);cs.setString(2, uf);
cs.execute(); // executa function
return cs.getDouble(1);}
}
Java
class FreteService {
public Double calcula(String uf) {String sql = "{? = call calc_frete(?)}";Connection c = // abre conexãoCallableStatement cs = c.prepareCall(sql);
cs.registerOutParameter(1, Types.DOUBLE);cs.setString(2, uf);
cs.execute(); // executa function
return cs.getDouble(1);}
}
Java
jUnit Testar Calcular Frete
class FreteServiceTest {
@Testpublic void deveCalcularFrete() {// cenárioString uf = "SP";
// açãoFreteService service = new FreteService();double valor = service.calcula(uf);
// validaçãoassertEquals(30.0, valor);
}}
jUnit
class FreteServiceTest {
@Testpublic void deveCalcularFrete() {// cenárioString uf = "SP";
// açãoFreteService service = new FreteService();double valor = service.calcula(uf);
// validaçãoassertEquals(30.0, valor);
}}
jUnit
class FreteServiceTest {
@Testpublic void deveCalcularFrete() {// cenárioString uf = "SP";
// açãoFreteService service = new FreteService();double valor = service.calcula(uf);
// validaçãoassertEquals(30.0, valor);
}}
jUnit
class FreteServiceTest {
@Testpublic void deveCalcularFrete() {// cenárioString uf = "SP";
// açãoFreteService service = new FreteService();double valor = service.calcula(uf);
// validaçãoassertEquals(30.0, valor);
}}
jUnit
class FreteServiceTest {
@Testpublic void deveCalcularFrete() {// cenárioString uf = "SP";
// açãoFreteService service = new FreteService();double valor = service.calcula(uf);
// validaçãoassertEquals(30.0, valor);
}}
jUnit
jUnitclass FreteServiceTest {
@Testpublic void deveCalcularFrete() {// cenárioString uf = "SP";
// açãoFreteService service = new FreteService();double valor = service.calcula(uf);
// validaçãoassertEquals(30.0, valor);
}}
class FreteServiceTest {
@Testpublic void deveCalcularFrete() {// cenárioString uf = "SP";
// açãoFreteService service = new FreteService();double valor = service.calcula(uf);
// validaçãoassertEquals(30.0, valor);
}}
jUnit
class FreteServiceTest {
@Testpublic void deveCalcularFrete() {// cenárioString uf = "SP";
// açãoFreteService service = new FreteService();double valor = service.calcula(uf);
// validaçãoassertEquals(30.0, valor);
}}
jUnit
class FreteServiceTest {
@Testpublic void deveCalcularFrete() {// cenárioString uf = "SP";
// açãoFreteService service = new FreteService();double valor = service.calcula(uf);
// validaçãoassertEquals(30.0, valor);
}}
jUnit
class FreteServiceTest {
@Testpublic void deveCalcularFrete() {// cenárioString uf = "SP";
// açãoFreteService service = new FreteService();double valor = service.calcula(uf);
// validaçãoassertEquals(30.0, valor);
}}
jUnit
class FreteServiceTest {
@Testpublic void deveCalcularFrete() {// cenárioString uf = "SP";
// açãoFreteService service = new FreteService();double valor = service.calcula(uf);
// validaçãoassertEquals(30.0, valor);
}}
jUnit
class FreteServiceTest {
@Testpublic void deveCalcularFrete() {// cenárioString uf = "SP";
// açãoFreteService service = new FreteService();double valor = service.calcula(uf);
// validaçãoassertEquals(30.0, valor);
}}
jUnit
class FreteServiceTest {
@Testpublic void deveCalcularFrete() {// cenárioString uf = "SP";
// açãoFreteService service = new FreteService();double valor = service.calcula(uf);
// validaçãoassertEquals(30.0, valor);
}}
jUnit
jUnit
Vamos complicar?
PL/SQL Calcular Frete
-- Calcula Fretefunction calc_frete(uf varchar2) return number isbegin if uf = 'SP' then return 30.0; end if;
return 20.20;end;
PL/SQL
-- Calcula Fretefunction calc_frete(uf varchar2) return number isbegin if uf = 'SP' then return 30.0; end if;
return 20.20;end;
PL/SQL
function calc_frete(uf varchar2) return number isbegin-- nova logica
end;
PL/SQL
MODELO
function calc_frete(uf varchar2) return number isvalor_frete number;
begin-- busca valor do frete na tabelaSELECT f.valor INTO valor_frete FROM TB_FRETE_VALOR f WHERE f.uf_destino = uf;
return valor_frete;end;
PL/SQL
function calc_frete(uf varchar2) return number isvalor_frete number;
begin-- busca valor do frete na tabelaSELECT f.valor FROM TB_FRETE_VALOR f WHERE f.uf_destino = uf;
return valor_frete;
end;
PL/SQL
function calc_frete(uf varchar2) return number isvalor_frete number;
begin-- busca valor do frete na tabelaSELECT f.valor FROM TB_FRETE_VALOR f WHERE f.uf_destino = uf;
return valor_frete;
end;
PL/SQL
function calc_frete(uf varchar2) return number isvalor_frete number;
begin-- busca valor do frete na tabelaSELECT f.valor INTO valor_frete FROM TB_FRETE_VALOR f WHERE f.uf_destino = uf;
return valor_frete;end;
PL/SQL
function calc_frete(uf varchar2) return number isvalor_frete number;
begin-- busca valor do frete na tabelaSELECT f.valor INTO valor_frete FROM TB_FRETE_VALOR f WHERE f.uf_destino = uf;
return valor_frete;end;
PL/SQL
function calc_frete(uf varchar2) return number isvalor_frete number;
begin-- busca valor do frete na tabelaSELECT f.valor INTO valor_frete FROM TB_FRETE_VALOR f WHERE f.uf_destino = uf;
return valor_frete;end;
PL/SQL
E o código Java?
class FreteService {
public Double calcula(String uf) {String sql = "{? = call calc_frete(?)}";Connection c = // abre conexãoCallableStatement cs = c.prepareCall(sql);
cs.registerOutParameter(1, Types.DOUBLE);cs.setString(2, uf);
cs.execute(); // executa function
return cs.getDouble(1);}
}
Java
class FreteService {
public Double calcula(String uf) {String sql = "{? = call calc_frete(?)}";Connection c = // abre conexãoCallableStatement cs = c.prepareCall(sql);
cs.registerOutParameter(1, Types.DOUBLE);cs.setString(2, uf);
cs.execute(); // executa function
return cs.getDouble(1);}
}
Java
Nada!
jUnit Testar Calcular Frete
class FreteServiceTest {
@Testpublic void deveCalcularFrete() {// cenárioString uf = "SP";
// açãoFreteService service = new FreteService();double valor = service.calcula(uf);
// validaçãoassertEquals(30.0, valor);
}}
jUnit
jUnit
class FreteServiceTest {
@Testpublic void deveCalcularFrete() {// cenárioString uf = "SP";this.limpaEInsereFrete("SP", 30.0);
// açãoFreteService service = new FreteService();double valor = service.calcula(uf);
// validaçãoassertEquals(30.0, valor);
}}
jUnit
class FreteServiceTest {
@Testpublic void deveCalcularFrete() {// cenárioString uf = "SP";this.limpaEInsereFrete("SP", 30.0);
// açãoFreteService service = new FreteService();double valor = service.calcula(uf);
// validaçãoassertEquals(30.0, valor);
}}
jUnit
class FreteServiceTest {
@Testpublic void deveCalcularFrete() {// cenárioString uf = "SP";this.limpaEInsereFrete("SP", 30.0);
// açãoFreteService service = new FreteService();double valor = service.calcula(uf);
// validaçãoassertEquals(30.0, valor);
}}
jUnit
DELETE FROM TB_FRETE_VALOR;INSERT INTO TB_FRETE_VALOR VALUES(1, ‘SP’, 30.30);
class FreteServiceTest {
@Testpublic void deveCalcularFrete() {// cenárioString uf = "SP";this.limpaEInsereFrete("SP", 30.0);
// açãoFreteService service = new FreteService();double valor = service.calcula(uf);
// validaçãoassertEquals(30.0, valor);
}}
jUnit
jUnit
E aí, tudo testado?
Mando pra produção?
E SE não encontrar a UF na tabela?
function calc_frete(uf varchar2) return number isvalor_frete number;
begin-- busca valor do frete na tabelaSELECT f.valor INTO valor_frete FROM TB_FRETE_VALOR f WHERE f.uf_destino = uf;
return valor_frete;end;
PL/SQL
function calc_frete(uf varchar2) return number isvalor_frete number;
begin-- busca valor do frete na tabelaSELECT f.valor INTO valor_frete FROM TB_FRETE_VALOR f WHERE f.uf_destino = uf;
return valor_frete;
EXCEPTIONWHEN no_data_found THENraise_application_error(-20200, ‘oops!’);
end;
PL/SQL
class FreteServiceTest {
@Testpublic void naoDeveCalcularFreteQuandoUfNaoEncontrada() {// lógica do teste vai aqui
}}
jUnit
jUnit
jUnit
E SE encontrar mais de um frete?
E SE…
Outros Cenários
Desafios
Desconfiança
Pair Programming
Testes Automatizados
O pior…
ATRASOU mesmo!
Mas não foi à toa…
não tem LITERATURA
não tem COMUNIDADE
não tem CULTURA
Não se engane!
Tivemos bons resultados!
Melhoramosnosso processo
Simplificamos nosso ambiente
Diminuimos o indice de bugs
Não temos MEDO de mexer no código
Padronização da Arquitetura dos testes
Agora a Gerência gostou!!
e a partir de agora novos projetos irão
adotar esta metodologia
o que ficou faltando?
treinar restante da equipe
Servidor de
Integração
Cobrir procedures IMPORTANTES com
testes
Bem…
O caminho é longo
Não será fácil…
Nem acontecerá da noite pro dia…
Recommended