[quote=rogelgarcia]Pois então x@andy… se você afirma que para usar TDD você tem que usar DDD também… você já não está usando somente um TDD concorda? Isso porque ele não deve ser adequado a qualquer situação. De acordo com o que coletei uma dessas situações é a etapa de decisões arquiteturais. Será que essa etapa de decisões arquiteturais você está usando DDD???
[/quote]
Mas quem foi que disse que voce não pode usar mais nada se usar TDD? E, por favor, pare de usar o termo arquitetura porque voce o esta visivelmente usando fora de contexto, e misturando as definicoes.
Não, não está no livro. Voce não está entendendo nada do que está lendo. " We must design organically, with running code providing feedback between decisions" não significa “Em TDD as decisões são feitas baseadas em código já implementado”, significa que código sendo executado provém feedback para decisoes tomadas, o que é bem diferente de tomar decisoes em cima de código implementado.
Mas ninguem disse que voce não pode pensar no que fazer, voce pode e deve. O que voce não deve é hoje implementar uma funcionalidade que voce não precisa hoje. É só isso.
Não, ele não disse isso, ele disse que não é possivel prever o todo e tentar é perda de tempo. Voce parte de uma ideia do todo e experimenta. E mais uma vez, este não eh um coneito de TDD, é um conceito Lean. Voce está rosnando para a ferramenta errada.
Olha o BDUF ai de novo, quanto mais detalhes no meu planejamento, menos problemas terei no futuro. Doce ilusao.
Pode, mesmo sem seguir TDD, mas nao pode usar a desculpa de que ele atrapalha na construcao do modelo de objetos.
[quote=rogelgarcia]“Architecture” is a term that lots of people try to define, with little agreement. There are two common
elements: One is the highest-level breakdown of a system into its parts; the other, decisions that are hard to
change. [FOWLER, Patterns of Enterprise Application Architecture]
Ralph Johnson: A shared understanding of a system’s design by the expert developers on a
project. Commonly this shared understanding is in the form of the major components of the system and how
they interact. It’s also about decisions, in that it’s the decisions that developers wish they could get right early
on because they’re perceived as hard to change. In the end
architecture boils down to the important stuff�whatever that is. [FOWLER, Patterns of Enterprise Application Architecture]
Decisões na arquitetura são difíceis de ser alteradas. Quanto mais cedo decisões arquiteturais forem tomadas melhor.
Não sou eu que estou dizendo: É Fowler e Johnson.[/quote]
Aqui você está se referindo a arquitetura no sentido que usamos mais tradicionalmente, quer dizer, as decisões técnicas de mais alto nível, aquelas que não podem ser alteradas (linguagem, frameworks, banco de dados, servidor de aplicação, infraestrutura, etc). Então como o TDD se relaciona com isso?
É muito mais simples do que parece, você está colocando no TDD uma culpa que ele não tem, que é tentar interferir na arquitetura.
Programar em TDD não quer dizer que essas decisões não possam ter sido tomadas de antemão. Pelo contrário, você está sempre subordinado à arquitetura que foi definida para o sistema!
Vou tentar dar um exemplo:
A arquitetura do projeto define que as operações de negócio estarão em um EJB. Você chega para desenvolver uma nova funcionalidade, e o que vai fazer?
Começa programando a partir da interface/implementação do EJB, aplicando testes e desenvolvendo sobre a implementação do serviço (regras de negócio).
A arquitetura prevê a utilização de DAO? Tudo bem, você cria a interface do DAO, injeta um mock no seu teste e continua a trabalhar nas regras de negócio (ainda na classe do EJB).
Enquanto implementa você acha melhor mover determinada operação para uma classe de negócio auxiliar, um POJO, e aí começa a desenvolver essa classe criando testes para ela. Nesses testes trabalha os cenários que forem apropriados e implementa o código correspondente. Depois injeta essa classe de negócio no EJB para que ambos passem a funcionar juntos…
E assim por diante.
Veja que no final você tem uma funcionalidade toda desenvolvida através do TDD mas respeitando as regras da arquitetura do sistema, que mandam usar Framework Web X -> EJB -> DAO
Se quiser desenvolver outros componentes usando TDD vale o mesmo princípio (se bem que ainda é questionável se ele se aplica bem a elementos que contenham GUI ou IO)
Bom, é isso aí… não sou um expert em TDD (aliás nesse mesmo tópico manifestei algumas dúvidas básicas…), mas espero que esse tenha sido um exemplo claro para demonstrar que ele não interfere na arquitetura.
Organização das classes e suas relações e responsabilidades num sistema.
Está bem definido?[/quote]
Arquitetura define-se assim : aquilo que não está no código.
Se vc pode inferir lendo o código, não é arqutetura, é design. Isso que vc falou é design.
Arqutetura estaria na razão para o fato de vc ter classes e OO em vez de programação funcional, por exemplo.
Do codigo vc pode saber que usa classes, mas nunca vai saber porquê.
[quote=YvGa][quote=sergiotaborda]
Pensando de outa forma, no modelo padrão vc quer colocar um pattern X vc vai e coloca. Em TDD vc não faz isso. Vc escreve um código qualquer e depois quando for refactorar é que vc identifica o padrão e o usa. O TDD é reactivo e não pro-activo. E isso pode ser bom quando vc quer ser minimalista como o Beck gosta de ser, mas implica em muitos passos desncessários. Ai ele fala que a pessoa pode pular para o passo que deseja ( no caso, pode colocar o padrão logo de inicio). Mas isso para mim não é desenvolvimento assistido, é simplesmente ter uma ideia e colocar um teste à volta dela (Test First).[/quote]
Certo, Sergio, entendo seu ponto de vista, mas deixa eu fazer uma defesa ao Beck, ou uma acusação, já que o livro dele não deixa isso claro. Mas foi a maneira que eu sempre entendi, lendo principalmente ele e os outros dois autores que eu citei no meu post anterior.
Não existe um jeito certo de começar a implementação, você pode começar por onde quiser, outside-in ou inside-out (o que pra mim parece o mesmo que top-down ou bottom up), você pode desenhar primeiro a interface de uma calculadora, pode implementar as teclas com infra-estrutura fake e ir aos poucos descendo para as operacoes matematicas. Ou então você pode fazer inside-out, começar pelas operações e vir para as teclas e a interface depois.
Mas o que você não pode, nem vai conseguir, de jeito nenhum, e é o que parece muita gente ter entendido da proposta do TDD é planejar inside-out. Não se pode planejar inside-out, não é possível imaginar uma calculadora começando simplesmente pelas operações matemáticas, sem pensar em como um ser humano irá interagir com ela
[/quote]
Aqui que vc se engana. A definição do dominio não depende da interação. Uma calculadora não é o que vc vê na tela, são as regras colocadas no codigo. Vc pode usar essas mesmas regras e colocar num servidor com um webservice na frente. Não ha necessidade de interação com o ser humano para definir o dominio. Isto é DDD. O Dominio é o ponto de partida porque é ele que atente dos requisitos que os usuários pedem. O resto é decoração e UX. Mas se o dominio não está bem modelado, não ha UX que salve.
Eu sim posso somar dois numeros sem saber se são float ou double ou int. Vc cria uma abstração. Vc pode criar uma classe com operação de soma e subtração que produzem objetos da mesma classe, e nunca, por baixo dos panos realmente fazer nenhuma conta. Mas vc abstraio o conceito de “operação” e é isso que é seu dominio.
Em nenhum momento eu falei de planejamento. Eu falei de design. Design não é planejamento, ele já é o produto final. Planejar o design é algo impossivel. Ou vc realiza o design ou não realiza. Vc pode realizar e se arrepender, mas não pode evitá-lo.
Frases como “Daqui a um mes implementamos o serviço de conversão” já implica que o design foi feito e existe um tal de “serviço de conversão”.
TDD realmente não tem que ver com planejamento, pois não é uma disciplina de gerencia.
[quote=YvGa][quote=rogelgarcia]
Linhas de montagens de carros são completamente diferentes de software. Você buscou um argumento de outro cenário para aplicar em software tentando rebater minha argumentação. Numa linha de montagem de carros, todos os carros são iguais. Decisões foram tomadas no projeto do carro e não na montagem. Just In Time é uma conceito relacionado a produção. Onde você entrega os produtos quando eles forem necessários. Exemplo: na produção do carro a chapa de aço será entrega quase no momento em que o carro iniciar na linha de montagem.
[/quote]
Lean nao e usado so em linha de montagem, é usado hoje em todas as areas, inclusive no desenvolvimento de produtos, onde usa conceitos parecidos.
Eu nao disse que TDD nao usa em refactoring, eu disse que o refactoring estará la, use você TDD ou nao. Voce acusa TDD de ser ruim por usar muito refactoring, mas desenvolvimento de software PRECISA de muito refactoring.
[/quote]
Não. Muito refactoring é sinônimo de más decisões e falta de robustez da solução. Muito refactoring é sinônimo de tentativa e erro. Quando vc coloca “refactoring” num loop vc está criando um mecanismo tentativa-e-erro (try-and-miss)
É como vc tentar decorar uma casa por tentativa e erro. Vc consegue, mas é muito mais fácil chamar um especialista que faz a decoração de primeira.
Mas estão esquecendo o básico, que o próprio autor defende. TDD é para quando vc não conhece a solução. Vc quer experimentar. E isso é comum quando está na camada de domínio. Por exemplo, todo o mundo sabe camadas e serviços e RMI e tal, mas como se modela um sistema que simula um cricuito integrado ? Como se simula um sistema que simula um coração ? Como se simula um sistema de controle de transito ? São estes problemas específicos que o TDD vai ajudar a resolver e não problemas do tipo “uso singleton ou registry?”, “uso dao ou domainsotre” não é nada disto que é o foco do TDD. E nestes cenários é aceitável tentativa e erro. Mas dizer que TDD é uma forma de desenvolver todo o sistema é absurdo. Ele só serve para desenvolver uma parte.
De facto o refactoring é uma ferramenta do programador e se começou a passar essa ideia que é bom e certo fazer refactoring. De fato é. Mas quando ele se repete muitas vezes torna-se um vicio da mente do tipo “não preciso pensar agora porque posso refactorar depois”. Se isso fosse real não precisaríamos de patterns, nem de centena de livros nos dizendo quais são as melhores práticas. Seria o equivalente a usar concatenação de string em vez de stringbuilder porque “não preciso fazer issso agora, posso fazer refactoring depois” e as pessoas ainda acrescentam “quando isso for um problema”. Mau código é um problema, assim que ele existe.
Portanto, um refacroring é pouco, dois é bom, três é de mais. Muito refactoring é sinal de mau desenvolvimento. Torna as equipes lentas e não produtivas. Repare que não estou falando de refactoring necessário devido a novos requisitos. Estou falando de mau codigo escrito sob a ideia que pode ser mudado depois.
O TDD usa muito refactoring, ou pelo menos ele aceita que isso exista. Contudo ele não aceita mau código (clean code foi mencionando ai). O que ele aceita é que devido a mudança nos requisitos , seja necessário mudar. E os requisitos , são aqui, os testes.
Mas ele também define que o painel de testes é conhecido à priori, logo, deve ser obvio, que antes do primeiro teste ser escrito eu já sei que o ultimo existe. E porque escolher uma design no primeiro teste que não encaixa no segundo ? simples burrice. Vc já ordena a implementação dos testes para implementar um depois do outro e implementar primeiro aquele que parece ser prominente na definição da estrutura. Isso é planejamento, e acontece antes do TDD.
O TDD não substitui a modelagem, no máximo ele a complementa. Contudo usando Test First e os passos normais de desenvolvimento chegamos no mesmo lugar. O TDD é apenas uma de se referir e vender a ideia de um ciclo de escrita de código baseado em testes. Só isso. Não é a oitava maravilha.
[quote=sergiotaborda][quote=YvGa][quote=sergiotaborda]
Pensando de outa forma, no modelo padrão vc quer colocar um pattern X vc vai e coloca. Em TDD vc não faz isso. Vc escreve um código qualquer e depois quando for refactorar é que vc identifica o padrão e o usa. O TDD é reactivo e não pro-activo. E isso pode ser bom quando vc quer ser minimalista como o Beck gosta de ser, mas implica em muitos passos desncessários. Ai ele fala que a pessoa pode pular para o passo que deseja ( no caso, pode colocar o padrão logo de inicio). Mas isso para mim não é desenvolvimento assistido, é simplesmente ter uma ideia e colocar um teste à volta dela (Test First).[/quote]
Certo, Sergio, entendo seu ponto de vista, mas deixa eu fazer uma defesa ao Beck, ou uma acusação, já que o livro dele não deixa isso claro. Mas foi a maneira que eu sempre entendi, lendo principalmente ele e os outros dois autores que eu citei no meu post anterior.
Não existe um jeito certo de começar a implementação, você pode começar por onde quiser, outside-in ou inside-out (o que pra mim parece o mesmo que top-down ou bottom up), você pode desenhar primeiro a interface de uma calculadora, pode implementar as teclas com infra-estrutura fake e ir aos poucos descendo para as operacoes matematicas. Ou então você pode fazer inside-out, começar pelas operações e vir para as teclas e a interface depois.
Mas o que você não pode, nem vai conseguir, de jeito nenhum, e é o que parece muita gente ter entendido da proposta do TDD é planejar inside-out. Não se pode planejar inside-out, não é possível imaginar uma calculadora começando simplesmente pelas operações matemáticas, sem pensar em como um ser humano irá interagir com ela
[/quote]
Aqui que vc se engana. A definição do dominio não depende da interação. Uma calculadora não é o que vc vê na tela, são as regras colocadas no codigo. Vc pode usar essas mesmas regras e colocar num servidor com um webservice na frente. Não ha necessidade de interação com o ser humano para definir o dominio. Isto é DDD. O Dominio é o ponto de partida porque é ele que atente dos requisitos que os usuários pedem. O resto é decoração e UX. Mas se o dominio não está bem modelado, não ha UX que salve.
Eu sim posso somar dois numeros sem saber se são float ou double ou int. Vc cria uma abstração. Vc pode criar uma classe com operação de soma e subtração que produzem objetos da mesma classe, e nunca, por baixo dos panos realmente fazer nenhuma conta. Mas vc abstraio o conceito de “operação” e é isso que é seu dominio.
Em nenhum momento eu falei de planejamento. Eu falei de design. Design não é planejamento, ele já é o produto final. Planejar o design é algo impossivel. Ou vc realiza o design ou não realiza. Vc pode realizar e se arrepender, mas não pode evitá-lo.
Frases como “Daqui a um mes implementamos o serviço de conversão” já implica que o design foi feito e existe um tal de “serviço de conversão”.
TDD realmente não tem que ver com planejamento, pois não é uma disciplina de gerencia.
[/quote]
Acho que estamos falando a mesma coisa de jeitos diferentes. Ok, vc acha que é possivel ter a funcionalidade de soma da calculadora, sem a interface humana e etc, etc, etc. Mas o ponto em que eu queria chegar é que voce não consegue planejar inside-out ou outside-in, voce necessariamente precisa da visão do todo antes de implementar. Mas visao nao eh ter o todo detalhado, minuciosamente descrito, visão do todo é simplesmente a visão, existem N possibilidades da implementação dessa visão e o TDD vai te ajudar a caminhar por elas.
Só quanto ao “voce não pode planejar o design” que talvez eu não concorde, ou talvez não tenha entendido. Essa visão do todo é um planejamento do design. Eu digo para um companheiro: “que tal se fizermos com que o pedido possua uma lista de itens e interaja com os produtos da seguinte maneira:…” Isto é planejamento de design. Depois eu vou implementar isso e ver se está de acordo.
De resto acho que estamos dizendo a mesma coisa de jeitos diferentes, sobre planejamento-implementação
Refactoring é diferente de tentativa e erro e muito refactoring é muito vago, pois não se sabe o quanto é muito. Refactoring não é indicativo de problema, refactoring é a solução de problemas de design. Tentativa e erro vem da falta de experiência, e o refactoring pode diminuir o estrago. Erro é erro e refatorar o que está errado é sinal de melhora, o erro em si é o problema. Mas isso vem, como eu ja disse, mais da capacidade do programador do que da ferramenta que ele usa.
Refactoring é sempre um bom sinal (considerando que se segue as práticas indicadas pra isso), porque indica que se há algo ruim, esta sendo melhorado. Pior que isso é o padrão corrente de tentativa-erro-tudo ok pode por em produção.
Concordo, TDD e basicamente para implementar o meu modelo de domínio, ele pode ir além, mas quanto mais longe dessas fronteiras ele estiver, menos efetivo será. Mas há quem discorde e antes de eu decretar isto como fato, gostaria de ver algo do trabalho de quem discorda
Esse tipo de ideia vem do mal entendimento da prática de “a mais simples solução para o problema”. Muita gente entende isso, como comprovamos nesse topico, muita gente mesmo, com “faça a primeira porcaria que te vier a cabeça que depois você refatora.”
Se o segundo teste está logo ali abaixo, talvez não faça sentido mesmo, faço o primeiro, pensando que haverá um outro que deverá se encaixar ali, porque eu já tenho a visão do todo. Eu tenho uma boa noção de para onde estou indo. Mas e quando o segundo está só na próxima iteração ou na outra ainda. Faz sentido eu me preocupar com ele, se eu ainda nem sei exatamente como ele vai ser? E mais ainda, ele é menos importante do qual eu estou fazendo agora. Tanto é que ficou para a próxima sprint. É certo então que ele venha atrapalhar o que eu estou fazendo agora, se na verdade, eu ainda nem sei se ele de fato existirá.
Acho que o bom senso na hora de interpretar o que está escrito num livro vale muito, pois do contrário irá se postar cada frase da obra do Kent Beck aqui, removida de contexto, ou num contexto incompreendido para tentar mostrar o quanto ele fere algo que nosso amigo achou por bem chamar de arquitetura.
[quote=sergiotaborda]
O TDD não substitui a modelagem, no máximo ele a complementa. Contudo usando Test First e os passos normais de desenvolvimento chegamos no mesmo lugar. O TDD é apenas uma de se referir e vender a ideia de um ciclo de escrita de código baseado em testes. Só isso. Não é a oitava maravilha.[/quote]
Ele não substitui, nem complementa, ele auxilia na sua construção. E se não é a oitava maravilha, ele ajuda muito, uma vez compreendido e bem utilizado.
Só quanto ao “voce não pode planejar o design” que talvez eu não concorde, ou talvez não tenha entendido. Essa visão do todo é um planejamento do design. Eu digo para um companheiro: “que tal se fizermos com que o pedido possua uma lista de itens e interaja com os produtos da seguinte maneira:…” Isto é planejamento de design. Depois eu vou implementar isso e ver se está de acordo.[/quote]
Quando vc falou essa frase, vc já fez o design. Já definiu que itens “itens” , “lista de itens” que elas está num “produto”. O design está feito. Isto é o design. O colega por falar “não usa lista, vamos usar set, porque assim assim,” ou map, sei lá. Ou ainda "não, é melhor termos um serviço que recebe um pedido e obtem os itens " (não tou dizendo que é melhor, é uma frase hipotética e comum). Isto é discutir o design. E tudo isto acontece nos vossos cérebros. Mesmo que usem uml para comunicar, ou qq outro artificio, o modelo é o que fica no cerebro de cada um. É por isso que mesmo desenhando N esquemas, o cara ainda implementa errado. Porque no cérebro dele não ficou a mesma ideia que no seu.
Então, esse tipo de interessão é desenhar, e o que resulta dai é o design. Planejamento envolve o conceito de tempo e não existe esse conceito quando vc desenha. Planejamento de design, seria, no seu exemplo, vc dizer para o colega “Cara, amanha precisamos pensar como vamos fazer o modelo do produto e itens” E mesmo assim vc já tem um design base onde existe “produtos” e “itens”.
É só tirar a palavra “planejamento” e tá tudo certo.
Se vc está usando scrum e decidiu colocar o teste mais relevante no final, bom, isso é uma escolha, mas não é a melhor escolha. E entenda que quando vc planeja o scrum vc faz isso de posse de informação sobre o todo. Todos os “majors” estão identificados. Se não estiverem, então é erro de processo. Ou seja, não é suposto, num planejamento bem feito, que seja o ultimo teste que comanda o design. Concordo com vc no seu exemplo, só não concordo que isso é exemplo do que deveria acontecer na prática. Se acontecer, a prática está errada.
Em relação ao refactoring vc falou que “refactoring é a solução de problemas de design”. O que é correto.
Mas se ha um erro no design, porquê vc o cometeu ? Esse é o ponto.
Se vc cometeu o erro porque desconhecia a sua existência, tudo bem. É chato, mas “não é culpa de ninguém”.
Se vc cometeu o erro porque descuidou de cuida da solução no momento que o criou, isso é mau desenvolvimento.
Se vc cometeu o erro porque pensou “vou fazer refactoring depois” significa “vou fazer a correção do problema de design depois” , o que singifica que vc está conscientemente incluindo débito tecnico, o que é mau desenvolvimento.
Ou seja, a necessidade de refactroing está relacionada à existência de débito técnico ou á falta de consciência de um requisito que o código atual não atende.
O único uso legítimo do refactoring é para o segundo caso. Quando um novo requisito aparece. Se o requisito já estava lá e vc se esqueceu dele, isso é simples mau desenvolvimento. Refactoring é explicitamente uma solução para trasnformar um design em outro, e a única necessidade legitima para fazer isso é quando o seu design anterior não suporta o novo requisito. Ou seja, o seu design anterior, não era robusto o suficiente.
Dai que o excesso de uso de refactoring representa excesso de “requisitos surpresa” ou “muito débito tecnico”. O primeiro pode não estar na sua mão, mas o segundo está.
Vc sabe que está fazendo muito refactoring quando toda a a funcionalidade que vc inclui necessita dele. Um sistema feito do zero ,para um conjunto N de requisitos não deve souber nenhum refactoring para esse conjunto N de requisitos. Apenas quando houver um requisit N+1 que o refactoring é licito. Se o refactoring aconteceu para os mesmos N requisitos, então é porque havia débito técnico. E isso nunca é desculpável. Utilizar refacrtoring para evoluir um sistema até cumprir os N requisitos já conhecidos não é o que se pretende, simplesmente porque é gastar tempo e dinheiro à toa. é como o exemplo que dei de decorar por tentativa. Não tente, faça.
Mas agora que vem o truque. Se vc desenha bem, vc não deseja fechado (open-close principle). Logo, o bom design é aquele que pode ser expandido a suportar coisas paras as quais não foi feito de principio. Se vc precisa refactorar a cada N+1 , então seus design são péssimos. Sua capacidade de abstração é ruim. Vc pode refactorar e eventualmente vai fazê-lo, mas aceitar que é legitimo refactorar a cada momento é simplesmente dizer que vc não precisa saber pensar com antecedência, e essa mensagem que eu acho ruim. A mensagem não é essa. Nada desculpa o programador que muda o código todos os dias. Está faltando informação para esse sujeito. Pode ser informação sobre os requisitos ( e ai pode não ser culpa dele) ou pode informação técnica de como fazer melhor (, e ai sim é culpa dele).
O TDD usa o refactoring no sentido de que são necessários ajustes porque os requisitos aumentaram, não porque a abstração OO , ou a implementação são uma porcaria.
Na prática refactorar é diferente de refazer. E refazer é que o que a maioria das pessoas faz por ai. Refactorar é lago mais simples, que uma IDE pode fazer sozinha. Refazer é jogar ideias fora, e o codigo que as traduz, e incluir outras e o codigo que as traduz. É bom não confundir as duas.