Compartilhando objetos DTO entre microsserviços

15

TL; DR - É permitido compartilhar uma biblioteca POJO entre serviços?

Geralmente, gostamos de manter o compartilhamento entre serviços estritamente limitado a nenhum, se possível. Houve um debate sobre se o serviço que está compartilhando dados deve ou não fornecer uma biblioteca de clientes para uso dos clientes. A client-lib geralmente é opcional para um cliente do serviço e pode consumir a API da forma que desejar, seja para usar a client-lib ou para usar uma linguagem alternativa e usar os aspectos gerais da biblioteca e tal.

No meu caso - sou considerado um serviço que cria um objeto de dados. Vamos supor que esse objeto seja um PET. NÃO é a entidade do banco de dados, mas estritamente um POJO que representa implicitamente os dados subjacentes. Esse POJO é o que a API definiu. Suponha: Animal de estimação - Idade, Peso, Nome, Proprietário, Endereço, Espécie, etc.

Serviço 1 - PetKeeper: Ele gera um animal de estimação por qualquer motivo e retém todos os dados e deve fazer referência a esse serviço para obtê-lo ou fazer modificações no animal de estimação, digamos que o nome seja alterado ou a alteração de endereço deve ser feita por meio de um Chamada de API para este serviço.

Serviço 2 - PetAccessor: Este serviço reúne os animais de estimação e faz verificações de validação

Serviço 3,4 - Mais chamadas de serviço intermediárias

Serviço 5 - Interface do usuário

Estes são muito arbitrários, mas o ponto é simples. A interface do usuário ou algum serviço voltado ao usuário deseja apresentar de alguma forma esse objeto "PET". Ele deve chamar por meio de uma API um serviço, que chama um serviço, que chama um serviço, etc., até atingir o serviço que reúne as informações necessárias e inicia a retransmissão. Finalmente, o serviço de interface do usuário tem o objeto PET para exibir.

Isso é bastante comum - mas com nossa mentalidade absoluta, duplicamos o objeto PET em todos os serviços. O princípio DRY (não se repita) se aplica apenas ao código DENTRO de um serviço e não se aplica a todos os serviços, mas o ponto ainda está lá. E se adicionarmos um campo ... devemos modificar 5 serviços do POJO em cada um.

--OR-- Podemos fornecer uma Pet-Objects-Library que contém alguns dos pojo da API e cada serviço pode importar / dependência da biblioteca. Não há dependência no (s) serviço (s) em si, mas apenas na biblioteca geral. Eu gosto dessa ideia para que cada serviço tenha o mesmo tipo de objeto e as atualizações sejam mais fáceis. Mas estou preocupado com os objetos de Deus.

Quais são os prós / contras - qual é o melhor design? O que você fez para passar dados entre serviços para minimizar a repetição das mesmas classes POJO e ao mesmo tempo permanecer desacoplado?

Aerith
fonte
@DaiKaixian: Certamente você não está sugerindo que o OP vá com um objeto de Deus, está? Isso é rotineiramente considerado um antipadrão.
28616 Makoto
Concordo com a resposta de @javaguy.
E também quero dizer que você pode considerar o padrão de visitantes. en.wikipedia.org/wiki/Visitor_pattern . Crie todo o campo e setter / getter em um POJO e compartilhe-o entre microsserviços. Se você deseja executar alguma operação no POJO em diferentes microsserviços, escreva alguns VisitorClass.
Obrigado. Minha hesitação em ter essa "biblioteca comum" é que ela crescerá. E haverá objetos lá nos quais apenas os serviços 1 e 3 se importam, ou 2 e 4, ou todos, ou qualquer combinação deles. Um tipo de pacote geral de biblioteca de DTO que possui todos os DTO, independentemente de eu usar um padrão vistor ou um simples DJ POJO ou o que não. É aceitável incluir todos esses objetos, mas tentar mantê-los da melhor maneira possível? Pelo menos os objetos são fornecidos a qualquer que deles necessitam se quiserem usá-los ...

Respostas:

5

Qual é o melhor design?

Você pode reutilizar o mesmo objeto Pet DTO entre os serviços de back-end (que processam a lógica comercial típica), mas quando se trata da camada de apresentação (interface do usuário), geralmente é uma boa prática usar um FormBean (um bean diferente com campos adicionados) para lógica de apresentação), para que haja uma separação clara entre lógica de apresentação e lógica de negócios .

Isso é necessário porque os serviços devem ser reutilizáveis ​​e um único serviço pode ser exposto / reutilizado por vários pontos de extremidade diferentes (como o frontend ou um serviço da web diferente etc.) e cada um desses pontos de extremidade pode exigir campos adicionais que serão preenchidos por os respectivos controladores ou camadas (como adaptadores) acima dos serviços.

O que você fez para passar dados entre serviços para minimizar a repetição das mesmas classes POJO enquanto também fica desacoplado?

Se você usar um único bean entre os negócios e as camadas da Web, estará acoplando firmemente a lógica de apresentação à lógica de negócios, o que não é uma boa prática e você acabará alterando os serviços para um requisito no Frontend (como, por exemplo, um formato de data diferente mostrado na interface do usuário). Além disso, para fazer esse processo de preencher / copiar os dados através dos beans (como DTO para FormBean ou Viceversa), você pode usar bibliotecas como Apache BeanUtils.copyProperties() ou Dozer para evitar o código padrão .

desenvolvedor
fonte
Concordo que a camada de apresentação provavelmente deve desserializar a carga útil recebida como um bean de apresentação com atributos diferentes, conforme necessário. Mas, em geral, não há problema em reutilizar o mesmo objeto (s) DTO em todos os serviços de back-end? Geralmente, tentamos separar esses pacotes de DTO em pacotes menores, apenas para os poucos serviços que precisam deles. Estou cansado de ter uma gaveta de lixo eletrônico de um pacote de biblioteca de DTOs que possui DTOs para mais de 75 microsserviços dos quais todos os serviços dependem. A menos que esteja tudo bem, já que são apenas objetos DTO que são opcionais em primeiro lugar?
Sim, obviamente você pode reutilizar o mesmo objeto DTO em todos os mesmos tipos de serviços de back-end como o seu PetServicespara evitar duplicação. Mas o que quero dizer é que não é preciso unir back-end e front-end, é isso.
desenvolvedor
4

Se o DTO representa a mesma entidade comercial em todos os microsserviços, deve haver apenas uma classe, compartilhada entre os serviços. Nunca é correto ter código duplicado para o mesmo objeto.

Jim Garrison
fonte
3
Compartilhar DTOs entre microsserviços é um pesadelo. "Esta versão já tem esse campo? Hum, talvez?" Você vai acabar com uma verdadeira bagunça depois de um tempo. Código duplicado é bom neste caso.
Mejmo 25/10/19
1

A maneira como pretendo fazer isso agora é que cada serviço empacota apenas DTOs e os coloca no Nexus como jar lib. Quando outro serviço precisar, ele obterá essas bibliotecas do DTO como dependência no manve / gradle. Se a nova versão do DTO for lançada em um serviço, tudo bem, desde que a versão antiga também seja suportada ao mesmo tempo; portanto, não interrompa a compatibilidade com versões anteriores, o controle de versão, etc. Também para evitar a dependência circural, é melhor separar o serviço do empacotamento dto

Agora olhe de back-end para front-end e vice-versa . Discordo dos comentários anteriores de que a interface do usuário como camada de apresentação é diferente. NÃO É!!! A interface do usuário é apenas mais um microsserviço para mim que também consome e produz eventos.

Direção de back-end para front-end O que faço é converter POJO (dtos) em interfaces Typescript e empacotar no NPM e carregá-las no Nexus também. O projeto baseado em nodejs da interface do usuário consome e os utiliza. Este é o serviço de maneira para a interface do usuário.

Direção de front-end para back-end Para a interface do usuário para eventos da camada de serviço, converto interfaces de Typecript e as converto em POJOs (dtos), empacote como jar e faça upload para o Nexus (ou algum repo) em forma de jar para ser consumido pelos serviços de back-end.

Esses processos são facilmente manipulados pelos processos de IC (Travis, Gitlab CI, etc.)

Quaisquer comentários a essa abordagem são bem-vindos.

kensai
fonte