/s é uma gíria da internet pra dizer que aquela frase contém sarcasmo 😆
Quem me segue nas redes sociais ou por aqui sabe que eu sou um entusiasta de testes automatizados e teste de software no geral (não confundir com TDD).
Esse artigo é um relato da decisão que fizemos no final de 2022, quando eu estava liderando um projeto com prazo apertadíssimo. Nele, abordarei nosso contexto, nossas hipóteses, as consequências e o que aprendemos com essa decisão. Eu não fornecerei detalhes específicos do projeto por motivos de NDA, mas tentarei ser específico o suficiente para abordar os pontos desejados.
Contexto
Em outubro de 2022, eu estava envolvido em um projeto com um prazo extremamente desafiador. O projeto era ambíguo, com várias frentes, envolvendo aproximadamente 4 equipes diferentes e cerca de 20 pessoas, entre engenharia e produto.
Quando a equipe de engenharia se reuniu com o gerente para analisar o escopo restante, a projeção indicava a entrega para junho de 2023. O problema era que tínhamos um prazo "não-negociável" de abril de 2023 por razões comerciais. A única solução viável? Reduzir o escopo.
Ao analisar o escopo a ser reduzido, incluindo funcionalidades e infraestrutura adicional, nosso gerente fez a seguinte pergunta: "E quanto a toda essa tarefa de testes de integração?". Antes de continuar, uma pausa para definir "testes de integração".
Testes de integração? O quê? Vamos para uma pausa estratégica sobre testes de integração.
No contexto desse artigo, eu me refiro a testes de integração como testes onde é necessário você subir sua aplicação e/ou interagir com componentes através da rede.
Por exemplo, um@SpringBootTest
que sobe o contexto e te permite testar a API conversando com o banco de dados.
No meu caso, os testes acima iriam fazer deploy do nosso código no AWS (na minha conta e depois na conta de homologação) e de lá eu poderia testar os vários microserviços interagindo uns com os outros através da orquestração.
Agora continuamos com a nossa programação normal...
Onde estávamos? Ah sim, o gerente. Você, que está lendo, deve estar pensando: "Claro, só podia ser um gerente...".
"Respire fundo" e permita-me acrescentar alguns detalhes:
- Eu trabalhei com esse gerente por ANOS, e confio extremamente no trabalho dessa pessoa.
- Ele possui experiência em testes. Mais do que qualquer um, ele estimulava a equipe de engenharia a trabalhar em testes e aprimorar nossa qualidade.
- Além disso, ele costumava ouvir o time, principalmente as pessoas mais experientes da equipe. Se naquele momento eu tivesse dito 'Nem pensar', havia uma grande possibilidade de ele acatar minha decisão."
A nossa hipótese
A pergunta feita naquele momento me fez refletir: "Será que realmente conseguiremos economizar tempo e ainda entregar com sucesso?".
O processo de decisão foi o seguinte:
- "Nós temos MUITOS testes de unidade; se houver alguma regressão no sistema, provavelmente esses testes identificarão qualquer erro".
- Além disso, a parte do sistema que desejávamos testar não era trivial; não tínhamos garantia de que os novos testes, do jeito que os estávamos projetando, realmente fariam alguma diferença.
- Por fim, a equipe trabalhando neste projeto era extremamente experiente, e conhecíamos o negócio e o sistema de ponta a ponta. Consequentemente, pensamos que os testes poderiam ser apenas o time seguindo as melhores práticas por seguir, sem necessariamente serem úteis naquele momento.
Assim, com esse risco documentado, a decisão foi tomada. Optamos por prosseguir com os testes de unidade e ignorar o segundo método de testes de integração até a entrega em abril. No entanto, estávamos enganados...
Consequências
O nosso primeiro "milestone" era em Dezembro de 2022. Naquele momento, nós poderíamos integrar o trabalho sendo feito pelos 4 times e testar os primeiros casos de uso de ponta a ponta. Foi aí que os problemas começaram.
Nós documentamos cerca de 16 casos de uso que teriam que ser testados. O setup para esses casos de uso era não trivial e envolvia configurar as contas na AWS das pessoas engenheiras envolvidas nos testes.
Porém, o problema de verdade acontecia quando nós encontrávamos um "bug". O time tinha que corrigir o bug, enviar a correção e testar manualmente novamente em ambiente de homologação. Obviamente, esse processo todo de re-testar era muito lento e atrasou muito a entrega do nosso primeiro milestone.
Mas o problemas não pararam por aí... logo elas chegaram, elas que são as melhores amigas de nós pessoas devs quando estamos com projetos atrasados. Sim, elas, as "regressões". Com cada correção que nós enviávamos, invariavelmente, nós introduzíamos bugs em outras partes do sistema.
Mas por quê isso estava acontecendo?
A causa
Pra entender o motivo desses bugs apesar de 90%+ de cobertura de testes é importante entender algumas detalhes sobre o nosso sistema:
- Esse projeto envolvia mudanças em 5 serviços diferentes.
- Muitas vezes, o que era corrigido no sistema A, tinha o único objetivo de propagar a informação até o sistema C. Apenas no sistema C poderíamos verificar que tudo estava correto.
- Um desses sistemas, era uma orquestração implementada com AWS Step Functions. Embora eu goste do controle que esse tipo de arquitetura proporciona, o trade-off é que você pode introduzir problemas sem perceber ao modificar um dos estados que afeta indiretamente outro estado na máquina de estados. Além disso, testar unicamente um estado não garante que sua máquina de estados está correta. A melhor forma de testar esse tipo de arquitetura é escrever testes que exercitem a máquina de estados como um todo, e tratar o output final da máquina de estados como o que deve ser verificado pelos testes.
Os testes que nós decidimos não escrever afetava justamente o item #3 acima. Ou seja, quando nós quebrávamos algo na máquina de estado, as vezes nós não percebíamos a consequência disso em outras partes do sistema.
Voltando aos eixos
Logo que entregamos o primeiro milestone, nós decidimos dar um "rollback" naquela decisão inicial. Os testes repetitivos e as regressões estavam causando tanto dano que era melhor sacrificar uma parte da nossa "gordura" no projeto e implementá-los pra resolver o problema de uma vez por todas.
Acabou que entregar os testes foi mais rápido do que tínhamos estimado inicialmente 🥳 e depois que adicionamos eles na nossa pipeline de CI/CD as regressões pararam 100%.
Aprendizado
Essa jornada me ensinou lições valiosas:
- Testes são importantes independente do nível de experiência do time. Mesmo com o contexto adequado e com a experiência o nosso time ainda cometeu erros e causou regressões. Os testes são os nossos paraquedas pra nos proteger justamente nessas situações.
- Essa experiência reforçou ainda mais o meu entusiasmo por testes. Eu sempre implementei estratégias de testes em todos os projetos que eu passei e justamente no projeto que eu pensei "sabe de uma coisa, talvez dessa vez a gente não precise?", foi a vez que mais precisamos deles. "Lei de murphy" que fala né?
- Embora o time tenha salvo 3 semanas iniciais pra implementar os testes. Nós perdemos muito mais tempo com regressões e testes manuais repetitivos, ou seja, testes vão te economizar tempo na cauda longa.
Conclusão
Espero que esse relato abra os olhos de vocês sobre a importância de testes automatizados. Não apenas isso, mas mesmo como um time experiente com 90%+ de cobertura em testes de unidade não foi suficiente pra nos prevenir de enfrentar problemas.
Finalmente, o meu amigo @rponte fala sobre a importância de testes de integração em sistemas distribuídos. Eu recomendo MUITO vocês assistirem a palestra do Ponte.
Inspirado pela talk acima, em sequência a esse artigo eu vou escrever mais sobre estratégias de testes em sistemas distribuídos.
De repente eu consigo trazer mais pessoas pra escrever testes e observar a importância deles em nossos projetos. Abraços e se curtiu, me segue aí já que meu conteúdo técnico vai ficar mais por aqui a partir de agora 🥰.
Top comments (12)
Estou entrando agora na área da programação e eu tenho uma curiosidade aparte sobre testes e como podemos implementar, ler esse artigo me deixou mais entusiasmado em aprender sobre testes, muito obrigado por compartilhar esse relato fizeram meus olhinhos brilharem 🦤.
Uma vez que você escreve testes, é muito difícil ter confiança em algo sem escrever testes. Não tem como garantir que não ocorrerá regressão, pelo menos humanos não conseguem.
Obrigado por compartilhar tua experiência conosco, Hugo.
Hey Hogo,
Excelente post, parabéns por compartilhar!
Tem muita gente que fala de Test, Test, Test, mas nao realça a diferença de cada tipo de test. Fala como se existise somente um tipo, nivel e próposito.
O mais fácil e simples é o unitário, o de Integraçacao e 2e2 sao os mais chatos pra fazer o setup, configurar pra ficar fácil depois de implementar.
Dependendo um 2e2 com bons use cases bem escrito seja o mínimo, mas tendos em todas as camadas vai ajudar a identificar bugs de forma mais precisa.
Vou deixar aqui uma referencia para quem ainda nao entende a diferenca dos tipos de teste, sobre Test Pyramid martinfowler.com/articles/practica...
Achei muito bacana seu relato. Estou estudando TDD com python e consegui associar vários tópicos com alguns aspectos do que você escreveu. De fato, durante os estudos o autor do livro enfatiza que testes realmente parecem ser uma perda de tempo inicial, mas que no long run fazem toda a diferença.
Achei curiosa a parte que você fala para não confundir testes, no geral, com TDD. Poderia fazer algum post sobre o assunto no futuro, sobre o que acha ou o que costumam achar sobre TDD? Embora eu programe diariamente em python (trabalho num banco de investimentos fazendo pequenas automações para melhorar a eficiência dos processos), não estou sujeito aos ritos e governanças de TI (não tenho governança centralizada acerca de utilizar o GIT, por exemplo), e, portanto, me falta essa experiencia de TI propriamente dita, a qual eu fico curioso pra saber como funciona, e posts como esse realmente ajudam!
Excelente moral! E assisti essa palestra esses dias e reforço a importância dela pra quem puder assistir!
Obrigado pelo artigo :)
esse /s é novidade para mim, e olha que nem estou tão velho haha, bom post!
Muita gente nova chegando através desse post. Não deixem de olhar os outros posts, inclusive, os compilados das dicas que tem muita coisa boa lá. 🤗
Que artigo MARAVILHOSO! Obrigado pelo relato, vai me servir de inspiração e ajuda!
Que bom que você curtiu Alicia. Eu gosto muito de testes, vou continuar escrevendo mais nesse tópico :).
Que doidera hein!!!!
Como estimaram a entrega para Junho?
Horas por feature?
Essa é uma das coisas que mais pega para mim. As nossas estimativas não estão legais
Olhamos ao longo das ultimas 8 sprints qual a velocidade de entrega de pontos do time por Sprint. Olhamos os pontos restantes do projeto e calculamos o número de Sprints que faltavam + % de segurança.
A estimativa estava relativamente correta e até conservadora pra ser honesto. Se fosse pra ser feito "do jeito certo" Junho seria uma data melhor.