Condivisione di oggetti DTO tra microservizi


15

TL; DR - Va bene condividere una libreria POJO tra servizi?

In generale, ci piace mantenere la condivisione tra servizi strettamente limitata a nessuno, se possibile. Si è discusso se il servizio che condivide o meno i dati debba fornire una libreria client da utilizzare per i client. Il client-lib è generalmente facoltativo da usare per un client del servizio e può consumare l'API comunque per favore, se usare il client-lib o usare un linguaggio alternativo e usare gli aspetti generali della libreria e simili.

Nel mio caso, sono considerato un servizio che crea un oggetto di dati. Supponiamo che questo oggetto sia un PET. NON è l'entità del database, ma rigorosamente un POJO che rappresenta implicitamente i dati sottostanti. Questo POJO è ciò che l'API ha definito. Assumi: Animale domestico - Età, Peso, Nome, Proprietario, Indirizzo, Specie, ecc.

Servizio 1 - PetKeeper: genererà un animale domestico per qualsiasi motivo e manterrà tutti i dati e dovrà fare riferimento a questo servizio per ottenere l'animale domestico o apportare modifiche all'animale domestico, diciamo che il cambio di nome o l'indirizzo deve essere effettuato tramite un Chiamata API a questo servizio.

Servizio 2 - PetAccessor: questo servizio raccoglie l'animale e fa controlli di convalida

Servizio 3,4 - Altre chiamate di servizio intermedie

Servizio 5 - Interfaccia utente

Questi sono molto arbitrari ma il punto è semplice. L'interfaccia utente o alcuni servizi rivolti all'utente desiderano presentare in qualche modo questo oggetto "PET". Deve chiamare tramite un'API un servizio, che chiama un servizio, che chiama un servizio, ecc. Fino a quando non raggiunge il servizio che raccoglie le informazioni richieste e riavvia il relè. Infine, il servizio UI ha l'oggetto PET da visualizzare.

Questo è abbastanza comune - ma con la nostra mentalità assoluta, abbiamo duplicato l'oggetto PET in ogni servizio. Il principio DRY (non ripetere te stesso) si applica solo al codice INSIDE di un servizio e non si applica a tutti i servizi ma il punto è ancora lì. E se aggiungessimo un campo ... dobbiamo modificare 5 servizi del POJO in ciascuno.

--OPPURE-- Siamo in grado di fornire una libreria Pet-Objects che contiene alcuni pojo dall'API e ogni servizio può importare / dipendere dalla libreria. Non vi è alcuna dipendenza dai servizi stessi, ma solo dalla biblioteca generale. Mi piace questa idea in modo che ogni servizio abbia lo stesso tipo di oggetto e gli aggiornamenti siano più facili. Ma sono preoccupato per God-Objects.

Quali sono i pro / contro - qual è il miglior design? Che cosa hai fatto per trasferire i dati tra servizi per ridurre al minimo la ripetizione delle stesse classi POJO rimanendo allo stesso tempo disaccoppiato?



@DaiKaixian: Sicuramente non stai suggerendo che l'OP vada con un oggetto God, vero? Questo è abitualmente considerato un anti-pattern.
Makoto,

Sono d'accordo con la risposta di @javaguy.

E voglio anche dire che puoi considerare il modello di visitatore. en.wikipedia.org/wiki/Visitor_pattern . Crea tutto il campo e setter / getter in un POJO e condividilo tra microservizi. Se desideri eseguire un'operazione sul POJO in un microservizio diverso, scrivi un VisitorClass.

Grazie. La mia esitazione con questa "biblioteca comune" è che crescerà. E ci saranno oggetti che interessano solo i servizi 1 e 3, o 2 e 4, o tutti, o qualsiasi combinazione di essi. Un tipo di pacchetto di libreria DTO generale che ha tutti i DTO, sia che io usi un modello di vistor o un semplice POJO DTO o no. È accettabile includere tutti questi oggetti ma cercare di mantenerlo nel miglior modo possibile? Almeno gli oggetti vengono forniti a chiunque ne abbia bisogno SE desiderano usarli ...

Risposte:


5

Qual è il miglior design?

È possibile riutilizzare lo stesso oggetto Pet DTO tra i servizi di backend (che elaborano la tipica logica aziendale), ma quando si tratta del livello di presentazione (interfaccia utente), è generalmente buona norma utilizzare un FormBean (un bean diverso con campi aggiunti per la logica di presentazione) in modo che ci sia una chiara separazione tra la logica di presentazione e la logica di business .

Ciò è necessario perché i servizi dovrebbero essere riutilizzabili e un singolo servizio può essere esposto / riutilizzato da più / diversi endpoint (come frontend o potrebbe essere un servizio web diverso, ecc.) E ciascuno di questi endpoint potrebbe richiedere campi aggiuntivi che verranno popolati da i rispettivi controller o livelli (come gli adattatori) sopra i servizi.

Che cosa hai fatto per trasferire i dati tra i servizi per ridurre al minimo la ripetizione delle stesse classi POJO rimanendo allo stesso tempo disaccoppiato?

Se si utilizza un singolo bean tra business e livelli Web, si sta accoppiando strettamente la logica di presentazione con la logica di business che non è una buona pratica e si finirà per modificare i servizi per un requisito nel frontend (come ad esempio un diverso formato di data da mostrare nell'interfaccia utente). Inoltre, per eseguire questo processo di popolamento / copia dei dati tra i bean (come DTO in FormBean o Viceversa), è possibile utilizzare librerie come Apache BeanUtils.copyProperties() o Dozer per evitare il codice del boilerplate .


Concordo sul fatto che il livello di presentazione dovrebbe probabilmente deserializzare il payload in entrata come bean di presentazione con attributi diversi, se necessario. Ma in generale va bene riutilizzare gli stessi oggetti DTO in tutti i servizi di backend? Generalmente proveremmo a separare questi pacchetti DTO in pacchetti più piccoli solo per i pochi servizi che ne hanno bisogno. Sono stanco di avere un po 'di cianfrusaglie di un pacchetto di librerie DTO che ha DTO per oltre 75 microservizi da cui dipendono tutti i servizi. A meno che non vada bene dato che sono solo gli oggetti DTO che sono opzionali in primo luogo?

Sì, puoi ovviamente riutilizzare lo stesso oggetto DTO su tutti gli stessi tipi di servizi di back-end come il tuo PetServicesper evitare duplicazioni. Ma il mio punto non è strettamente accoppiare backend e frontend, tutto qui.
sviluppatore

4

Se il DTO rappresenta la stessa entità commerciale in tutti i microservizi, dovrebbe esserci solo una classe, condivisa tra i servizi. Non è (quasi) mai corretto avere un codice duplicato per lo stesso oggetto.


3
La condivisione di DTO tra microservizi è un incubo. "Questa versione ha già questo campo? Forse?" Dopo un po 'finirai con un vero casino. Il codice duplicato è buono in questo caso.
Mejmo,

1

Il modo in cui ho intenzione di farlo ora è che ogni servizio impacchetta solo DTO e li inserisce in Nexus come jar lib. Quando altri servizi ne hanno bisogno, otterrà le librerie DTO come dipendenza in manve / gradle. Se la nuova versione di DTO viene rilasciata su un servizio, va bene anche se è supportata contemporaneamente anche la versione precedente, quindi non interrompere la retrocompatibilità, il controllo delle versioni, ecc., Quindi questa è l'area back-end-back-end. Inoltre, per prevenire la dipendenza circolare è meglio separare il servizio dall'imballaggio

Ora guarda backend-to-frontend e viceversa non sono d'accordo con i commenti precedenti che l'interfaccia utente come livello di presentazione è diversa. NON È!!! L'interfaccia utente è solo un altro microservizio per me che consuma e produce anche eventi.

Direzione da backend a frontend Quello che faccio è convertire POJO (dtos) in interfacce Typescript e pacchetto in NPM e caricarli anche in Nexus. Il progetto basato su nodejs dell'interfaccia utente quindi li consuma e li utilizza. Questo è il modo di servizio all'interfaccia utente.

Direzione da front-end a back-end Per l'interfaccia utente per servire gli eventi del livello, converto le interfacce Typescript e le converto in POJO (dtos), pacchetto come jar e caricamento su Nexus (o alcuni repository) sotto forma di jar per essere utilizzato dai servizi di backend.

Questi processi sono gestiti facilmente dai processi CI (Travis, Gitlab CI, ecc.)

Tutti i commenti a questo approccio sono stati ben accolti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.