Author Archives: mauricioaniche

Testes e infraestrutura: inimigos de longa data

TL;DR: Suas classes com regras de negócio não podem depender de infraestrutura. Elas devem ser facilmente testáveis por meio de testes de unidade. Dependências devem ter interfaces amigáveis e serem facilmente mockadas.

Às vezes ouço perguntas como “como testo meu sistema em Android”, ou “como testo meu sistema em JSF”, ou “como testo meu sistema em <ponha-sua-tecnologia-aqui>”. Pra mim, essa pergunta faz todo sentido se você está procurando uma maneira de fazer testes de sistema. Algo como Selenium, só que Android. No entanto, se você está pensando em testes de unidade, essa pergunta não deveria ser muito importante.

Regras de negócio são importantes. Tão importantes que merecem ficar o mais afastado possível da sua infraestrutura. Ou seja, não importa se você usa JSF, Android, ou whatever, o coração do sistema deve ficar em classes Java, simples, que não dependem de nada externo. Se você pensar sempre assim, pronto, todas suas regras de negócio serão facilmente testadas.

Ah, mas e se pra realizar aquela regra de negócios, eu precisar consultar uma infraestrutura? Sei lá, pegar um dado do banco de dados, ou postar algo em um serviço web? Faça sua classe depender de uma classe que tenha uma interface bastante amigável. Algo como bd.pegaValor() ou correios.calcula(“SP”). Nada que você tenha que ficar escrevendo linhas e linhas para chegar no resultado que espera. Assim, fica fácil mockar depois para testar. E dentro da dependência, você faz o que tiver que fazer pra fazer a infraestrutura funcionar.

Se você pensar assim sempre, a infraestrutura que está usando deixa de ser importante. Afinal, você fugiu dela. E testou o que precisava ser testado.

Como você usa construtores?

Construtores são legais, afinal, eles nos permitem garantir que uma classe não será instanciada sem alguns dados básicos. No entanto, a dúvida sempre aparece: o que devemos passar pelo construtor e o que devemos passar pelo método?

Bem, minhas regras pessoais são:

  • Se a classe é uma entidade, então eu peço no construtor todos os dados necessários para que a entidade seja válida. Por exemplo, Pessoa precisa de nome, vai pelo construtor.
  • Se a classe não é uma entidade, e ela precisa de “ferramentas de trabalho” (outras dependências, como DAOs, etc), eu as passo todas pelo construtor, sempre. Já os valores que serão utilizados ao longo do processamento, eu passo sempre pelo método.
  • Se algum dos frameworks que estou usando me obrigar a ter um construtor default, eu o crio, com a menor visibilidade possível, e o anoto com @Deprecated.
  • Se estou refatorando algum código legado, não me incomodo de ter um construtor padrão, fazendo alguma ação padrão.
  • Se minha classe aceita diferentes combinações de valores obrigatórios, tenho diferentes construtores. Em entidades, se tenho atributos não obrigatórios, às vezes crio dois construtores, recebendo e não recebendo aquele atributo. Depende da situação.

Acho que é isso. Se vc tiver as suas regras, estou curioso para conhecê-las!

Desenvolvedores e Testes Automatizados em suas IDEs

Será que fazemos o que falamos? Falamos o que fazemos? Em um estudo bastante interessante, os pesquisadores monitoraram programadores usando o Eclipse, e vejam o que encontraram:

  • A maioria dos projetos e usuários não praticam testes ativamente.
  • Desenvolvedores, em sua maioria, não rodam testes na IDE. Mas quando o fazem, fazem com muita frequência.
  • Código de testes e código de produção não co-evoluem de maneira elegante.
  • Testes que são executados na IDE rodam muito rápido.
  • Desenvolvedores comumente executam apenas um conjunto específico de testes. Na maioria dos casos, os desenvolvedores executam apenas um teste.
  • A maioria das execuções de testes dentro das IDEs falham.
  • A reação mais comum a um teste falhando é mergulhar no código de produção culpado.
  • TDD não é amplamente praticado. E os programadores que dizem fazer, não o fazem estritamente e nem para todas as modificações.
  • Desenvolvedores gastam um quarto do seu tempo trabalhando em testes. Curiosamente, eles acreditavam que esse número era o dobro maior.

E o mais legal: os resultados observadores contradizem as respostas que esses mesmos desenvolvedores deram em uma survey.

E você? Como faz!? 🙂

Beller, Moritz, Georgios Gousios, Annibale Panichella, and Andy Zaidman. “When, how, and why developers (do not) test in their IDEs.” In Proceedings of the 2015 10th Joint Meeting on Foundations of Software Engineering, pp. 179-190. ACM, 2015.

Não teste fluxos!

Recebi esses dias um e-mail bastante interessante. A pergunta era: devo ou não devo testar o código abaixo?

A pergunta é bastante válida, afinal podemos pensar em dois caminhos diferentes para testar esse código:

  • Fazer um teste de integração, batendo no banco de dados de verdade. Assim, garantiríamos que o salva() realmente funciona.
  • Fazer um teste de unidade, mockar o DAO, e garantir que a regra de validação funciona, e que o salva() é invocado.

A minha abordagem seria: não teste!

Quando o código basicamente controla fluxo, eu evito testá-lo com testes de unidade. Simplesmente não faz sentido. Você vai ficar apanhando com mocks, e no fim, vai só garantir que os métodos são invocados na ordem certa.

Nesse código em particular, eu preferia mover a função valida() para uma classe separada, e testá-la isoladamente. O DAO também teria um teste para o salvar(). E o código acima, que apenas controla o fluxo não teria testes de unidade.

Mas como eu o testaria? Se for uma aplicação web, esse código provavelmente estaria em um controlador. Aí, eu prefiro testar via teste de sistema. Aliás, o argumento que dei aqui é o mesmo que dou para quando digo que também não testo controladores de maneira isolada.

Primeiros Passos com Testes de Unidade – Parte 3

No post anterior, discutimos um pouco sobre pensar nos vários cenários. E conseguimos! Agora que nossa bateria de testes está legal, perceba a segurança que ela nos dá. Podemos abrir o método joga() e mudar sua implementação inteira. Para garantir que ela funciona, basta rodarmos os testes. Veja como eles nos dão a liberdade de mexermos no código à vontade, sem medo. Isso é um grande benefício da nossa bateria de testes.

O próximo passo é começar a pensar na qualidade do código que escrevemos em nossos testes. Afinal, você já percebeu que escreveremos muito código. E, claro, se ele não for fácil de manter, teremos problemas.

Nesse post, vamos começar devagar. Vamos remover o código repetido que existe em todos os nossos testes. Repare que a linha abaixo está em todos nossos testes:

Além de repetida, essa é uma linha perigosa em nossos testes. Ela é a linha que instancia a classe sob teste. Isso significa que qualquer mudança em seu projeto pode fazer com que a bateria de testes inteira pare de funcionar. Faça um teste e modifique o construtor dela! Mais pra frente, mostrarei que, ao projetar para testabilidade, construtores são fundamentais e mudam com frequência.

Vamos então isolar essa linha em um método só pra ele. Esse método instancia o objeto e o guarda em um atributo da classe, para que consigamos vê-lo dentro de qualquer dos métodos de teste:

Agora podemos remover a linha repetida de todos nossos métodos de teste. E como esse é um método que queremos executar antes de cada método de teste, basta avisarmos ao JUnit para fazer isso automaticamente. E só anotar o método de setUp() com @Before. Veja como ficou todo nosso código:

Você pode colocar um Sysout dentro do setUp() para perceber que ele é executado sempre antes de cada teste. E veja que agora se mudarmos o construtor dessa classe, mudaremos apenas em um lugar. Muito melhor e contrado.

Por esse post, é isso. Lembre-se então de evitar código repetido nos seus testes e, em particular, o código que instancia a classe sob teste.

Primeiros Passos com Testes de Unidade – Parte 2

No post passado, escrevemos testes para o FizzBuzz. E foi fácil: criamos a classe FizzBuzzTest e escrevemos lá métodos, com diferentes entradas e saídas. A grande charada é que, como conhecemos a entrada, também sabemos a saída. Mas será que os testes que temos são suficientes? Vamos agora discutir um pouco sobre o que testar.

Veja novamente nosso código de produção:

O grande truque é olhar para o código e pensar nos vários caminhos diferentes que ele pode ter. Para isso, analisarmos cada instrução que faz o fluxo do código mudar. Por exemplo, ifs, fors, whiles, etc. Em nosso FizzBuzz, temos:

  • Cenário 1: O primeiro if tem duas condições: número é múltiplo de 5 E múltiplo de 7. Se esse if der verdadeiro, o programa retorna “fizzbuzz” e acaba.
  • Cenário 2: O segundo if valida se o número é múltiplo de 5. Se der verdadeiro, o programa retorna “fizz” e acaba.
  • Cenário 3: O terceiro if valida se o número é múltiplo de 7. Se der verdadeiro, o programa retorna “buzz” e acaba.
  • Cenário 4: O quarto caminho acontece quando nenhum dos anteriores acontece. O programa retorna o número e acaba.

O próximo passo é: qual a entrada que precisamos passar para que o cenário 1 aconteça? E depois, para o cenário 2? E assim por diante. Foi o que fizemos: passamos 35 para o cenário 1 acontecer, ou 13 para o cenário 4 acontecer.

E perceba também que temos um teste para cada cenário. Preciso de mais? Geralmente não. Se você pensar bem nos cenários, verá que não precisará exercitar mais de uma entrada em cada. Chamamos essas entradas diferentes, mas que exercitam o código da mesma maneira, de classes de equivalência. Um teste por classe de equivalência é uma boa regra a seguir.

No entanto, nada te impede de ter um pouco mais de segurança. Quando lidamos com algoritmos que envolvem números, como é o caso desse, podemos exercitar cenários similares. Não só para garantir que funciona, mas também para facilitar o entendimento quando outro desenvolvedor ler o teste.

E casos excepcionais? Se você achar que seu programa precisa tratar casos excepcionais, como zero, nulo ou exceção, você então deve escrever o teste para garantir que seu programa se comportará corretamente.

Neste post, discuti sobre como deve ser seu pensamento na hora de escrever um teste. Mas ainda temos 3 posts. Estamos chegando lá! 🙂

Primeiros Passos com Testes de Unidade – Parte 1

Olá,

Para comemorar os 50 posts do meu blog, farei uma série sobre primeiros passos com testes de unidade. Então, se ainda não pratica, essa é a hora!

Bem, pra testar código, significa que precisamos ter código, certo? Então, veja o exemplo abaixo. É uma simples implementação do jogo fizzbuzz. Se o número é múltiplo de 5, ele imprime “fizz”. Se é múltipo de 7, ele imprime “buzz”. Se é múltplo de 5 e 7, imprime “fizzbuzz”. Caso contrário, só imprime o número.

A pergunta é: como testar esse código de maneira automática? Será que existe algum robôzinho mágico que sai por aí testando? Testar não é tão legal assim. Mas é fácil! Tudo que precisamos fazer é executar essa função várias vezes, passando dados diferentes pra ela, e ver como ela se comporta.

Pense que o programa está rodando na web, e você precisa manualmente garantir que ela funcione. Ligue sua mente destrutiva e pense nos vários casos que possam fazer esse programa não funcionar.

Como somos programadores, podemos olhar para o código e ver que ele tem 4 caminhos diferentes (um para cada if, mais o caminho onde nenhum if é verdadeiro). Precisamos executar o programa com cada um deles. Vamos começar com o primeiro, onde ele precisa retornar “fizz” se o número é múltiplo de 5.

Legal! Ele retorna “fizz”. Está funcionando! Mas ainda não está tão automático quanto gostaríamos. Pois, você, ser humano, precisa ver que a resposta saiu certa. Precisamos pedir pra máquina comparar. Afinal, é fácil, sabemos que se a entrada for 5, a saída é “fizz”. Basta compararmos:

Se rodarmos, ele imprime “verdadeiro”. Quer dizer que a comparação deu certo e o programa comportou-se como esperado! Agora vá no código do FizzBuzz, e altere ali “% 5” para “% 6”. Sim, estamos colocando um bug em nosso código. O que acontece agora? Ele imprime “falso”. Ótimo, verdadeiro se está certo, falso se estiver errado.

Parabéns! Você escreveu seu primeiro teste de unidade! Pois é, é simples assim. Basta você pensar em entradas e saídas, e executar seu programa com elas! Agora faça um código parecido para testar a entrada 7. Você sabe que a saída será… “buzz”.

Mas agora vamos fazer isso melhor. Vamos usar o JUnit, o framework hiper-pop de testes de unidade do mundo Java. O que ele faz? Ele é um robô que vai fazer tudo pra mim? Não! Ele não faz muita coisa, além de te ajudar a dizer se seus testes estão passando ou não. Ao invés de imprimirmos verdadeiros ou falsos (que não ia funcionar bem quando tivéssemos 1000 testes desse), ele pinta a tela de verde ou vermelho, e nos mostra qual “sysout” não funcionou.

No Eclipse, é fácil plugar o JUnit. Aperte o botão direito do mouse em cima do seu projeto, escolha a opção Build Path -> Configure Build Path. Na aba Libraries, clique em Add Library. Selecione JUnit -> JUnit 4. E pronto!

Agora basta usarmos. Vamos escrever métodos de teste, um para cada diferente cenário (entrada/saída) que temos para nosso programa. Todo método deve ser anotado com @Test, ser público e retornar void. E aí, no fim, ao invés de fazermos Sysout, usaremos o Assert.assertEquals(), que é quem faz a comparação que garante que a saída bate com o esperado. Veja:

Se você clicar com o botão direito do mouse no código-fonte, e selecionar Run -> Run as JUnit Test, verá uma tela como a abaixo. Verde, ou seja funcionou.

junit

Agora, faça o teste e coloque um bug na aplicação. Adivinha que cor vai ficar?

falhou

Fácil, né?! Agora basta continuarmos a escrever outros métodos de teste, para os vários cenários. Veja:

Legal, né!? Sua máquina agora roda 5 testes mais rápido do que um piscar de olhos! Um ser humano nunca seria tão rápido! Testes automatizados são muito vantajosos:

  • Rodam muito rápido. Você pode ter milhares de testes e ainda assim executá-los todos em apenas alguns segundos.
  • Se rodam rápido, quer dizer que você vai rodá-los o dia todo. Ou seja, quando algum quebrar, você corrigirá mais rápido, pois tudo estará fresco na sua cabeça. Sem testes, você acha um bug muuuito depois de ter escrito o código, e isso torna tudo mais difícil.
  • Não custa caro. A máquina não cobra nada para executar. E você só gasta tempo nele na hora de escrever. Já parou pra pensar quantas vezes você executa o mesmo teste manual ao longo do dia?

Parabéns, você sabe escrever testes automatizados! Será que tem mais!? Aguarde o próximo post.

O que faz um arquiteto de software?

Semana passada, Alberto Souza e eu fizemos um Hangout sobre arquitetura de software. E uma pergunta que nos fez pensar bastante foi “o que é um arquiteto de software?”

Não sei se há uma definição oficial por alguém chique, mas para mim, um arquiteto é aquele que:

  • Consegue comparar duas tecnologias/práticas/etc e discutir sobre suas vantagens e desvantagens.
  • Já entregou muito software, e já passou por diferentes situações. Experiência.
  • Não necessariamente sabe cada vírgula do framework que a equipe usa, mas compreende a idéia por trás dele, bem como suas desvantagens e as soluções concorrentes.
  • Apesar de conhecer bastante os conceitos, ele os experimenta no mundo real, por exemplo, por meio de POCs ou projetos menores.
  • Reflete constantemente sobre suas decisões.
  • Participa do processo de desenvolvimento com a equipe. Talvez não programando 100% do tempo, mas revisando e discutindo a implementação atual.
  • Não precisa ser necessariamente o mais experiente da equipe. É um papel dentro dela, e pode rotacionar de acordo com o problema e conhecimento de cada um.

Esqueci algo? Me ajudem a completar a lista com diferentes opiniões!

Como começar a refatorar seu legado em PHP/ASP/JSP?

TL;DR: O primeiro passo na refatoração de arquivos de script é mover todo o código de acesso a banco de dados, regras de negócio existentes e fluxo para o topo do arquivo. Para isso, crie as variáveis que serão usados na parte de baixo. Em seguida, o HTML que contém código PHP apenas para regras de visualização.

Não é difícil encontrarmos aqueles arquivos de script imensos, em PHP, ASP ou JSP, misturando um pouco de tudo: HTML, lógica, acesso a dados, mais HTML, mais lógica, etc:

A pergunta é: Como começar a refatorar esse código? Muitos anos atrás, tive uma experiência bastante interessante com um sistema enorme escrito só em JSP. O primeiro passo que costumava fazer é fazer com que todo código JSP ficasse no começo do arquivo. Assim, toda lógica de negócio, acesso a banco de dados ficaria agrupado. O resto da página com HTML conteria scripts apenas para alguma lógica de visualização.

Veja o código anterior refatorado. Tanto rs quanto rs2 foram para cima. Criei a variável total também para deixar o código um pouco melhor.

Porque fiz isso? Para começar a separar as responsabilidades desse código. Colocar todo “controle de fluxo” em um único lugar, e regras de visualização em outro. Mesmo que estando no mesmo arquivo, a separação já é visível e facilita a manutenção. Sim, no fim, estou tentando separar o M, do V, do C.

Aqui, começamos a separar o C do V. O M (modelo) não existe nesse código! O próximo passo seria começar a criar classes de domínio e lidar com elas, ao invés de manipular diretamente o array que as funções de acesso a banco geralmente devolvem. Mas isso é assunto para um próximo post!

PS: rs e rs2 são péssimos nomes. Você, claro, escolha nomes que tenham a ver com o seu domínio.

Como são as boas práticas de um médico cirurgião?

TL;DR: Boas práticas não deveriam mostrar apenas sua implementação, mas também em que contextos elas deram certo e, tão importante quanto, onde elas não são recomendadas.

É bastante interessante que todas nossas boas práticas de desenvolvimento de software sejam empíricas. Afinal, é pondo a mão na massa que você consegue experimentar diferentes abordagens e ver os prós e contras de cada uma delas. Grady Booch, no seu texto sobre RUP [1], diz que uma “boa prática é uma abordagem que se mostrou válida na indústria e que, quando combinadas, atacam as raízes de problemas em desenvolvimento de software; elas são boas práticas, não tanto porque elas conseguem quantificar seu valor, mas sim porque elas são comumente usadas na indústria em projetos de sucesso”.

Exemplo de nossas boas práticas nossas são “escreva métodos com poucas linhas”, “evite ifs aninhados”, “não tenha longas hierarquias de classes”, e assim por diante. O curioso é que, de vez em quando, queremos (ou eu quero, hehe?!) provar que uma boa prática é realmente a melhor. TDD é melhor. Agil é melhor.

Durante algumas viagens mentais, comparo um programador com um médico cirurgião. O médico sabe tudo do corpo humano, assim como o programador sabe tudo de código. Mas cada corpo é diferente do outro, assim como cada software é diferente do outro. Ele também deve ter suas boas práticas, como “segurar o aparelho X com a mão esquerda e Y com a mão direita é melhor”, ou mesmo “fazer o corte 2 cm abaixo da barriga pode dar mais espaço para manobra”.

Minha pergunta é: será que eles também ficam nessa maluquice de descobrir qual a melhor prática, ou simplesmente preferem conhecer várias delas, e usar sua experiência para escolher a melhor para aquele caso?

Talvez sempre que você bolarmos uma boa prática, devêssemos pensar não só em detalhar as técnicas para sua implementação, mas também deixar claro quais os contextos que elas deram certo, e quais os seus possíveis contras. Faça você o exercício: quando que TDD pode ser ruim? Quando que ágil pode ser?

PS: Apesar de ter alguns médicos na família, não entendo nada. Prova disso é que não soube dar exemplos de ferramentas usadas em cirurgias, e também não sei ao menos se o “fazer o corte 2cm abaixo”, faz sentido.

[1] Booch, Grady. “Software development best practices.” The Rational Unified Process: an introduction (1998): 3-16.