TDD substitui ou complementa modelagem?

Bom dia, há algum tempo eu tenho lido e praticado (um pouco) de TDD, muito embora até hoje não tenha conseguido trazê-lo totalmente para a minha realidade profissional. Nessa minha pouca experiência, percebo que: mesmo que os testes ajudam na especifação do sistema, rascunhar um UML ou outro vem muito a calhar, especialmente na hora de entender o domínio do sistema ser construído sair aquele 1o teste.

Sendo assim, o que vocês acham ?

obs: haters de TDD e testes unitários são bem vindos! :twisted:

O único livro sobre DDD, do Eric Evans, foi um sucesso de vendas. Para repetir, inventaram uma nova metodologia: TDD. Mais alguém vai ficar rico, não será você. A grande “sacada” dessas metodologias ágeis é justamente não produzir qualquer documentação, incluindo modelagem. Todo o negócio fica na classe de Domínio, mesmo que tenha 1000 linhas. A aplicação “vai saindo” a cada entrega. E não tem problema se ficou ruim ou não atendeu as expectativas do seu cliente. Isso agora é problema da outra equipe, responsável pela manutenção. Você ainda está no time de elite, produzindo apenas coisas novas.

Este novo modelo de criar aplicações a partir de testes, porque o próprio teste passa a ser a história do caso de uso, poderia ser melhor avaliado. Afinal, teste também é fonte. É legal um fonte massaroquento e você começa a fazer testes unitários, produz a sensação de “tudo novo de novo”. No longo prazo, quando for necessário fazer manutenção nos testes, essa situação será o retrato da situação anterior, quando os testes ainda não existiam.

Vai da necessidade, se ninguém usa a documentação então não faça por fazer, as vezes quando se pára pra pensar e questionar pode ser a falta da necessidade. Mas se vai usar e vê retorno, então uma coisa pode complementar a outra e não substituir. Importante é não fazer nada só por etiqueta, se algo vai agregar valor ao sucesso do negócio do cliente diante de uma criticidade por exemplo, tendo investimento/recurso para isso então tá valendo.

Profissionalmente na equipe que trabalho não fazemos testes antes de desenvolver, de “documentação” para o antes de desenvolver, só temos especificação escrita junto com o cliente, e de UML no máximo caso de uso e só quando são muitos papeis envolvidos. O ciclo de entrega é pequeno, a presença e parceria do cliente ajuda mais do que fazer os testes antes. Acho que muitas vezes apresentar um item em andamento que não seria o esperado e ajustar seria o mesmo tempo de fazer os testes antes/ver erros/produzir 100%. Claro que para isso o cliente precisa ser parceiro e não aquele que só quer ver a tela perfeita fechada no final.

Putz, olha me desculpe mas não acredito que você tem lido qualquer coisa a respeito de DDD ou TDD e até mesmo sobre metodologias ágeis. Em primeiro lugar um não é fruto do outro. TDD é muito antigo, foi criado por Kent Beck muito antes de se ouvir falar de DDD. TDD e DDD não são a mesma coisa, um não substitui o outro! Para ter uma ideia TDD era usado com Smaltalk! Outra coisa TDD e DDD não são metologias ágeis, você deve estar confundindo com Scrum, XP e Kanbam. TDD e DDD fazem parte das metodologias ágeis, testes são obrigatórios para XP por exemplo.

Se você tivesse lido o livro do Evans, vai ver que em lugar algum ele falou que não se deve fazer documentação. Na verdade nenhuma metologia ágil diz que não se deve fazer documentação o que ela falam é da importância da documentação. Com uma metodologia ágil você tem documentação, mas ela é um guia para desenvolvimento.

Bah. Nunca vi isso com alguém que usa TDD e DDD na verdade a ideia é justamente NÃO fazer isso! Se alguém faz isso então não está usando TDD ou DDD!

A ideia de TDD é justamente não ter código massaroquento, pois uma coisa inerente a ele é a refatoração continua. Também não existe manutenção de Teste, não sei da onde vc tirou isso.

[quote=rmendes08]Bom dia, há algum tempo eu tenho lido e praticado (um pouco) de TDD, muito embora até hoje não tenha conseguido trazê-lo totalmente para a minha realidade profissional. Nessa minha pouca experiência, percebo que: mesmo que os testes ajudam na especifação do sistema, rascunhar um UML ou outro vem muito a calhar, especialmente na hora de entender o domínio do sistema ser construído sair aquele 1o teste.

Sendo assim, o que vocês acham ?

obs: haters de TDD e testes unitários são bem vindos! :twisted: [/quote]

TDD não substitui você entender o problema. Nada impede você de rascunhar algumas classes para ter uma idéia do modelo, na verdade acredito que isso seja fundamental para entender o dominio e se comunicar com seu cliente. O problema é você implementar essas as classes antes de fazer os testes! O ideal também é que essas classes do modelo não tenha funções ou somente as necessárias para entender o modelo. Eu costumo usar um quadro branco para criar modelar o dominio e depois implementar.

Uma grande vantagem de TDD é que ela te mostra rapidamente quando você não entendeu o dominio, pois o código começa a ficar complexo e difícill de desenvolver!

[quote=x@ndy]Nada impede você de rascunhar algumas classes para ter uma idéia do modelo, na verdade acredito que isso seja fundamental para entender o dominio e se comunicar com seu cliente.
[/quote]
Com certeza, o papel de pão numa mesa redonda é fundamental, a tela vicia a dar alt tab e “partir para implementação”.

Acho que não. A modelagem inicial eu acho sempre uma boa abordagem para se ter uma direção.

Depois disso eu penso que pode-se partir para TDD direto para começar a criar classes e outros relacionamentos, mas ainda assim eu gosto de ter um diagrama de classe (pelo menos a um nível mais abstrato, sem ter que mostrar métodos e coisas do tipo). O diagrama é bom para quem está iniciando ter uma idéia do sistema. [=

[quote=Hebert Coelho]Acho que não. A modelagem inicial eu acho sempre uma boa abordagem para se ter uma direção.

Depois disso eu penso que pode-se partir para TDD direto para começar a criar classes e outros relacionamentos, mas ainda assim eu gosto de ter um diagrama de classe (pelo menos a um nível mais abstrato, sem ter que mostrar métodos e coisas do tipo). O diagrama é bom para quem está iniciando ter uma idéia do sistema. [=[/quote]

Concordo. O que não se pode é se prender ao diagrama e nesse caso ter um diagrama mais “abstrato”, mais para ver os relacionamentos é ótimo! O modelo deve ser guiado pelo entendimento do domínio e um modelo inicial pode estar errado. O bom de TDD é que ele indica facilmente quando seguimos um caminho errado e não entendemos o domino pois normalmente nesses casos os testes começam a se tornar complexos com alto acoplamento de classes e baixa coesão e nesse momento deve-se parar e refletir o que se está fazendo! Por que o sistema está ficando tão complexo? Realmente entendemos o dominio do cliente? Ele é tão complexo quanto estamos implementando?

O maior problema de se criar um diagrama é se prender a ele. Isso acontece muito no desenvolvimento tradicional, principalmente em fabricas de software. Nesses casos a documentação é a regra e não se pode quebra-la. O problema é que diagrama de classes não interage com você, não de tá feedback. O papel aceita tudo, mas nem tudo que está no papel pode ser feito ou se pode é muito complexo. O que mais gosto em TDD é o feedback rápido que me mostra quando estou desviando do caminho.

PS: Pegando um gancho, gostaria a opnião de vcs a respeito de uma coisa! A algum tempo tenho usado diagramas de classes (sem funções, somente com os relacionamentos) para se comunicar com o cliente. Tirando a herança que eles não entendem e que tenho evitado tenho obtido muito sucesso. Depois se uma explicação inicial de como funciona a classe (eu digo normalmente que é um documento ou objeto que ele usa) e como funciona os relacionamentos, eles entendem perfeitamente e me corrigem quando estou fazendo algo errado! Com isso tento levar o q estou fazendo para mundo deles em busca de feedback. Alguém por acaso já tentou? Se sim como foi?

[quote=Hebert Coelho]Acho que não. A modelagem inicial eu acho sempre uma boa abordagem para se ter uma direção.

Depois disso eu penso que pode-se partir para TDD direto para começar a criar classes e outros relacionamentos, mas ainda assim eu gosto de ter um diagrama de classe (pelo menos a um nível mais abstrato, sem ter que mostrar métodos e coisas do tipo). O diagrama é bom para quem está iniciando ter uma idéia do sistema. [=[/quote]

Acho que esse eh o ponto, voce deve fazer da forma com que se sente mais a vontade. TDD, em nenhum momento proibe, nem encoraja, o uso de UML seja lá o quão aprofundada for. Eu, por exemplo, não costumo modelar nada em UML antes, quando estou fazendo algo sozinho, eu imagino o modelo e o implemento com os testes. Quando estou em equipe, procuro ter certeza de que estamos todos falando da mesma coisa, entao faço alguns rabiscos em UML, se necessario, pra ajudar a “unificar” o modelo.

Resumindo: Se voce se sente mais a vontade com um modelo de classes já desenhado, isso nem de longe fere o TDD. O único cuidado é pra não se ater a ele como se fosse lei e recusar melhoras nesse modelo, sugerida pelos testes, só porque não estavam no documento inicial.

[quote=x@ndy]
PS: Pegando um gancho, gostaria a opnião de vcs a respeito de uma coisa! A algum tempo tenho usado diagramas de classes (sem funções, somente com os relacionamentos) para se comunicar com o cliente. Tirando a herança que eles não entendem e que tenho evitado tenho obtido muito sucesso. Depois se uma explicação inicial de como funciona a classe (eu digo normalmente que é um documento ou objeto que ele usa) e como funciona os relacionamentos, eles entendem perfeitamente e me corrigem quando estou fazendo algo errado! Com isso tento levar o q estou fazendo para mundo deles em busca de feedback. Alguém por acaso já tentou? Se sim como foi? [/quote]

Não sei, já tentei isso e o cara ficou completamente perdido, embora dissesse que entendia. Não sei se por culpa minha, mas ele não entendia. Talvez não seja possível com todos os clientes.

Eu, particularmente, prefiro protótipos. Mas eu acho, e provavelmente você vai concordar, que o importante é você falar a mesma lingua do cliente, seja la em que idioma for.

[quote=YvGa][quote=x@ndy]
PS: Pegando um gancho, gostaria a opnião de vcs a respeito de uma coisa! A algum tempo tenho usado diagramas de classes (sem funções, somente com os relacionamentos) para se comunicar com o cliente. Tirando a herança que eles não entendem e que tenho evitado tenho obtido muito sucesso. Depois se uma explicação inicial de como funciona a classe (eu digo normalmente que é um documento ou objeto que ele usa) e como funciona os relacionamentos, eles entendem perfeitamente e me corrigem quando estou fazendo algo errado! Com isso tento levar o q estou fazendo para mundo deles em busca de feedback. Alguém por acaso já tentou? Se sim como foi? [/quote]

Não sei, já tentei isso e o cara ficou completamente perdido, embora dissesse que entendia. Não sei se por culpa minha, mas ele não entendia. Talvez não seja possível com todos os clientes.

Eu, particularmente, prefiro protótipos. Mas eu acho, e provavelmente você vai concordar, que o importante é você falar a mesma lingua do cliente, seja la em que idioma for.[/quote]

No inicio notei que eles não entediam, mas refinei o modo de exibir o modelo e nem digo que são classes. Como uso palavras do dominio dele para as classes e normalmente elas representam documentos fica fácil. Mas não dá para colocar funções, no máximo alguns campos.

TDD não substitui você entender o problema. Nada impede você de rascunhar algumas classes para ter uma idéia do modelo (…)
[/quote]
Pensando bem essa dúvida do rmendes faz bastante sentido. Se você estiver seguindo o TDD à risca, como manda o livro, acaba realmente ficando mais difícil planejar com antecedência.
Segundo o TDD você deve fazer a implementação (simultaneamente ao design) em passos pequeninos: um pequeno incremento no teste, um pequeno incremento no código para passar no teste, uma refatorada para eliminar duplicidades. Sempre baseando um ciclo no resultado do anterior. E uma coisa que ele coloca muita ênfase: PASSOS PEQUENINOS! Idealmente, não mais de um minuto de planejamento + codificação em cada ciclo. E mais: não pode “atropelar”, ou seja, tentar prever coisas que não fazem parte do incremento atual.

E aí, como conciliar esse procedimento com um planejamento inicial? Se eu reunir a equipe, desenhar alguns diagramas e chegarmos a uma solução completa (ou quase completa) quando for começar a programar estarei “trapaceando” o TDD, não? Pois acabei de atropelar e pensei de antemão em como todo o programa deverá funcionar.

Também queria saber do pessoal sobre isso:

Vocês tem conseguido aplicar o TDD de forma razoavelmente rigorosa?

Eu particularmente tenho dificuldades para me adaptar ao modo de pensar do TDD, especialmente quanto aos “small steps”, é difícil olhar só para o passo atual sem planejar mais à frente. Acabo escrevendo um teste que pega a funcionalidade quase completa do método que estou criando, e depois preciso escrever uma grande quantidade de código para passar o teste.
Acho essa mudança mais difícil do que passar da programação procedural para OOP…

TDD não substitui você entender o problema. Nada impede você de rascunhar algumas classes para ter uma idéia do modelo (…)
[/quote]
Pensando bem essa dúvida do rmendes faz bastante sentido. Se você estiver seguindo o TDD à risca, como manda o livro, acaba realmente ficando mais difícil planejar com antecedência.
Segundo o TDD você deve fazer a implementação (simultaneamente ao design) em passos pequeninos: um pequeno incremento no teste, um pequeno incremento no código para passar no teste, uma refatorada para eliminar duplicidades. Sempre baseando um ciclo no resultado do anterior. E uma coisa que ele coloca muita ênfase: PASSOS PEQUENINOS! Idealmente, não mais de um minuto de planejamento + codificação em cada ciclo. E mais: não pode “atropelar”, ou seja, tentar prever coisas que não fazem parte do incremento atual.

E aí, como conciliar esse procedimento com um planejamento inicial? Se eu reunir a equipe, desenhar alguns diagramas e chegarmos a uma solução completa (ou quase completa) quando for começar a programar estarei “trapaceando” o TDD, não? Pois acabei de atropelar e pensei de antemão em como todo o programa deverá funcionar.[/quote]

Ops, vejo um problema ai! Em momento algum do livro do Kent ele fala que você não deve fazer um rascunho ou que não deva entender o dominio! TDD é parte do desenvolvimento de software e não é tudo! É fundamental entender o dominio, ou seja, entender o negócio que você está implementando. Não tem como implementar algo que você não conheça. TDD fala da parte de implementação, mas implementar oq? Ai entra o DDD que fala justamente que você deve entender o dominio do seu cliente, que você deve falar a mesma língua que ele e que isso deve ser representado em código. Você deve fazer de tudo para entender o dominio, não da para sair simplesmente programando.

Se seu chefe pedisse para você programar um simulador de motor de carro oq você faria? Eu iria estudar como o um motor funciona, de quais peças ele é constituído e como elas se relacionam. Muito provavelmente eu criaria um rascunho com as classes que esse domínio tem. Mas seria apenas um rascunho algo que me ajuda-se a entender o problema. Um rascunho não é nd mais que um rascunho, se for feito em papel eu posso amassa-lo e joga-lo fora a qualquer momento e começar do zero, se for feito em um quadro (eu faço os meus assim pois fica mais fácil) é só apagar e começar de novo.

O problema é perder tempo precioso modelando classes, definindo métodos e depois ir para o código, seguindo fielmente o modelo feito! Um modelo documental você tem que seguir fielmente um rascunho não, é uma ideia e se não deu certo joga fora ou altera! A ideia do rascunho assim como dos Testes é ter um feedback rápido. Você faz um rascunho e cria uma duzia de testes para implementar aquele rascunho ou melhor, para implementar uma classe do rascunho! Com esses testes você tem um feedback rápido se aquilo que você pensou está certo, se você realmente entendeu o dominio!

Também queria saber do pessoal sobre isso:

Vocês tem conseguido aplicar o TDD de forma razoavelmente rigorosa?
[/quote]

Depende do que voce considera rigorosa. Sim, eu tenho aplicado e tem funcionado. O TDD em si é bem simples, a dificuldade está em tentar por testes em algo complexo, isso torna os testes complexos. Simplifique o modelo e os testes ficarao simples.

[quote=gomesrod]
Eu particularmente tenho dificuldades para me adaptar ao modo de pensar do TDD, especialmente quanto aos “small steps”, é difícil olhar só para o passo atual sem planejar mais à frente. Acabo escrevendo um teste que pega a funcionalidade quase completa do método que estou criando, e depois preciso escrever uma grande quantidade de código para passar o teste.
Acho essa mudança mais difícil do que passar da programação procedural para OOP…[/quote]

É muito dificil julgar baseado em alguns parágrafos sem ver nada de código, mas o teu comentário me passa a impressão de que você está com problemas de atribuição de responsabilidade nos seus objetos. Se você pega a funcionalidade completa e tenta testar e tem dificuldade em separar isso, talvez elas estejam emaranhadas umas nas outras.

Vamos supor que voce tenha na sua mais alta camada um metodo que executa uma tarefa extremamente complexa. Ainda que ela, por força da regra de negócio, seja extremamente complexa, ela irá executar uma série de tarefas bem definidas. Se cada passo é bem definido, você tem em cada um desses passos, algo simples. E são nesses passos que estarão seus testes.

Lógico, nada impede que você tenha testes que integrem estas partes e confirmem que juntas elas estão funcionando corretamente, mas haverá testes unitários para cada um dos passos simples que irão compor a tarefa complexa.

O foco dos small steps não é necessáriamente no teste, mas na prórpia funcionalidade que você está implementando. E como disse o Xandy, para fazer a parte você terá que entender o todo, mas entender os small steps é compreender que esse todo é divido em partes e cada uma delas pode ser testada.

Supondo que você queira fazer uma venda().

La no mais alto ponto de abstracao voce terá um vender(), que recebera as informacoes vindas do usuario, como o que, para quem, a que preço, em que condições, com quais restricoes e etc…

Nesse vender(), podem estar muitos passos como:
estoque suficiente
cliente mora em uma regiao que permite entrega expressa
cliente nao possui pendencia financeira com a empresa
cliente tem direito a 10% de desconto para compras acima de 1000 reais

E assim por diante. Cada passo desse é independente do outro e pode ser testado separadamente. E se algum deles puder se subdividir, essas subdivisoes tambem podem ser testadas isoladamente. Note que para saber se o cliente mora em determinada regiao, nao se precisa saber se ele esta comprando alguma coisa ou nao. Ele mora ou não mora. Se ha estoque suficiente, há e pronto, nenhuma dessas funcionalidades precisa saber porque esta sendo chamada. Elas são independentes.

E você concentra seus testes nas partes independentes primeiro. Depois voce pode, e deve, integra-las, mas as responsabilidades estarão isoladas e sendo testadas separadamente.

Também queria saber do pessoal sobre isso:

Vocês tem conseguido aplicar o TDD de forma razoavelmente rigorosa?

Eu particularmente tenho dificuldades para me adaptar ao modo de pensar do TDD, especialmente quanto aos “small steps”, é difícil olhar só para o passo atual sem planejar mais à frente. Acabo escrevendo um teste que pega a funcionalidade quase completa do método que estou criando, e depois preciso escrever uma grande quantidade de código para passar o teste.
Acho essa mudança mais difícil do que passar da programação procedural para OOP…[/quote]
Não sei como você desenvolve, mas para TDD é necessário planejar! Isso é feito escrevendo quais testes devem ser feitos! Você escreve os testes, ai pega o primeiro teste da lista e implementa! Para Testar uma funcionalidade você tem saber o que está testando, no mínimo o resultado esperado! No livro do kent ele da varios exemplos. Uma forma é
implementar o q vai se testar no próprio teste. Por exemplo se você vai implementar uma soma vai fazer isso[code]
// Criando o teste - e rodando (sinal vermelho)
int x = 5;
int y = 7

int somaEsperada = x + y;
int resultadoSoma = soma(x, y);

assertEquals(somaEsperada, resultadoSoma)

int soma(x, y){
return 0;
}[/code][code]
// Sinal verde.
int x = 5;
int y = 7

int somaExperada = x + y;
int resultadoSoma = soma(x, y);
assertEquals(somaExperada, resultadoSoma)

int soma(x, y){
return 10;
}
[/code][code]
// Refatore.
int x = 5;
int y = 7

int somaExperada = x + y;
int resultadoSoma = soma(x, y);
assertEquals(somaExperada, resultadoSoma)

int soma(x, y){
return (x + y);
}
[/code]Esses são os pequenos passos! Mas nem sempre é necessário fazer assim. Eu sei como é uma soma eu posso primeiro criar o teste de uma forma mais simples e simplesmente refatorar, fazendo a refatoração junto com o sinal vermelho. Isso tudo depende da minha confiança no que estou fazendo:// Criando o teste - e rodando (sinal vermelho) assertEquals(12, soma(7, 5)); ... int soma(x, y){ return 0; } // Refatore, Sinal verde. assertEquals(12, soma(7, 5)); ... int soma(x, y){ return (x + y); }

Você planeja as funcionalidades mas não como implementar essa funcionalidade! Cada funcionalidade é testada e durante a criação do teste você implementa a funcionalidade. Testes devem ser mínimos, testes grandes é sinal de algo errado, muito provavelmente baixa coesão. Poucas classes e testes longos é complicados é um grande indicativo de problemas. TDD evita isso fazendo com que você implemente somente aquilo que seja necessário no momento

O autor do tópico quer a discussão… então… vou jogar uma bombinha… :twisted: rs

Comentem a seguinte afirmação:
Testes unitarios não testam a arquitetura do sistema. Como TDD é baseado em testes de pequenos pedaços funcionais, e de acordo com o que foi falado aqui, não deve-se planejar. Desenvolver com TDD é um facilitador para que seu sistema termine com uma arquitetura questionável.

[quote=rogelgarcia]O autor do tópico quer a discussão… então… vou jogar uma bombinha… :twisted: rs

Comentem a seguinte afirmação:
Testes unitarios não testam a arquitetura do sistema. Como TDD é baseado em testes de pequenos pedaços funcionais, e de acordo com o que foi falado aqui, não deve-se planejar. Desenvolver com TDD é um facilitador para que seu sistema termine com uma arquitetura questionável.

[/quote]Mas tdd é >>>>>unitário<<<< o próprio nome diz.
Se você quer teste da arquitetura, vá para outros testes como o de integração. uai!

[quote=Hebert Coelho]Mas tdd é >>>>>unitário<<<< o próprio nome diz.
Se você quer teste da arquitetura, vá para outros testes como o de integração. uai![/quote]

Então… seguindo esse raciocínio… o que acontece…

Você tem uma funcionalidade. Então, você cria um teste. Faz todos os procedimentos até ele passar.
Depois, pega outra funcionalidade, e repete o processo.
Faz isso mil vezes.
No final, onde está a arquitetura do sistema?

O problema que levantei não é a falta de teste da arquitetura. O que quiz dizer é: seguindo o TDD, você não terá uma boa arquitetura.

obs: Só estou fazendo o papel de advogado do diabo…

[quote=rogelgarcia]O autor do tópico quer a discussão… então… vou jogar uma bombinha… :twisted: rs

Comentem a seguinte afirmação:
Testes unitarios não testam a arquitetura do sistema. Como TDD é baseado em testes de pequenos pedaços funcionais, e de acordo com o que foi falado aqui, não deve-se planejar. Desenvolver com TDD é um facilitador para que seu sistema termine com uma arquitetura questionável.

[/quote]
Putz…nada haver! Esse tipo de afirmação embora lógica é uma falácia e demostra um total desconhecimento de TDD!

  1. Arquitetura não é só desenvolvimento. Envolve um conjunto de coisas. O desenvolvimento é somente parte é parte do processo arquitetural!
  2. O que TDD tem haver com falta de planejamento! Por quê usando TDD eu não posso fazer um planejamento? O que eu não tenho é uma documentação especificando exatamente o que deve ser implementado e isso não é planejamento é artefato da análise
  3. Da onde TDD é testar pequenos pedaços do sistema? Cada teste deve testar uma pequena parte, uma funcionalidade. Mas eu devo testar todas as funcionalidades, de modo que acabo por testar totalmente o sistema!
  4. A grande sacada do TDD é justamente ter um sistema com uma arquitetura coerente! Os testes de tão feedback rápido, indicando problemas na arquitetura do modelo ou na arquitetura geral do sistema.

O pessoal, se você quer saber oq é TDD tem que ler o livro do Kent Beckman - Que uma referência no assunto.