Testes: pragmatismo ou ideologia?

January 31st, 2009 § 6 comments § permalink

Eu gosto bastante do que Joel Spolsky e Jeff Atwood escrevem, mas a última conversa entre os dois no postcast regular que eles mantém realmente releva uma boa falta de conhecimento sobre o que testes e TDD realmente representam.

No núcleo do argumento dos dois está a idéia de que alta cobertura por meio de testes–Jeff Atwood menciona a falta de 95% ou mais–torna a manutenção dos próprios testes problemática considerando a proporção de testes que precisa ser mudada quando o código em si também é modificado. Um argumento secundário é que testes são mais indicados para código legado do que código que está sendo desenvolvido, a menos que o mesmo tenha rigidez natural como a especificação de um compilador.

A solução para o segundo argumento é simples: todo código é legado. Simples assim. Código que entrou em produção é legado por definição e o argumento de que há uma diferença entre código com “mais idade” e “menos idade” é dúbio no pior dos casos.

Lendo o diálogo entre os dois, é possível perceber que há uma confusão sobre o que testes realmente representam–especialmente quando os dois falam sobre a relação entre testes e arquitetura, algo que em um contexto ágil é normalmente referenciado por TDD e BDD.

Essa confusão–de que testes são feitos para cobrir a interface de uma classe ou método–é extremamente comum mesmo entre os próprios proponentes de testes, seja entre aqueles que propõem testes como ferramenta de design como é o caso de TDD e BDD, seja entre os que simplesmente os usam para validar o funcionamento posterior do código.

Eu posso concordar parcialmente com o argumento de que 100% de cobertura geralmente é desnecessária. De fato, 100% de cobertura nunca representa uma garantia absoluta de que seu código, e por extensão sua arquitetura, não possuem problemas.

Primeiro porque 100% de cobertura real é algo virtualmente impossível de ser conseguido para um corpo mais complexo de código (e realmente impossível se o mesmo tem dependências externas). Segundo, por que não importa a quantidade de testes que você tiver, a complexidade ciclomática sempre vai acabar com seu dia nas horas mais inapropriadas. Não importa o quantidade de white-box ou black-box testing que você possuir, cobertura é alvo exponencialmente proporcional à evolução do seu código.

Existe também um outro fator representado por uma variação casual da regra 80/20. Os maiores ganhos de testes estão nas partes mais complexas do seu código, é claro, mas os ganhos reais geralmente aparecem nos desvios pequenos que pegam você de surpresa. Nesse ponto, quando maior a cobertura, maior facilidade de introduzir novos testes.

E aqui está o verdadeiro ponto em que o argumento de Spolsky e Attwood falha: testes não são sobre interfaces, APIs ou contratos. Antes, eles são sobre o relacionamento entre as partes distintas de seu código. Nessa diferença essencial está um dos grandes debates recentes da comunidade ágil: qual é a diferença real entre TDD e BDD?

A minha resposta está centrada em uma pequena reinterpretação de TDD. Ao invés de usar o termo como Test-Driven Development, eu prefiro ver a questão toda como Test-Driven Design.

Se você está usando testes como uma ferramenta para guiar o design de sua aplicação, isso significa que você estará preocupado mais em saber com as peças se encaixam do que como elas funcionam individualmente, como mencionado acima.

Joel diz:

But the real problem with unit tests as I’ve discovered is that the type of changes that you tend to make as code evolves tend to break a constant percentage of your unit tests. Sometimes you will make a change to your code that, somehow, breaks 10% of your unit tests.

Você realmente pode fazer uma mudança que quebra 10% de seus testes, mas para que isso aconteça, o design do sistema precisa estar tão falho e seus testes tão quebradiços que os mesmos podem ser jogados fora sem remorso.

Há pouco mais do que duas semanas, eu fiz uma modificação considerável em uma biblioteca que escrevi. Em linhas gerais, significa trocar o motor de um middleware de DRb (Ruby distribuído) para JSON over HTTP. Esse código em particular está 100% coberto.

Por causa das diferenças entre os protocolos, uma quantidade de código significativa teve que ser modificada. Mas apenas três ou quatro novos testes foram escritos e nenhum dos outros foi modificado. Código foi movido, reorganizado em classes diferentes e mesmo assim, os testes resistiram bravamente.

A explicação é simples: enquanto existem testes que realmente testam como funções específicas funcionam, a vasta maioria destes testes é focado em como as várias partes da aplicação trocam informações: se os dados que saíram daqui nesse formato chegaram do outro lado do formato necessário, se essa AST foi reorganizada apropriadamente de modo que o gerador do outro lado da equação possa produzir a linguagem apropriada e assim por diante.

Jeff continua com outra asserção:

Yeah, it’s a balancing act. And I don’t want to come out and say I’m against [unit] testing, because I’m really not. Anything that improves quality is good. But there’s multiple axes you’re working on here; quality is just one axis. And I find, sadly, to be completely honest with everybody listening, quality really doesn’t matter that much, in the big scheme of things…

Isso é algo que me fez repensar todo o contexto da discussão. Eu realmente fico espantado de ver alguém que considera Peopleware e The Mythical-Man Month como referências básicas dizer isso. Ambos os livros focam em arquitetura dirigida por qualidade como um foco para produzir código mais robusto, entregue em menor tempo e que traz mais valor para o negócio e para o usuário. Os parágrafos finais da transcrição são realmente decepcionante nesse aspecto.

Para finalizar, TDD realmente não é um fim em si próprio. Mas o argumento de que usar testes é um desperdício de tempo–seja para quem está cobrindo 100% do seu código de forma viável ou para quem usa testes como validação de funcionalidade–é simplesmente falho.

Joel é conhecido bastante por seu pragmatismo em relação à correção de bugs. Testes são uma maneira bastante pragmática de garantir que aquele conjunto particular de situações de falha não vá se repetir por engano em alguma codificação posterior. Isso é business value, algo que tanto Joel como Jeff valorizam.

No final das contas, pragmatismo é o que realmente conta. E testes, quanto feitos da maneira certa, são algumas das mais pragmáticas ferramentas que um programador tem à sua disposição.

Waterfalling Agile

January 18th, 2009 § 1 comment § permalink

O Luiz Rocha escreve com razão sobre os perigos de confundir Agile com um conjunto de métodos que devem ser seguidos para que o “processo” funcione. É uma coisa natural de organizações–que por extensão são pessoas–procurarem um ponto do balanço entre necessidades discordantes e este é um dos pontos mais propícios para transformar a filosofia Agile em uma metodologia que pouco difere do tradicional Waterfall.

Por outro lado, existe uma tentação muito grande de pensar em Agile com o oposto exato do Waterfall e transformar isso em uma desculpar para não ter nenhum processo ou método coerente de desenvolvimento. É muito comum encontrar empresas imersas na desorganização que descrevem os seus processos como ágeis.

“Não escrevemos documentação, oras. Somos Agile. Preferimos software que funciona a documentação compreensiva. Não é isso o que o manifesto diz?”

É claro que o manifesto termina com a afirmação: That is, while there is value in the items on the right, we value the items on the left more. Isso não impede que tudo seja abandonado em favor de uma pretensa agilidade.

Como o Luiz diz, não é um task board que faz uma empresa ou equipe ágil. Tampouco é a falta de planos em contraponto a uma resposta completamente desorganizada a mudanças.

Agile exige um compromisso com o detalhe:

Para valorizar interação e não processos é necessário entender que o nível de detalhe requerido do primeiro é maior que o do segundo.

Para valorizar software que funciona é preciso uma cultura de qualidade, o que implica em muito mais trabalho do que escrever documentação compreensiva–e isso vai muito além de colocar no quadro de tarefas itens para escrever testes, algo que nada mais é do que transformar o Agile em Waterfall.

Para valorizar a colaboração do cliente é preciso ouvir e raciocinar sobre o que foi ouvido, transformando isso em valor. Negociar contratos é muito mais simples.

Finalmente, para valorizar resposta rápida a mudanças é necessário uma atitude de constante atenção ao que está sendo feito e como isso vai evoluir no futuro. Novamente, seguir um plano é incomparavelmente mais fácil, mesmo que o mesmo seja completamente falho.

Agile não é, e nunca foi, uma opção para aqueles que querem tomar a rota mais fácil. Excelência técnica, cultura de qualidade, atenção ao detalhe–transformar isso em segunda natureza requer anos de prática: o mesmo tipo de esforço que um artesão passa a vida aplicando.

Se você quer algo simples, esqueça Agile. Não é para quem não tem um compromisso com o tempo necessário para que coisas permanentes floresçam.

Balanço cultural de 2008

January 6th, 2009 § 4 comments § permalink

Mesmo sendo um ano agitado, deu para ler e ver bastante coisa em 2008. Não vou fazer uma lista de destaques como fiz no ano passado, mas só comparar rapidamente os números:

  • Livros: 68 (68 no ano anterior)
  • Filmes: 73 (106 no ano anterior)
  • Séries: 94 (200 no ano anterior)
  • Contos: 12 (nenhum no ano anterior)
  • Quadrinhos: 2 (nenhum no ano anterior)
  • Teatro: 1 (não lembro no ano anterior)

Consegui ler o mesmo tanto de livros, o que é bom. Reduzi o número de filmes e séries, o que também é bom, considerando que a safra do ano passado não foi lá essas coisas.

Estou começando a ler alguns quadrinhos novamente, aproveitando que o pessoal da WebCo possui vários dos clássicos que fizeram época. Confesso que sou um péssimo conhecedor do assunto e nesse final de ano comecei a seguir algumas recomendações. Vamos ver o que dá no próximo ano.

Finalmente, vergonha completa em qualquer coisa que exija sair de casa. 😉 Nesse ano agora, espero conseguir ir mais ao teatro, ouvir mais orquestras e, em geral, fazer mais coisas do tipo.

Balanço cultural de dezembro

January 6th, 2009 § 0 comments § permalink

Dezembro foi um mês bem atípico para mim nas leituras. Depois dos primeiros quinze dias agitados, resolvi tirar férias pela primeira vez em quatro anos. O resultado foi o seguinte:

  • 3 livros
  • 35 episódios de séries

Comecei o mês com Halting State, de Charles Stross. Stross é um dos poucos autores que consegue escrever sobre futuros próximos de uma forma plausível. Seus livros são cheios de especulações tecnológicas e sociais que poderiam muito bem ser as notícias de amanhã e Halting State não é uma exceção.

Nesse livro, o ponto focal é o roubo de um banco–com o detalhe de que o banco é localizado em um jogo que é essencialmente uma versão futura do World of Warcraft. A partir disso, Stross pinta uma novela detetivesca em um mundo onde a convergência já aconteceu e realidade consensual é algo do dia-a-dia, explorando as implicações disso tanto para os relacionamentos entre as pessoas como para a diplomacia internacional.

Seguindo no mês, completei mais uma passo da minha educação cyberpunk lendo Snow Crash, de Neal Stephenson. Eu sei que é uma vergonha confessar, mas eu ainda não li muitos dos romances originais do movimento. Estou recuperando agora.

Snow Crash é um Stephenson clássico, com o mesmo humor, verve e capacidade de extrapolação exibida nos livros mais recentes do mestre do cyberpunk. Só mesmo Stephenson para chamar o seu personagem principal de Hiro Protagonist e torná-lo um samurai, hacker e entregador de pizza. Além disso, é impressionante como um livro de 1992 pode parecer completamente atual. Nada do que ele escreve sente datado.

A estória segue Hiro e seus vários associados enquanto ele tenta descobrir o mistério por trás de uma droga virtual chamada Snow Crash cujo alvo específico são os hackers e os mistérios por trás dos seus criadores e distribuidores. Leitura perfeita para geeks.

Finalmente, terminei o mês lendo Hyperion, por Dan Simmons. Do Simmons eu havia lido anteriormente Ilium e Olympus, sua duologia pós-humana reconstruindo a guerra de Tróia em um futuro distante e fiquei impressionado com sua mistura de pós-tecnologia e literatura (baseada primariamente em Shakespeare, Homero, Proust e Nabokov). Hyperion estava na fila há tempo por ter ganho o Hugo e segue o mesmo padrão, desta vez misturando The Cantebury Tales e John Keats.

Obviamente, por ser mais antigo, o livro demonstra um domínio menor das técnicas que tornaram o trabalho de Simmons famoso e o fato de que eu li os trabalhos posteriores primeiro implicou em notar algumas falhas que eu não teria notado de outra forma. Mesmo assim, gostei do livro o suficiente para prosseguir pelos outros três que seguem Hyperion e estou quase terminando o quarto e final.

Nas séries, só mesmo completando o que ainda não tinha visto das que eu acompanho nos corridos meses anteriores. Com a exceção de uma menção desonrosa para Heroes, que permanece uma porcaria completa, estou esperando somente os retornos do próximo ano.

Agora é só seguir para a fila do próximo ano. :)

Where am I?

You are currently viewing the archives for January, 2009 at Superfície Reflexiva.