Diff #0: Testes e programação

Antes de mais nada…

…preciso justificar por que volto a escrever sobre assuntos técnicos. Nos ja longiquos meados dos anos 2000, escrevi muita coisa relacionada aos meus aprendizados de software livre e linux por causa dos booms da blogosfera. Blogspot e WordPress eram formas de se conectar com pessoas de interesses comuns e poder ver um pouco das opiniões umas das outras de uma maneira mais ampla. Era sempre um blog referenciando outro e assim você tinha la o sonho da Web 2.0 (em cima da plataforma do Google, mas enfim ¯\_(ツ)_/¯). Ja escrevi tutorial sobre tor, blender, bash, drivers de wifi, configuração de repositório Ubuntu, ArchLinux, a lista é longa. Tudo se perdeu na falta de zelo e descuido, no entanto. Mas era legal porque servia de referência para a própria pessoa que escrevia quando precisava revisitar um assunto numa linguagem que lhe era mais acessivel e que precisou passar por um raciocinio e esforço pra tornar compreensivel. E é por isso que volto. Espero que esses diffs sejam uteis a quem lê pois quero que sejam uteis a mim também, como escritor e programador.

Por que testes?

Porque programar é dificil. Dependendo do problema e do sistema a ser implementado, a carga cognitiva
de implementar uma solução fica insuportável. Se remetermos as primeiras tentativas de simplificar a atividade de programação, iremos chegar aos esforços de Edsger Dijkstra de dividir a atividade de programação em tarefas menores para “conquista-la”. Nos primórdios matematicos da programação, foi provado que todos os programas poderiam ser construidos com estruturas de sequencia, seleção e iteração.

Com esse fundamento de programação estruturada, Dijkstra conseguia utilizar provas euclideanas pra provar a corretude de cada uma dessas 3 estruturas fundamentais e por consequência, provar a corretude de um programa que fosse construido utilizando-as. Com isso, a decomposição de grandes sistemas em modulos e componentes prováveis poderiam garantir a plena corretude e a infaliabilidade desses programas. No entanto, sabemos que criar provas matemáticas é uma atividade complexa e por si só laboriosa (os especialistas na disciplina de analise que o digam).

Uma alternativa existente então era a possibilidade de testar, dado que é uma forma empirica de provar o funcionamento esperado de um determinado pedaço de código. Dadas as limitações, um teste cria visibilidade de incorretudes de forma que ele se torna viável para os propósitos a que ele foi delimitado. É levantada a hipotese de um dado funcionamento, observa-se dentro de um cenário construido o comportamento do programa e dai averigua-se e conclui-se se essa hipotese é valida. Como adotado no método científico, este processo é uma forma de garantir que certas expectativas dado um contexto são satisfeitas. No entanto, dadas as limitações do que é previsivel e o que é observavel , as garantias caem na limitação do contexto e, como o proprio Dijsktra dizia,

testes mostram a presença, não a ausência, de bugs

Os testes acabam por se tornar uma forma de termos visibilidade de modulos e componentes do sistema, suas interações e como isso pode-se garantir essa corretude dados os limites da especificação. Uma maneira de dividir essa enorme carga cognitiva e de resolver um problema através de um olhar critico.

Qualidade

Qualidade é o termo utilizado pra garantir padrões aceitaveis de funcionamento de um determinado produto. O antigo padrão ISO 8402-1986, precursor da ISO 9001:2015, define qualidade como “a totalidade de funcionalidades e caracteristicas de um produto ou serviço que mantem sua capacidade de satisfazer as necessidades descritas ou implicadas”. Isso infere que o produto possui alguma característica mensurável, se ela satisfaz ou não o seu propósito.

Uma faca tem a função de cortar, mas fica a duvida se ela é pra cortar um tomate ou um pedaço de carne. Como está o fio? Qual o tamanho do objeto que posso cortar? De repente, consegue-se utiliza-la para apertar parafusos, mesmo que não tenha sido feita pra isso. E ai vem a pergunta se ela consegue aperta bem aquele parafuso. Ele ficou frouxo? Ou torto? A cabeça do parafuso ficou carcomida? Existe uma série de pontos de efetividade da função exercida em um objeto solido e que conseguimos instigar mas que fica menos claro quando adentramos no mundo de escrita de software.

Alguns pontos vão sobre o que é esperado daquele sistema, ou seja sua funcionalidade. Se tem um bom design: codigo de facil compreensão e com estilização… confiável, consistente… caracteristicas que pra saber se foram atendidas precisamos de alguma métrica. No entanto, essa métrica está ligada a especificação da funcionalidade, tornando assim a métrica mais difícil de ser obtida, dados os diversos fatores mencionados. O que podemos tirar disso é que podemos nos focar no nosso mundinho e construir qualidade dentro do software atraves de testes. Alguns testes precisam de capacidade técnica especifica ou alguma distancia desse desenvolvimento de software pra mitigar qualquer tipo de viés de criador que o software possa estar submetido.

O papel da pessoa programadora

Uma vez mencionado qual o objetivo de teste e como se relaciona com a questão de qualidade, fica o questionamento do papel da pessoa que escreve o código. Aqui, uma desenvolvedora se refere a quem tem esse papel como responsabilidade primordial. Pra satisfazer os padrões de qualidade esperados pelo time ou evitar que quem tenha que testar tenha que lidar com um produto de qualidade inferior, essa desevolvedora tem que garantir a corretude do seu código e para tal espera-se que ela escreva o codigo de forma que torne possível a testabilidade e verificação do mesmo ao longo do ciclo de vida do software. Para tanto, entende-se que boa parte do ciclo de vida do software está relacionado a manutenabilidade desse sistema e tem-se inicialmente dois tipos de manutenção de código. O primeiro diz respeito a manutenabilidade de um sistema sob desenvolvimento, tento como principal objetivo manter a corretude dentro de uma arquitetura evolutiva. Testes aqui garantem segurança nas especificações e a possibilidade de utilização de técnicas que guiem a construção do próprio software intrisicamente ligado a testes (BDD, TDD, ATDD, Especificação por exemplo…).

O segundo é sobre patches e correção de bugs de sistemas ja estaveis que podem ou não possuir testes. Nesse caso, é responsabilidade de quem coda introduzir testes de caracterização de forma que seja possivel garantir visibilidade das especificações ja satisfeitas ou possuir testes que passem e garantam que bugs encontrados foram devidamente corrigidos.

E aqui ainda nem falo sobre o papel de testes design do código, pois creio que isso seja uma discussão mais ampla já que traz um outro papel do teste para alem da corretude da funcionalidade do codigo, que por si só não é trivial. Podemos dizer com segurança que testes de programação é amplo e pode envolver varias questões como

  • Quanto de testes é suficiente?
  • Quais tipos de testes dão retorno no investimento em um sistema?
  • Porque testabilidade é importante?
  • Como tornar um componente testavel?
  • O que é testabilidade?
  • O que é um bom teste?
  • Quais test doubles devo utilizar?
  • Quando devo quebrar dependencias e quando é aceitavel ?
  • Devo testar estado ou comportamento?
  • Como estruturar testes a evitar duplicação? Ou é viável duplicar?
  • Como testar situações que geram multiplas combinações de asserções?

A lista é longa e todas são relacionadas a porção de qualidade de software que cai sobre a responsabilidade da pessoa programadora. Testes unitarios, integração, componente, CI, infraestrutura de integração… são vários os aspectos que cabem ou podem caber na responsabilidade da pessoa que coda e que se beneficiam de um conhecimento de fundamentos de testes.

Apesar dessa introdução longo, orei abordar temas de forma concisa e que possa ajudar a diferencia-los nos pequenos aspectos do dia a dia de programação.

Ate a proxima.

Referências

Clean Architecture: A Craftsman’s Guide to Software, Robert C. Martin
Developer Testing: Building Quality into Software; Alexander Tarlinder
xUnit Test Patterns: Refactoring Test Code; Gerard Meszaros
Software Quality Management – Quick Guide, Tutorials Point

Add a comment

Your email address will not be published. Required fields are marked *