24 Mar
Já faz um bom tempo que eu mudei o meu ciclo de desenvolvimento com testes do Red, Green, Refactor (ciclo tradicional de TDD) para algo um pouco diferente.
O que aconteceu foi que eu tinha muito problema para pensar nas unidades pequenas sem ter as unidades grandes. Ah? Basicamente eu não consigo pensar em como implementar sem estar resolvendo o problema.
Confuso ainda, certo?
Bom, digamos que eu queira implementar algo que transforme um html em uma árvore (basicamente, parsear html). Eu não consigo pensar em como eu faria para parsear a tag. Apenas consigo pensar em como funcionaria para o html. Algo como:
HtmlParseado html = new HtmlParser().
parse("<html><title>Conteudo</title></html>");
Somente no momento em que estou dentro do método parse que eu consigo pensar em como descobrir quais são as tags. Por que isso? Por causa da abstração.
No código acima não faz o menor sentido pensar nas tags, apenas no html completo. Dentro do método parse começa a fazer sentido procurar pelas tags.
Então o que tenho feito? Eu crio um ou mais testes que sobre a funcionalidade inteira (no caso, o que o parse deve fazer com o html).
Algo como:
@Test
public void testaQueOParserFunciona(){
HtmlParseado html = new HtmlParser().
parse("<html><title>Conteudo</title></html>");
Assert.assertEquals("html", html.getFirstChild().getTagName());
...
}
O problema é que esse teste é muito grande para guiar o desenvolvimento. O que eu faço então? Parto para o problema menor que é o reconhecimento de tags.
Como nesse ponto eu já consigo imaginar mais ou menos o que quero que aconteça, consigo criar os testes para fazer o reconhecimento de tags.
Mas durante todo esse tempo, o meu teste do ponto mais alto da abstração continua sem passar. Isso quebra com o RGR, mas me ajuda muito com o desenvolvimento da interface de uso.
Talvez eu tenha perdido um pouco na qualidade do código usando essa abordagem top-down, mas ganho bastante em termos de usabilidade desse código. Isso me força a pensar em primeiro lugar em como vai ser usada a funcionalidade final e não nos menores constituintes dela.
Outra coisa que esses testes me ajudam muito é a saber quando eu terminei a funcionalidade mais complexa.
O que acham disso? Já fizeram (ou fazem) algo semelhante?
Posts Relacionados:
Acompanhe-nos por
RSS, por Email ou via Twitter.
Veja como ter um desconto no Dreamhost: um excelente servidor web.
Email This Post
3 Responses for "Red, Green, Refactor?"
Oi, Jonas!
Também tenho seguido esse modo de desenvolvimento faz um tempo e concordo com você.
Aprendi isso quando comecei a mexer num projeto rails que tinha testes de integração com Cucumber e unitários com RSpec. A gente foi aprendendo a primeiro escrever o teste do Cucumber, depois escrever os testes do RSpec necessários e só aí implementar o necessário para fazer passar tudo.
Hoje em dia sigo esse processo sempre que dá. Digo isso porque no projeto em que estou trabalhando agora os testes de integração são mais custosos de escrever e rodar (é um defeito a se corrigir um dia).
Acho que isso não quebra o Red-Green-Refactor exatamente. Acho que pode ser visto de duas maneiras: um Red-Green-Refactor dentro de outro ou ainda um Red-Green-Refactor, mas escrevendo mais testes de uma vez antes de fazer passar (se você for refatorar só depois de fazer o teste mais genérico passar).
Além da vantagem que você mencionou (melhor usabilidade de código), ainda há de se considerar que testes de integração muitas vezes são deixados por último ou esquecidos e essa prática incentiva a escrevê-los. Mais cobertura de código e mais garantia de funcionalidade sem bugs.
Apoio muito essa prática!
Abraços
Jonas, também uso algo bem semelhante a essa técnica que você descreve e acredito que mesmo não sendo 100% TDD, tá valendo. :)
Pois, o princípio mais importante do TDD, na minha visão, é fazer o desenvolvedor parar para pensar em qual é o resultado que ele tem que ter ao fim da implementação/alteração de um método, isto é, a unidade. E também, ao fim do requisito/funcionalidade inteira.
Embora, se esteja pensando em um nível um pouco mais alto que uma unidade primeiramente. Se está no caminho.
Mas, com certeza, desse modo perdemos alguns dos benefícios do TDD, que já vi vários desenvolvedores que usam TDD a risca relatando, como, por exemplo, não precisar nunca mais fazer um debug.
Se metade dos desenvolvedores que eu conheço seguissem essa linha, o mundo seria bem, mais bem melhor.
:P
Abs
Na realidade normalmente é muito difícil (senão impossível) ter uma down-top das unidades, justamente por elas na maioria das vezes serem ainda inexistentes.
No caso o que acontece é que como pode testar algo que nunca foi formado, quando começa o desenvolvimento todos vêem o resultado, nunca o resultante.
Entretanto o problema disso tudo esta mais no planejamento do software do que simplesmente dos testes em si, já que 80% do tempo é planejamento, nunca desenvolvimento, mas o que acontece muitas vezes é que se começa a partir do desenvolvimento ao invés do planejamento, até que entendo as razões já que dar uma séria impressão de que o sistema esta parado ou o desenvolvedor esta jogando tempo fora.
Um exemplo prática foi o que estava desenvolvendo recentemente trabalhando com tecnologias arcaicas e improdutivas (diga-se struts), um dos problemas que passei foi por causa da exaustiva configuração que mais atrapalhava que ajudava, fora a ausência de diversas facilidades que precisava para tornar meu trabalho mais produtivo, assim passei um certo tempo planejando como eliminaria esses fatores, como o xml e o melhor uso do conceito MVC, o resultado ficou muito bom, mesmo usando a versão 1.2 do struts (acredito eu, mas estar entre 1.0 a 1.3) conseguir fazer seguir um conceito bem semelhante ao que é usado em Ruby on Rails e no Spaghetti* framework, mas sim gastei muito, mas muito tempo só planejando para depois construir, entretanto a construção foi bem rápida e direta (mas ainda usei o debug, é meio complicado utilizar o TDD com portlets).
Leave a reply