Mostrando postagens com marcador TDD. Mostrar todas as postagens
Mostrando postagens com marcador TDD. Mostrar todas as postagens

quinta-feira, 24 de abril de 2014

TDD está morto?

Nesta semana o chão estremeceu após a declaração de David Heinemeier Hansson (@DHH), autor de livros como Getting Real, Rework, Remote, além do framework Ruby On Rails e do Basecamp, postada recentemente em seu blog, de que para ele TDD está morto. O texto original pode ser encontrado aqui.

Nos últimos anos quem busca estar sempre atualizado com as práticas modernas de desenvolvimento de software tem ouvido sempre que praticar TDD, ou seja, escrever testes unitários antes de escrever o código que será testado, deve ser uma prática obrigatória para se garantir a qualidade do trabalho realizado. Livros e livros foram escritos sobre o assunto, e provavelmente alguns mais ainda serão.

O desenvolvimento utilizando TDD é conceitualmente simples: Para cada método público que pretende escrever em cada uma das entidades que compõem seu software, escreva antes um ou mais testes unitários que entreguem a esse método algumas combinações de parâmetros de entrada, o executem e por fim verifiquem se o resultado de sua execução é aquele esperado para cada um dos conjuntos de parâmetros informados. Faça isso escrevendo primeiro os testes, em seguida, antes mesmo de escrever o conteúdo do método a ser testado, execute os testes para garantir que eles não estão indicando um falso positivo, em seguida escreva apenas o mínimo de código necessário para fazer com que aquele teste passe e por fim refatore o código para torna-lo mais claro e/ou eficiente. Ao terminar essa refatoração seus testes passaram novamente e você terá um indicador para lhe dizer caso alguém faça uma besteira e acabe alterando o comportamento do seu método.

Tudo muito lindo, até se colocar em prática. Na prática, é muito difícil determinar o que testar, além de a arquitetura e o desenho do software mudarem bastante à medida em que sua implementação evolui. E quanto mais granulares os seus testes, mais difícil será mantê-los atualizados. Sem falar no inferno de mocks, fakes e stubs que acabam sendo necessários para permitir que apenas aquele método, aquela unidade de código, esteja de fato sendo testada naquele momento, e não tudo que é executado como dependência a partir dela.

Diante dessas dificuldades, muitos desistem do TDD. Creio que a maioria desista, por elas e pela falta de disposição em aprender e treinar o calhamaço de novas habilidades necessárias para se praticar TDD. Em Janeiro de 2012 o maior advogado do TDD, Uncle Bob (@unclebobmartin), autor de livros como PPP, Clean Code e The Clean Coder, escreveu um artigo em que falava justamente sobre a mudança de posicionamento necessária ao desenvolvedor para que ele pudesse finalmente virar o bit e se tornar um praticante de TDD. Esse artigo pode ser visto aqui, e é um interessante contraponto ao que foi apresentado ontem pelo David.

Pelo que já coloquei acima, já da pra perceber que minha posição se assemelha mais à posição do David nesse caso. Sempre fui extremamente pragmático, e escrever quilos e quilos de mocks e testes para verificar o comportamento de um método que em poucos dias provavelmente nem existirá mais nunca ganhou minha simpatia. Estudei muito a respeito, ainda tenho livros na minha estante sobre o assunto que lerei em breve, mas nunca consegui assumir essa prática (TDD) como uma religião, como muitos tem feito e advogado que deve ser feito. No entanto, assim como David, não me coloco no outro extremo, não sou de modo algum um Programmer Motherfucker que quer apenas escrever código do jeito que bem entender, sem critério algum por que é isso que fazermos, programar. Não estaria me dedicando a este blog agora se fosse esse o caso.

A saída pra mim foi encontrada na verdade em um irmão mais novo do TDD (Test-Driven Development) o BDD (Behavior-Driven Development). Ao qual tenho me referido bastante ultimamente como Especificação por Exemplo.

Após Dan North (@tastapodintroduzir a técnica denominada BDD, muitos afirmaram que BDD não seria mais que TDD feito da forma correta, e a forma correta nesse caso seria dar ênfase ao comportamento a ser apresentado pelo software a ser testado, e não a um único método, uma única unidade de código. Neste link e neste link vemos respostas de Uncle Bob a esse tipo de afirmação.

Dando ênfase a um comportamento, favorecemos a modularização, damos um norte ao desenvolvedor, que pode ter liberdade para criar o desenho do software, tendo como parâmetro o comportamento descrito. Tal comportamento pode ser definido por ele mesmo, ou em conjunto com outros envolvidos, como testadores e analistas de requisitos, mas será no fim parte do código fonte do sistema, será compilado, traduzido para código e testado, num ciclo muito semelhante ao ciclo do TDD, no entanto sem a ênfase absurda à unidade. Serão testes maiores, mais lentos, integrados, embora não necessariamente end-to-end. É uma técnica que com certeza vale a pena conhecer. Obtém-se muitas das vantagens do TDD, sem trazer consigo a maioria de seus problemas.

Enfim, não vou me estender demais. Queria apenas aproveitar a polêmica do momento e escrever esse texto contrastando as duas técnicas e expondo minha posição a respeito do uso de TDD.

Recentemente fiz um trabalho acadêmico sobre o assunto: Melhorando a Eficiência no Desenvolvimento de Software através da Aplicação de Técnicas de Especificação por Exemplo. Tal trabalho pode ser encontrado aqui.

sexta-feira, 20 de dezembro de 2013

Conclusão do Curso de Especialista em Estratégias em Arquitetura de Software

Desenvolvo software desde 1998, profissionalmente desde 2002, mas apenas em 2008 identifiquei a área de Arquitetura de Software como aquela que mais me desperta interesse. Naquela época, ainda era uma área bastante marginalizada, ainda sendo um pouco ainda hoje. Afinal, quantas empresas possuem o cargo Arquiteto de Software? Quantas se quer sabem o que seria um Arquiteto de Software? Infelizmente ainda não parecem ser a maioria. Por conta disso, ainda é baixa a oferta de cursos de qualificação específica na área.

Ainda em 2008, soube da criação em Belo Horizonte do IGTI, uma instituição que passava a oferecer o primeiro curso de Estratégias em Arquitetura de Software do país, sendo uma das poucas a oferecer tal curso ainda hoje. Me interessei bastante, mas por inúmeros motivos não me matriculei. Até que, em 2012 soube que o mesmo curso passou a ser oferecido na modalidade de Ensino à Distância e com isso seria bem mais fácil conseguir o tempo necessário para me dedicar às aulas. Não havia mais desculpas. Fiz o curso e gostei bastante. Aprendi muito, ratifiquei boa parte do conhecimento que adquiri na prática ao longo dos anos, fiz bons contatos profissionais e bons amigos.

Desde os primeiros meses de curso, já falávamos a respeito do trabalho de conclusão, e aproveitei a oportunidade para estudar mais a fundo dois temas que muito me agradam, e que visivelmente contribuem para a melhoria da qualidade do meu trabalho e para o aumento de minha produtividade, que são as já bem conhecidas Boas Práticas para Desenvolvimento de Software e as nem tão conhecidas Especificações por Exemplo.

Desde meu primeiro contato com Especificação por Exemplo, então conhecidas por mim apenas como Behavior-Driven Development, já notei o quanto a técnica tornava mais simples a definição do que deve ser feito e como o trabalho deve ser divido, implementado e testado. Tendo uma boa técnica para verificar continuamente a qualidade do trabalho, fica bem mais fácil refatorar continuamente o código e aplicar continuamente as tão famosas Boas Práticas.

O resultado desse trabalho está disponível neste link. Confiram.

quinta-feira, 7 de março de 2013

Pragmatismo e TDD

Anteontem, 05 de Março de 2013, Uncle Bob Martin, um dos principais defensores do desenvolvimento guiado por testes (TDD), fez uma crítica ao modo como são vistas as startups, jovens empresas que se aventuram, ousam, e se arriscam na busca do sucesso através da criação de softwares inovadores. 

Como resposta, alguns leitores tacharam o autor de ser muito dogmático a respeito da prática de TDD. E quem o conhece sabe que há alguma verdade nisso.

No dia seguinte, Uncle Bob publicou uma resposta onde apresentou o seu ponto de vista com relação ao pragmatismo vs dogmatismo no que se refere à prática de TDD, apontando situações em que ele é pragmático e não utiliza a técnica.

Segue abaixo, traduzido para nosso idioma:
Então, quando eu não pratico TDD?
  • Não escrevo testes para getters e setters. Fazer isso normalmente é besteira. Tais getters e setters serão indiretamente testados por testes de outros métodos; então não há porquê testá-los diretamente.
  • Não escrevo testes para variáveis membros. Elas também serão testadas indiretamente.
  • Não escrevo testes para funções de uma só linha ou funções que são obviamente triviais. Novamente, elas serão testadas indiretamente.
  • Não escrevo testes para GUIs. GUIs necessitam ajustes. Você tem que acertá-las no lugar alterando tamanho de fonte aqui, valores RGB ali, uma posição XY aqui, a largura de um campo ali. Fazer isso com testes primeiro é estupidez e perda de tempo.
    • No entanto, me certifico que qualquer processamento relevante no código da GUI seja removido para módulos que sejam testáveis. Não permito que código relevante passe sem testes. Portanto meus códigos de GUI são pouco mais que colas e fios que enfiam os dados no seu lugar na tela (Veja artigos sobre MVVM e Model View Presenter).
  • Em geral não escrevo testes para nenhum código que eu tenha que ajustar no lugar por tentativa e erro. Mas separo o código "ajustável" do código que estou mais certo de que escreverei testes.
    • Ocasionalmente, ajusto código no lugar e então escrevo os testes posteriormente.
    • Também ocasionalmente removo código "ajustado" e o reescrevo com testes primeiro.
    • Qual abordagem escolher é uma questão de julgamento.
  • Alguns meses atrás escrevi um programa inteiro de 100 linhas sem nenhum teste.
    • O programa era para uma única execução. Seria usado uma vez e então descartado. (Era para um efeito especial em um de meus vídeos).
    • O programa era todo relacionado à tela. Em essência, era um aplicativo GUI puro. Sendo assim eu tive que ajustar a coisa toda no lugar.
    • Escrevi em Clojure, e portanto tinha REPL! Pude executar o programa à medida em que crescia a partir da REPL, e pude ver os resultados de cada linha de código que escrevia instantaneamente. Isso não era TDD, isso era EDD (Eye Driven Development).
  • Normalmente não escrevo testes para frameworks, bancos de dados, web-servers, ou outra ferramenta de terceiros que supõe-se funciona. Crio mocks para essas coisas e testo o meu código, não o deles.
    • Claro que as vezes testo códigos de terceiros se:
      • Acredito que tenha defeitos.
      • Os resultados são rápidos e previsíveis o bastante a ponto de criar um mock ser um exagero.
Não é tudo dogma.
Essa lista não está completa. Estou certo de que pensarei em outras vezes que não escrevi testes; mas o espirito dessa lista deve estar evidente. Pragmatismo entra em jogo quando fazemos TDD. Não é apenas dogma.
Entretanto, respeito o dogma; há uma razão para isso. Pragmatismo pode as vezes se sobresair; mas: Não escreverei nenhum código de produção relevante sem fazer todo esforço para usar TDD.
Uncle Bob Martin