Como combinar TDD e DDD estritos?

15

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)?

Mik378
fonte
3
Relacionado: O TDD leva ao bom design?
Doc Brown

Respostas:

11

Leia os comentários recentes do tio Bob sobre o papel do design no TDD .

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.

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 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. "

VoiceOfUnreason
fonte
11

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:

insira a descrição da imagem aqui

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- Presenterno 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. Uma PresenterMockaula seria uma boa maneira de verificar se está obtendo o que você esperava. Distribua o Use Case Interactordo PresenterMocke conduzir o Use Case Interactorcomo se você fosse o Controllere você tem uma boa maneira de testar a unidade o Use Case Interactordesde 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.

candied_orange
fonte
Eu nunca disse que TDD é um design, mas é sobre design.
Mik378
1
Tio Bob estava lhe dizendo para projetar. Ele não estava lhe dizendo "ei, se você faz testes, quem se importa com o resto".
Candied_orange 29/05
1
Como eu já disse, basta seguir as regras de com quem você pode conversar. A arquitetura limpa não é algo para se discutir o BDUF. Apenas identifique em que parte você está e pense sobre quem e como deve se comunicar. É mais ágil do que você imagina. Depois disso, pergunte se é testável pelo TDD. Se não for, você fez algo errado. Se é que espero que você esteja prestando atenção, porque um bom design é mais do que testável.
Candied_orange 29/05
6
Ugh ... Eu realmente não suporto o nome impróprio "Design Orientado a Testes". Você ainda precisa projetar um pouco antes de começar a bater alegremente no teclado, independentemente de escrever ou não testes.
RubberDuck
1
Para citar o tio Bob neste ponto exato, "Você precisa projetar o período" . Clique lá e se você estiver impaciente demais para ler a coisa toda, procure essas palavras. Martin descobrirá que o TDD não é uma bala mágica e que você deve projetar não apenas seu código, mas também seus testes, se não quiser viver em uma base de código muito frágil.
Candied_orange 30/05
4

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.

Matt Oaxaca
fonte
1
Eu discordo, TDD não é sobre testes, é sobre design.
11376 Mik378
Estou baseando tudo nas três regras do TDD, conforme descrito pelo tio Bob.
Matt Oaxaca
Steve Freeman, autor do livro GOOS, declarou: você não deve especificar nenhuma camada ou infraestrutura antes de iniciar os ciclos de TDD.
11376 Mik378
Não conheço esse livro, mas teria que discordar. Não quero que o TDD modele meu gráfico de DI e de classe.
Matt Oaxaca
3
@ Mik378: TDD não é sobre testes, mas também não é principalmente sobre design - o único design induzido pelo TDD é o design para teste de unidade. Todas as outras partes do design devem vir de outro lugar. Eu vejo o TDD mais como uma técnica de implementação.
Doc Brown
3

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

JonyLoscal
fonte
1
bem ao software mim e código é a mesma coisa
Konrad
1
Poderia ser o mesmo também. Tentei dizer: software como "solução", "sistema", "alto nível" e código como "implementação", "baixo nível", "detalhes".
JonyLoscal
Eu acho que o importante é que "primeiro testemos, mas precisamos de um esqueleto mínimo onde começaríamos a testar". Você?
JonyLoscal
1

Devo deixar estritamente o design emergir dos testes

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)

Ou devo criar essas camadas vazias (aplicativo, entidades / serviços de domínio, infraestrutura) e deixar o TDD caber em cada uma delas independentemente

(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)

Cola
fonte
+1 para o livro FP DDD e explicação geral.
Roman Susi