Lidando com o Caos: Testando Código PLSQL em um Projeto Critico

Preview:

Citation preview

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…

Obrigado!

Eduardo Menezesedumenezes@gmail.com

Rafael Ponterponte@gmail.com