TDD é sobre como projetar código, guiado por testes.
Assim, camadas típicas geralmente não são construídas antecipadamente; eles devem aparecer um pouco através das etapas de refatoração.
O design orientado a domínio envolve muitos padrões técnicos, definindo camadas bem estabelecidas, como Camada de aplicativos, Camada de infraestrutura, Camada de domínio, Camada de persistência.
Para iniciar a parte de codificação de um projeto DDD do zero, como se comportar?
Devo deixar estritamente o design emergir dos testes, o que significa que não há separação de preocupações (sem camadas) e refatoração para atender aos padrões técnicos do DDD?
Ou devo criar essas camadas vazias (aplicativo, entidades / serviços de domínio, infraestrutura) e permitir que o TDD se encaixe em cada uma delas independentemente (usando zombarias para isolar as camadas)?
Respostas:
Leia os comentários recentes do tio Bob sobre o papel do design no TDD .
Udi Dahan: "Deus, como eu odeio camadas." Ele passa algum tempo discutindo isso em sua palestra CQRS - mas Diferente (as camadas começam às 18h30)
Eu escreveria sua sentença um pouco diferente; "O DDD reconhece que há uma série de preocupações comuns à maioria dos aplicativos de negócios e que as soluções para essas preocupações têm vida útil diferente" .
Por exemplo, as preocupações com o domínio, em regra, precisam ser flexíveis - especialmente quando você está personalizando uma solução para um negócio específico. Afinal, o domínio diz respeito à forma como a empresa faz negócios, ou seja, como a empresa ganha dinheiro e ser capaz de oferecer melhorias nos negócios rapidamente é uma receita gratuita.
Por outro lado, você provavelmente não precisa alterar o componente de persistência com frequência. A solução de banco de dados que funcionou na última versão provavelmente também funcionará nesta versão.
As preocupações de aplicação estão em algum lugar no meio; eles tendem a ser estáveis para que os usuários não precisem aprender um novo aplicativo a cada lançamento.
Além disso, pode haver várias implementações para resolver qualquer preocupação. Por exemplo, o aplicativo pode precisar apenas de um instantâneo de seu estado atual - basta salvar um arquivo no disco. E nas suas primeiras iterações, também pode ser tudo o que o domínio precisa. Mas, finalmente, chega uma história que exige suporte a consultas ad-hoc, e você reconhece que configurar um banco de dados relacional será muito mais fácil do que implementá-lo do zero. E há esse recurso que funcionaria melhor em um banco de dados de gráficos.
Enquanto isso, o CTO quer uma versão do aplicativo que seja executada em seu telefone; o CEO acabou de ouvir de um cara que publicar uma API é algo importante.
Além disso, a equipe de vendas usa um modelo diferente, portanto, forneça o mesmo aplicativo, com um modelo diferente. Ah, mas estamos viajando muito, por isso nossa versão precisa funcionar quando estiver offline e sincronizar mais tarde ...
Em outras palavras, você aplica os padrões táticos do ddd não implementando espaços reservados vazios e assumindo que eles serão preenchidos posteriormente, mas reconhecendo quando você está cruzando os fluxos "Ei, esse é o código de persistência no meu modelo de domínio, não devo ser refatoração ainda. "
fonte
O Test Driven Development (TDD) não é um design. É um requisito que afeta seu design. Assim como se você precisasse ser seguro para threads, isso não é um design. Novamente, é um requisito que afeta seu design.
Se você ignorar alegremente todas as outras preocupações de design e respeitar religiosamente as regras do TDD, não culpe o TDD quando o seu código se tornar um lixo. Será uma porcaria testável, mas será uma porcaria.
Uma coisa boa sobre porcaria testável é que é porcaria refatorável, então para algumas pessoas isso é bom o suficiente. Ficaremos chiques apenas quando necessário. Outros odeiam isso e culpam o TDD por isso. Não. Isso é seu.
O DDD (Domain Driven Design) é algo que você faz antes do ciclo de refatoramento verde vermelho do TDD.
DDD é o esforço para criar e preservar um espaço no código em que um especialista em domínio, que é amplamente alheio aos detalhes do sistema, pode entender como controlar o sistema. Isso é feito abstrando e modelando um domínio do problema de uma maneira familiar.
Um sistema DDD pode ter uma arquitetura parecida com esta:
Essa arquitetura DDD tem vários nomes: Limpo , Cebola , Hexagonal , etc.
Aqui está a desconexão que vejo muitas pessoas quando observam esse design. Isto não é concreto. Eu posso seguir este design e nunca escrevi nada que você veja diagramado aqui. Vejo que outros insistem em que deve haver um objeto de caso de uso ou uma classe de entidades. O que é isso é um conjunto de regras que informam com quem você pode conversar e como.
É isso aí. Siga as regras deste design e você pode TDD seu pequeno coração. TDD não se importa com quem você fala. É importante que tudo o que faz alguma coisa funcione ou não com o clique de um botão. Não, algo em algum lugar está quebrado. Diz exatamente o que está quebrado.
Ainda é vago? Veja o diagrama
Controler
-Use Case Interactor
-Presenter
no canto inferior direito. Aqui estão três coisas concretas se comunicando. Claro que isso é DDD, mas como você adiciona TDD aqui? Apenas zombe do material concreto. O apresentador deve estar recebendo informações. UmaPresenterMock
aula seria uma boa maneira de verificar se está obtendo o que você esperava. Distribua oUse Case Interactor
doPresenterMock
e conduzir oUse Case Interactor
como se você fosse oController
e você tem uma boa maneira de testar a unidade oUse Case Interactor
desde o mock vai dizer se ele tem o que você espera-se obter.Bem, olhe para isso. TDD satisfeito e não tivemos que mexer no nosso design DDD. Como isso aconteceu? Começamos com um design bem dissociado.
Se você usa o TDD para direcionar o design (não apenas o desenvolvimento ), obtém um design que reflete o esforço que você coloca nele. Se é isso que você quer bem. Mas nunca foi para isso que o TDD foi criado. O que isso acaba faltando certamente não é culpa do TDD.
TDD não é sobre design. Se você precisar fazer alterações no design para usar o TDD, terá problemas maiores que o teste.
fonte
O TDD garante que seu código tenha todos os casos de teste necessários escritos em paralelo ao desenvolvimento. Isso não deve afetar o design de alto nível. Pense mais no trabalho das trincheiras.
DDD é sobre projetos de alto nível, linguagem entre especialistas e engenheiros de domínio, mapeamento de contexto etc. Esse deve ser o driver do design de alto nível do aplicativo.
Essas são explicações superficiais de duas poderosas metodologias de programação. Mas no final do dia eles realmente realizam duas coisas muito diferentes.
Comece com o idioma DDD e o mapeamento de contexto e, eventualmente, quando você escrever o código, inicie a prática do TDD. Mas a prática do TDD não deve afetar o design de alto nível, mas deve garantir que as coisas possam ser testadas. Há um pouco de advertência aqui.
Eu acho que pode ser importante observar: você só deve praticar DDD se o aplicativo for suficientemente complexo.
fonte
DDD é sobre design de software.
TDD é sobre design de código.
No DDD, o "modelo" representa a abstração do domínio, todo o conhecimento do especialista em domínio.
Poderíamos usar o TDD para o modelo de design de software inicial de código. O domínio possui regras de negócios e modelos de domínio que o teste gravado (primeiros) deve ser verde.
Com efeito, podemos codificar os testes, depois de projetar um modelo controlado por domínio.
Este livro "Crescendo software orientado a objetos, guiado por testes" link para compra
Adote essa abordagem, com um esqueleto ambulante , arquitetura hexagonal e TDD.
Fonte de: DDD rapidamente - InfoQ
fonte
Não. (Direcionado ao domínio) O design por definição deve emergir dos requisitos do domínio. É uma má idéia deixar que qualquer outra coisa direcione seu design, seja suíte de testes, esquema de banco de dados ou ... (para continuar)
(continuação) ... ou algumas camadas canônicas de classes / hierarquias de classes em seu idioma preferido de OO, mesmo que seja muito maduro e popular (afinal "milhões de moscas não podem estar erradas", certo?) .
Quando se trata de DDD, o POO deixa de expressar os requisitos de forma legível por humanos, isto é, algo que seria mais ou menos claro para um não programador. Linguagens FP estritamente tipadas fazem um trabalho melhor. Eu recomendo ler um livro sobre DDD usando a programação funcional "Domain Modeling Made Functional", de Scott Wlaschin
https://pragprog.com/book/swdddf/domain-modeling-made-functional
Você não precisa usar a linguagem FP para emprestar algumas das idéias de lá (nem todas infelizmente), mas se você realmente a ler, provavelmente desejará usar uma linguagem funcional.
Ele também responderá sua pergunta sobre como o TDD se encaixa na imagem do DDD. Em poucas palavras, quando os requisitos são codificados em estilo funcional, elimina a necessidade de uma grande quantidade de testes de unidade, pois torna a maioria dos estados e cenários inválidos irrepresentáveis / impossíveis de compilar. Obviamente, ainda há lugar para testes automatizados no projeto FP, mas de maneira alguma os testes conduzirão as principais decisões de projeto.
Para fazer um círculo completo, vamos voltar à pergunta do título, ou seja, "Como combinar TDD e DDD estritos?". A resposta é direta: não há nada a combinar / nenhum conflito de interesses. Projete de acordo com os requisitos, desenvolva de acordo com o design (escrevendo primeiro os testes se você realmente deseja fazer TDD)
fonte