Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

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

1,125 views

Published on

Imagine entrar em um projeto critico de uma grande empresa onde todo o desenvolvimento se baseia em integrar diversos outros sistemas mais criticos ainda? Agora, imagine que essa integração ocorrerá toda via banco de dados através de stored procedures, de código PLSQL?

São milhares de linhas de código PLSQL executando toda lógica de negócio que deve rodar com alto desempenho e, principalmente, corretude. Uma simples falha e todo um sistema de Logística pode parar! Como garantir que tudo funciona de forma correta e mais, que tenhamos ao final um código manutenível? Nessa apresentação vamos expor como nossa equipe conseguiu implementar todo esse código PLSQL com qualidade e o melhor de tudo, coberto por centenas de testes automatizados; o uso de testes foi crucial para o sucesso! Some a isso todo o desafio cultural e desconfiança do mercado em testar código PLSQL, a falta de literatura sobre o assunto e a real necessidade de automatizar ao máximo o ambiente de desenvolvimento.

Essa palestra te fará repensar sobre como você programa em PLSQL.

Palestra ministrada no evento Javou #9 da JavaCE em MAR-2017 (http://www.javace.org/javou-09-casos-de-sucesso/) por Rafael Ponte e Eduardo Menezes (edumenezes@gmail.com)

Published in: Technology

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

  1. 1. Lidando com o Caos: testando código PLSQL em projeto crítico
  2. 2. Preparar essa palestra me trouxe de volta um sentimento…
  3. 3. INSEGURANÇA
  4. 4. parece bobagem, mas não é…
  5. 5. Imagina entrar num projeto…
  6. 6. CRÍTICO PROJETO
  7. 7. Reestruturar Logistica
  8. 8. Integração de vários sistemas
  9. 9. Prazo Apertado
  10. 10. Onde você…
  11. 11. NADA do NEGÓCIO
  12. 12. NEM dos SISTEMAS ENVOLVIDOS
  13. 13. Tabelas e mais Tabelas
  14. 14. Pra piorar…
  15. 15. Não
  16. 16. 2006
  17. 17. 2006+10 anos
  18. 18. Mas daí…
  19. 19. Me deram a BOA Notícia!
  20. 20. Líder Técnico
  21. 21. E quando fomos apresentados…
  22. 22. Olá, tudo bom? Meu nome Rafael. Novo desenvolvedor no projeto.
  23. 23. Olá, tudo bom? Meu nome Rafael. Novo desenvolvedor no projeto. Opa, sou Dudu. O líder técnico do projeto.
  24. 24. Olá, tudo bom? Meu nome Rafael. Novo desenvolvedor no projeto. Opa, sou Dudu. O líder técnico do projeto. 300, viu?
  25. 25. 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?
  26. 26. 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!
  27. 27. R$300k/h
  28. 28. E assim eu me senti de novo…
  29. 29. ESTAGIÁRIO
  30. 30. Me veio vários questionamentos…
  31. 31. Será que posso ajudar no projeto?
  32. 32. Minha experiência vai ajudar em algo?
  33. 33. Lidando com o Caos: testando código PLSQL em projeto crítico
  34. 34. @rponte
  35. 35. Eduardo Menezes
  36. 36. Lidando com o Caos: testando código PLSQL em projeto crítico
  37. 37. Esclarecendo o que o Rafael falou…
  38. 38. Líder Técnico
  39. 39. Líder Técnico
  40. 40. R$300k/h
  41. 41. Falei besteira pro Rafael…
  42. 42. R$5.5mi/h
  43. 43. E a empresa na qual rola o projeto é…
  44. 44. 4.6bi/ano$ * Lucro Liquido - 2015
  45. 45. E este PROJETO tem por finalidade…
  46. 46. Reestruturar Logistica
  47. 47. Utilizando tecnologias como…
  48. 48. Mas sem dúvida…
  49. 49. Parte importante dessa integração ficou com…
  50. 50. Para quem não conhece PL/SQL…
  51. 51. Integer tamanho(String texto) { // retorna tamanho return texto.length(); } Java
  52. 52. function tamanho(texto varchar2)
 return number is begin -- retorna tamanho return lENGTH(texto); end; PL/SQL
  53. 53. Apesar de ser uma linguagem simples
  54. 54. Quando o assunto é PROCESSAR DADOS…
  55. 55. PODEROSA
  56. 56. Afinal…
  57. 57. function tamanho(texto varchar2)
 return number is begin -- retorna tamanho return lENGTH(texto); end;
  58. 58. E na MDIAS trabalhamos com GRANDES VOLUMES DE DADOS
  59. 59. Não dá pra ignorar isso!
  60. 60. PERFORMANCE
  61. 61. Mas PL/SQL tem seus problemas…
  62. 62. Milhares de Linhas
  63. 63. Fácil ter procedures com 5-10k linhas de código
  64. 64. Ferramentas Precárias
  65. 65. Esqueça IDEs sofisticadas como Eclipse
  66. 66. Regras de Negócio
  67. 67. Não tem a mesma clareza de linguagens OO
  68. 68. E isso era um grande problema…
  69. 69. Regras de Negócio Complexas
  70. 70. Pra piorar…
  71. 71. A metade da equipe não dominava o negócio
  72. 72. Agora imagina…
  73. 73. PL/SQL
  74. 74. PL/SQL +
  75. 75. PL/SQL +Regras 
 Complexas
  76. 76. Batemos com 2 desafios sérios…
  77. 77. MANUTENÇÃO
 do código CORRETUDE 
 das regras de negócio
  78. 78. CORRETUDE 
 das regras de negócio
  79. 79. Como representar as regras em código corretamente?
  80. 80. Documentação
  81. 81. Quadro-branco
  82. 82. Programação em Par
  83. 83. Programação em Par
  84. 84. MANUTENÇÃO
 do código
  85. 85. Como escrever código de qualidade?
  86. 86. Como escrever código fácil de ler e manter?
  87. 87. Guia de Estilo
  88. 88. Padronização do Código
  89. 89. Padronização ajuda; estilo ajuda. Mas precisamos ir mais longe…
  90. 90. BEGIN IF is_frete_calc(cliente) THEN
 processa_entrega(cliente); notifica_cliente(cliente); END IF; END; Funções Pequenas
  91. 91. BEGIN IF is_frete_calc(cliente) THEN
 processa_entrega(cliente); notifica_cliente(cliente); END IF; END; Funções Pequenas
  92. 92. BEGIN IF is_frete_calc(cliente) THEN
 processa_entrega(cliente); notifica_cliente(cliente); END IF; END; Funções Pequenas
  93. 93. BEGIN IF is_frete_calc(cliente) THEN
 processa_entrega(cliente); notifica_cliente(cliente); END IF; END; Funções Pequenas
  94. 94. e claro…
  95. 95. BEGIN IF is_frete_calc(cliente) THEN
 processa_entrega(cliente); notifica_cliente(cliente); END IF; END; Funções Pequenas comNOMESLEGÍVEIS!
  96. 96. BONS NOMES MAIOR CLAREZA=
  97. 97. BONS NOMES MENOS COMENTÁRIOS NO CÓDIGO =
  98. 98. Só isso é suficiente?
  99. 99. Não
  100. 100. Precisamos EXECUTAR o código para ter certeza
  101. 101. Mas como executar?
  102. 102. Manualmente?
  103. 103. BEGIN 
 processa_entrega(cliente); END;
  104. 104. ou…
  105. 105. Usa equipe de QA…
  106. 106. só que…
  107. 107. e ai?
  108. 108. Testes Automatizados
  109. 109. function tamanho(texto varchar2)
 return number is begin -- retorna tamanho return lENGTH(texto); end;
  110. 110. Não existem boas ferramentas de testes
  111. 111. Mas nosso time é…
  112. 112. function tamanho(texto varchar2)
 return number is begin -- retorna tamanho return lENGTH(texto); end;
  113. 113. Executa procedure
  114. 114. Executa procedure Devolve resultado
  115. 115. Executa procedure Devolve resultado
  116. 116. PL/SQL Calcular Frete
  117. 117. -- Calcula Frete function calc_frete(uf varchar2)
 return number is begin if uf = 'SP' then return 30.0; end if; return 20.20; end; PL/SQL
  118. 118. -- Calcula Frete function calc_frete(uf varchar2)
 return number is begin if uf = 'SP' then return 30.0; end if; return 20.20; end; PL/SQL
  119. 119. -- Calcula Frete function calc_frete(uf varchar2)
 return number is begin if uf = 'SP' then return 30.0; end if; return 20.20; end; PL/SQL
  120. 120. -- Calcula Frete function calc_frete(uf varchar2)
 return number is begin if uf = 'SP' then return 30.0; end if; return 20.20; end; PL/SQL
  121. 121. -- Calcula Frete function calc_frete(uf varchar2)
 return number is begin if uf = 'SP' then return 30.0; end if; return 20.20; end; PL/SQL
  122. 122. -- Calcula Frete function calc_frete(uf varchar2)
 return number is begin if uf = 'SP' then return 30.0; end if; return 20.20; end; PL/SQL
  123. 123. -- Calcula Frete function calc_frete(uf varchar2)
 return number is begin if uf = 'SP' then return 30.0; end if; return 20.20; end; PL/SQL
  124. 124. -- Calcula Frete function calc_frete(uf varchar2)
 return number is begin if uf = 'SP' then return 30.0; end if; return 20.20; end; PL/SQL
  125. 125. JAVA Calcular Frete
  126. 126. class FreteService { public Double calcula(String uf) { String sql = "{? = call calc_frete(?)}”; Connection c = // abre conexão CallableStatement cs = c.prepareCall(sql); cs.registerOutParameter(1, Types.VARCHAR); cs.setString(2, uf); cs.execute(); return cs.getDouble(1); } } Java
  127. 127. class FreteService { public Double calcula(String uf) { String sql = "{? = call calc_frete(?)}”; Connection c = // abre conexão CallableStatement cs = c.prepareCall(sql); cs.registerOutParameter(1, Types.VARCHAR); cs.setString(2, uf); cs.execute(); return cs.getDouble(1); } } Java
  128. 128. class FreteService { public Double calcula(String uf) { String sql = "{? = call calc_frete(?)}”; Connection c = // abre conexão CallableStatement cs = c.prepareCall(sql); cs.registerOutParameter(1, Types.VARCHAR); cs.setString(2, uf); cs.execute(); return cs.getDouble(1); } } Java
  129. 129. class FreteService { public Double calcula(String uf) { String sql = "{? = call calc_frete(?)}"; Connection c = // abre conexão CallableStatement cs = c.prepareCall(sql); cs.registerOutParameter(1, Types.VARCHAR); cs.setString(2, uf); cs.execute(); return cs.getDouble(1); } } Java
  130. 130. class FreteService { public Double calcula(String uf) { String sql = "{? = call calc_frete(?)}"; Connection c = // abre conexão CallableStatement cs = c.prepareCall(sql); cs.registerOutParameter(1, Types.VARCHAR); cs.setString(2, uf); cs.execute(); return cs.getDouble(1); } } Java
  131. 131. class FreteService { public Double calcula(String uf) { String sql = "{? = call calc_frete(?)}"; Connection c = // abre conexão CallableStatement cs = c.prepareCall(sql); cs.registerOutParameter(1, Types.DOUBLE); cs.setString(2, uf); cs.execute(); return cs.getDouble(1); } } Java
  132. 132. class FreteService { public Double calcula(String uf) { String sql = "{? = call calc_frete(?)}"; Connection c = // abre conexão CallableStatement cs = c.prepareCall(sql); cs.registerOutParameter(1, Types.DOUBLE); cs.setString(2, uf); cs.execute(); return cs.getDouble(1); } } Java
  133. 133. class FreteService { public Double calcula(String uf) { String sql = "{? = call calc_frete(?)}"; Connection c = // abre conexão CallableStatement cs = c.prepareCall(sql); cs.registerOutParameter(1, Types.DOUBLE); cs.setString(2, uf); cs.execute(); return cs.getDouble(1); } } Java
  134. 134. class FreteService { public Double calcula(String uf) { String sql = "{? = call calc_frete(?)}"; Connection c = // abre conexão CallableStatement cs = c.prepareCall(sql); cs.registerOutParameter(1, Types.DOUBLE); cs.setString(2, uf); cs.execute(); // executa function return cs.getDouble(1); } } Java
  135. 135. class FreteService { public Double calcula(String uf) { String sql = "{? = call calc_frete(?)}"; Connection c = // abre conexão CallableStatement cs = c.prepareCall(sql); cs.registerOutParameter(1, Types.DOUBLE); cs.setString(2, uf); cs.execute(); // executa function return cs.getDouble(1); } } Java
  136. 136. class FreteService { public Double calcula(String uf) { String sql = "{? = call calc_frete(?)}"; Connection c = // abre conexão CallableStatement cs = c.prepareCall(sql); cs.registerOutParameter(1, Types.DOUBLE); cs.setString(2, uf); cs.execute(); // executa function return cs.getDouble(1); } } Java
  137. 137. jUnit Testar Calcular Frete
  138. 138. class FreteServiceTest { @Test public void deveCalcularFrete() { // cenário String uf = "SP"; // ação FreteService service = new FreteService(); double valor = service.calcula(uf); // validação assertEquals(30.0, valor); } } jUnit
  139. 139. class FreteServiceTest { @Test public void deveCalcularFrete() { // cenário String uf = "SP"; // ação FreteService service = new FreteService(); double valor = service.calcula(uf); // validação assertEquals(30.0, valor); } } jUnit
  140. 140. class FreteServiceTest { @Test public void deveCalcularFrete() { // cenário String uf = "SP"; // ação FreteService service = new FreteService(); double valor = service.calcula(uf); // validação assertEquals(30.0, valor); } } jUnit
  141. 141. class FreteServiceTest { @Test public void deveCalcularFrete() { // cenário String uf = "SP"; // ação FreteService service = new FreteService(); double valor = service.calcula(uf); // validação assertEquals(30.0, valor); } } jUnit
  142. 142. class FreteServiceTest { @Test public void deveCalcularFrete() { // cenário String uf = "SP"; // ação FreteService service = new FreteService(); double valor = service.calcula(uf); // validação assertEquals(30.0, valor); } } jUnit
  143. 143. jUnitclass FreteServiceTest { @Test public void deveCalcularFrete() { // cenário String uf = "SP"; // ação FreteService service = new FreteService(); double valor = service.calcula(uf); // validação assertEquals(30.0, valor); } }
  144. 144. class FreteServiceTest { @Test public void deveCalcularFrete() { // cenário String uf = "SP"; // ação FreteService service = new FreteService(); double valor = service.calcula(uf); // validação assertEquals(30.0, valor); } } jUnit
  145. 145. class FreteServiceTest { @Test public void deveCalcularFrete() { // cenário String uf = "SP"; // ação FreteService service = new FreteService(); double valor = service.calcula(uf); // validação assertEquals(30.0, valor); } } jUnit
  146. 146. class FreteServiceTest { @Test public void deveCalcularFrete() { // cenário String uf = "SP"; // ação FreteService service = new FreteService(); double valor = service.calcula(uf); // validação assertEquals(30.0, valor); } } jUnit
  147. 147. class FreteServiceTest { @Test public void deveCalcularFrete() { // cenário String uf = "SP"; // ação FreteService service = new FreteService(); double valor = service.calcula(uf); // validação assertEquals(30.0, valor); } } jUnit
  148. 148. class FreteServiceTest { @Test public void deveCalcularFrete() { // cenário String uf = "SP"; // ação FreteService service = new FreteService(); double valor = service.calcula(uf); // validação assertEquals(30.0, valor); } } jUnit
  149. 149. class FreteServiceTest { @Test public void deveCalcularFrete() { // cenário String uf = "SP"; // ação FreteService service = new FreteService(); double valor = service.calcula(uf); // validação assertEquals(30.0, valor); } } jUnit
  150. 150. class FreteServiceTest { @Test public void deveCalcularFrete() { // cenário String uf = "SP"; // ação FreteService service = new FreteService(); double valor = service.calcula(uf); // validação assertEquals(30.0, valor); } } jUnit
  151. 151. jUnit
  152. 152. Vamos complicar?
  153. 153. PL/SQL Calcular Frete
  154. 154. -- Calcula Frete function calc_frete(uf varchar2)
 return number is begin if uf = 'SP' then return 30.0; end if; return 20.20; end; PL/SQL
  155. 155. -- Calcula Frete function calc_frete(uf varchar2)
 return number is begin if uf = 'SP' then return 30.0; end if; return 20.20; end; PL/SQL
  156. 156. function calc_frete(uf varchar2)
 return number is begin -- nova logica end; PL/SQL
  157. 157. MODELO
  158. 158. function calc_frete(uf varchar2) return number is valor_frete number; begin -- busca valor do frete na tabela SELECT f.valor INTO valor_frete FROM TB_FRETE_VALOR f WHERE f.uf_destino = uf; return valor_frete; end; PL/SQL
  159. 159. function calc_frete(uf varchar2) return number is valor_frete number; begin -- busca valor do frete na tabela SELECT f.valor FROM TB_FRETE_VALOR f WHERE f.uf_destino = uf; return valor_frete; end; PL/SQL
  160. 160. function calc_frete(uf varchar2) return number is valor_frete number; begin -- busca valor do frete na tabela SELECT f.valor FROM TB_FRETE_VALOR f WHERE f.uf_destino = uf; return valor_frete; end; PL/SQL
  161. 161. function calc_frete(uf varchar2) return number is valor_frete number; begin -- busca valor do frete na tabela SELECT f.valor INTO valor_frete FROM TB_FRETE_VALOR f WHERE f.uf_destino = uf; return valor_frete; end; PL/SQL
  162. 162. function calc_frete(uf varchar2) return number is valor_frete number; begin -- busca valor do frete na tabela SELECT f.valor INTO valor_frete FROM TB_FRETE_VALOR f WHERE f.uf_destino = uf; return valor_frete; end; PL/SQL
  163. 163. function calc_frete(uf varchar2) return number is valor_frete number; begin -- busca valor do frete na tabela SELECT f.valor INTO valor_frete FROM TB_FRETE_VALOR f WHERE f.uf_destino = uf; return valor_frete; end; PL/SQL
  164. 164. E o código Java?
  165. 165. class FreteService { public Double calcula(String uf) { String sql = "{? = call calc_frete(?)}"; Connection c = // abre conexão CallableStatement cs = c.prepareCall(sql); cs.registerOutParameter(1, Types.DOUBLE); cs.setString(2, uf); cs.execute(); // executa function return cs.getDouble(1); } } Java
  166. 166. class FreteService { public Double calcula(String uf) { String sql = "{? = call calc_frete(?)}"; Connection c = // abre conexão CallableStatement cs = c.prepareCall(sql); cs.registerOutParameter(1, Types.DOUBLE); cs.setString(2, uf); cs.execute(); // executa function return cs.getDouble(1); } } Java Nada!
  167. 167. jUnit Testar Calcular Frete
  168. 168. class FreteServiceTest { @Test public void deveCalcularFrete() { // cenário String uf = "SP"; // ação FreteService service = new FreteService(); double valor = service.calcula(uf); // validação assertEquals(30.0, valor); } } jUnit
  169. 169. jUnit
  170. 170. class FreteServiceTest { @Test public void deveCalcularFrete() { // cenário String uf = "SP"; this.limpaEInsereFrete("SP", 30.0); // ação FreteService service = new FreteService(); double valor = service.calcula(uf); // validação assertEquals(30.0, valor); } } jUnit
  171. 171. class FreteServiceTest { @Test public void deveCalcularFrete() { // cenário String uf = "SP"; this.limpaEInsereFrete("SP", 30.0); // ação FreteService service = new FreteService(); double valor = service.calcula(uf); // validação assertEquals(30.0, valor); } } jUnit
  172. 172. class FreteServiceTest { @Test public void deveCalcularFrete() { // cenário String uf = "SP"; this.limpaEInsereFrete("SP", 30.0); // ação FreteService service = new FreteService(); double valor = service.calcula(uf); // validação assertEquals(30.0, valor); } } jUnit DELETEFROMTB_FRETE_VALOR;
 INSERTINTO TB_FRETE_VALORVALUES(1,‘SP’,30.30);
  173. 173. class FreteServiceTest { @Test public void deveCalcularFrete() { // cenário String uf = "SP"; this.limpaEInsereFrete("SP", 30.0); // ação FreteService service = new FreteService(); double valor = service.calcula(uf); // validação assertEquals(30.0, valor); } } jUnit
  174. 174. jUnit
  175. 175. E aí, tudo testado?
  176. 176. Mando pra produção?
  177. 177. E SEnão encontrar a UF na tabela?
  178. 178. function calc_frete(uf varchar2) return number is valor_frete number; begin -- busca valor do frete na tabela SELECT f.valor INTO valor_frete FROM TB_FRETE_VALOR f WHERE f.uf_destino = uf; return valor_frete; end; PL/SQL
  179. 179. function calc_frete(uf varchar2) return number is valor_frete number; begin -- busca valor do frete na tabela SELECT f.valor INTO valor_frete FROM TB_FRETE_VALOR f WHERE f.uf_destino = uf; return valor_frete; EXCEPTION WHEN no_data_found THEN raise_application_error(-20200, ‘oops!’); end; PL/SQL
  180. 180. class FreteServiceTest { @Test public void naoDeveCalcularFreteQuandoUfNaoEncontrada() { // lógica do teste vai aqui } } jUnit
  181. 181. jUnit
  182. 182. jUnit
  183. 183. E SEencontrar mais de um frete?
  184. 184. E SE…
  185. 185. Outros Cenários
  186. 186. Desafios
  187. 187. Desconfiança
  188. 188. Pair Programming
  189. 189. Testes Automatizados
  190. 190. O pior…
  191. 191. ATRASOU mesmo!
  192. 192. Mas não foi à toa…
  193. 193. não tem LITERATURA
  194. 194. não tem COMUNIDADE
  195. 195. não tem CULTURA
  196. 196. Não se engane!
  197. 197. Tivemos bons resultados!
  198. 198. Melhoramos nosso processo
  199. 199. Simplificamos nosso ambiente
  200. 200. Diminuimos o indice de bugs
  201. 201. Não temos MEDO de mexer no código
  202. 202. Padronização da Arquitetura dos testes
  203. 203. Agora a Gerência gostou!!
  204. 204. e a partir de agora novos projetos irão adotar esta metodologia
  205. 205. o que ficou faltando?
  206. 206. treinar restante da equipe
  207. 207. Servidor de Integração
  208. 208. Cobrir procedures IMPORTANTES com testes
  209. 209. Bem…
  210. 210. O caminho é longo
  211. 211. Não será fácil…
  212. 212. Nem acontecerá da noite pro dia…
  213. 213. Obrigado! Eduardo Menezes
 edumenezes@gmail.com Rafael Ponte
 rponte@gmail.com

×