Domain-Driven: Context Mappers, DTOs e Testes

Amigos(as),

Imaginem que eu estou fazendo um ERP e tenho uns 15 domínios internos. Só para exemplificar, eu tenho base.Cliente, faturamento.NotaFiscal e vendas.Pedido (cada empacotamento seria um domínio). Problema: eu quero deixar esses domínios bem separados, pois eles serão desenvolvidos por pessoas diferentes e para tal, usarei Context Mappers como serviços que integração os domínios. Como exemplo, NotaFiscal tem Cliente, porém, só usa algumas características de Cliente (seria um faturamento.Cliente, talvez um subset de base.Cliente).

Minha dúvida:

  1. Como vocês têm feito esses Mappers? Se usam serviços é possível fugir de DTOs internos mas garantindo uma independência entre a estrutura do DB?

  2. E os testes? Qual estratégia vocês tem usado com total segurança? Nesses casos estou achando os Mockings muito frágeis, pois preciso garantir a independência entre módulos (domínios), porém, quero ter segurança que a integração contínua me mostre claramente as quebras da integração.

(tenho mais discussões, mas só essas para começar)

Oi Rodrigo,

Acompanho seu trabalho a um tempo e é bom ter a oportunidade de participar desta discussão.

  1. Sobre mappers:

Para manter a independência de banco, podemos pensar em remover a integridade referencial entre domínios e desnormalizar os dados dos mappers.

Para continuar alimentando os mappers sem precisar dos DTOs internos, podemos usar um modelo publish-subscribe disparado/alimentado na camada de services.

ex: faturamento publica que cliente tem crédito suspenso, vendas é um subscriber e alimenta seus mappers que esse cliente não pode mais comprar a crédito.

  1. sobre testes entre os domínios:

O que eu tenho feito é chamar a camada de services bem ao estilo bdd/atdd usando rollback no final (transaction rollback teardown)

O que acabou acontecendo é que os atdd/bdd (lá do fitnesse por ex) acabaram sobrepondo um pouco os units, mas não dá para abrir mão.

Ex:

testados pelo unit:

 nome_cliente_deve_conter_mais_3_caracteres
 idade_cliente_maior_de_18_anos
 cpf_cliente_deve_ser_valido
 cidade_deve_ser_capital

testados pelo bdd/atdd:

dado um cliente “joão” , 21 anos, rio de janeiro, superior incompleto, que requisita cartão de fidelidade, então recebe crédito de R$ 800
dado um cliente “pedro” , 25 anos, são paulo, superior completo, que requisita cartão de fidelidade, então recebe crédito de R$ 1.500
dado um cliente “maria” , 15 anos, rio de janeiro, ensino médio, que requisita cartão de fidelidade, então não é elegível para o programa

aqui um caso desses de integração:

dado o cliente “joão”, suspenda o crédito então recebe crédito suspenso (nesse momento o módulo de vendas vai ser “avisado”)
dado o cliente “joão” item “cd zezé de camargo e luciano” pagamento cartão de fidelidade seleciona modalidade de pagamento então “crédito suspenso”

no final o teardown limpa tudo.

Veja que acabou sobrepondo um pouco, mas se pensarmos na estratégia de integração contínua, podemos separar os jobs entre units (+ rápidos e frequentes) e atdd (noturnos por exemplo).

O que acha ?

Abraços

Essa é uma solução interessante, apesar de aumentar um pouco a complexidade, pois não estava considerando mensageria nesse problema. Eu estava pensando em deixar o banco único - uma única tabela “cliente” e deixar as coisas sincronas, apesar que cada vez mais estou vendo que isso vai ser impossível se eu quiser realmente deixar os domínios e serviços independentes.

Uma dúvida: Você está usando essa estratégia hoje em algum projeto? Seus testes de integração demoram tanto assim para rodar? (é provável que meus testes de integração entre domínios rodem direto, pois as equipes vão gerar muitas funcionalidades por dia).

Sobre os testes, como foi o primeiro projeto de CI da equipe do cliente, acabei não fazendo os 03 jobs (unit, integration e full). Acabei colocando reports de cobertura pmd e unit no integration, mas no próximo acho que pode ser uma boa deixar só para o full e rodar o integration mais frequentemente.

Sua thread foi uma boa porque eu estou prestes a começar um projeto e tenho intenções parecidas. Não sei ao certo a quantidade de contextos que terei, mas quero manter o isolamento entre os serviços e não quero fazer as amarrações ponto a ponto.

Fui ver se o Enterprise Integration Patterns me dava uma luz e no google acabei achando o Apache Camel. Vou fazer uns testes.