Best practice per la serializzazione di aggregati DDD

21

Secondo la logica del dominio DDD non dovrebbe essere inquinata da problemi tecnici come la serializzazione, la mappatura relazionale degli oggetti, ecc.

Quindi, come serializzare o mappare lo stato degli aggregati senza esporlo pubblicamente tramite getter e setter? Ho visto molti esempi per es. implementazioni di repository, ma praticamente tutte si basavano su accessor pubblici sulle entità e oggetti value per la mappatura.

Potremmo usare la reflection per evitare accessors pubblici, ma IMO questi oggetti di dominio sarebbero ancora implicitamente dipendenti dal problema della serializzazione. Per esempio. non è possibile rinominare o rimuovere un campo privato senza modificare la configurazione di serializzazione / mappatura. Quindi devi considerare la serializzazione in cui dovresti invece concentrarti sulla logica del dominio.

Quindi qual è il miglior compromesso da seguire qui? Vivi con i metodi di accesso pubblici, ma evita di usarli per nient'altro che il codice di mappatura? O mi mancava qualcosa di ovvio?

Sono esplicitamente interessato alla serializzazione dello stato degli oggetti del dominio DDD (aggregati costituiti da entità e oggetti valore). NON si tratta di serializzazione in generale o script di transcript scenari in cui i servizi stateless operano su semplici oggetti contenitore di dati.

    
posta EagleBeak 14.12.2014 - 16:56
fonte

2 risposte

11

Tipi di oggetti

Ai fini della nostra discussione, separiamo i nostri oggetti in tre diversi tipi:

Logica del dominio aziendale

Questi sono gli oggetti che funzionano. Trasferiscono denaro da un conto corrente a un altro, evadono gli ordini e tutte le altre azioni che ci aspettiamo che il software aziendale prenda.

Gli oggetti logici di dominio normalmente non richiedono accessor (getter e setter). Piuttosto, si crea l'oggetto passandogli le dipendenze tramite un costruttore e quindi si manipola l'oggetto tramite i metodi (tell, do ask ask).

Oggetti di trasferimento dati

Gli oggetti Data Transfer sono pure state; non contengono alcuna logica aziendale. Avranno sempre degli accessor. Possono o non possono avere setter, a seconda che tu li stia scrivendo o meno in modo immutabile . Imposterai i tuoi campi nel costruttore e i loro valori non cambieranno per tutta la vita dell'oggetto, o i tuoi accessori saranno letti / scritti. In pratica, questi oggetti sono in genere mutabili, in modo che un utente possa modificarli.

Visualizza oggetti modello

Visualizza Gli oggetti del modello contengono una rappresentazione di dati visualizzabile / modificabile. Possono contenere logiche di business, generalmente limitate alla convalida dei dati. Un esempio di oggetto View Model potrebbe essere InvoiceViewModel, contenente un oggetto Customer, un oggetto Header di fattura e articoli Line fattura. Gli oggetti View Model contengono sempre accessor.

Quindi l'unico tipo di oggetto che sarà "puro" nel senso che non contiene accessori di campo sarà l'oggetto Logica del Dominio. La serializzazione di tale oggetto salva il suo attuale "stato computazionale", in modo che possa essere recuperato in seguito per completare l'elaborazione. Visualizza Modelli e DTO possono essere serializzati liberamente, ma in pratica i loro dati vengono normalmente salvati in un database.

Serializzazione, dipendenze e accoppiamento

Sebbene sia vero che la serializzazione crea dipendenze, nel senso che è necessario deserializzare su un oggetto compatibile, non necessariamente segue che è necessario modificare la configurazione della serializzazione. I buoni meccanismi di serializzazione sono di uso generale; a loro non importa se si modifica il nome di una proprietà o di un membro, a condizione che possa ancora mappare i valori ai membri. In pratica, ciò significa solo che devi serializzare nuovamente l'istanza dell'oggetto per rendere la rappresentazione della serializzazione (xml, json, qualunque sia) compatibile con il tuo nuovo oggetto; nessuna modifica alla configurazione del serializzatore dovrebbe essere necessaria.

È vero che gli oggetti non dovrebbero preoccuparsi di come sono serializzati. Hai già descritto in un modo che tali preoccupazioni possono essere disaccoppiate dalle classi di dominio: riflessione. Ma il serializzatore dovrebbe essere preoccupato di come serializza e deserializza oggetti; dopotutto, è la sua funzione. Il modo in cui mantieni gli oggetti disaccoppiati dal processo di serializzazione è rendere la serializzazione una funzione generica , in grado di funzionare su tutti i tipi di oggetto.

Una delle cose su cui le persone si confondono è che il disaccoppiamento deve avvenire in entrambe le direzioni. Non è così; deve solo funzionare in direzione one . In pratica, non puoi mai disaccoppiare completamente; c'è sempre un accoppiamento alcuni . L'obiettivo di un accoppiamento lento è facilitare la manutenzione del codice, non rimuovere tutte le dipendenze.

    
risposta data 14.12.2014 - 22:18
fonte
-1

Lo scopo alla base della serializzazione è garantire che i dati prodotti da un sistema possano essere utilizzati da uno o più sistemi compatibili.

L'approccio alla serializzazione più semplice e robusto consiste nel tradurre i dati in un formato di tipo agnostico che mantiene la struttura in un formato semplice e facile da utilizzare. Ad esempio, i formati di serializzazione più diffusi (es. JSON, XML) utilizzano un formato basato su testo ben definito. Il testo è semplice da produrre, trasmettere e consumare.

Ci sono 2 motivi per cui l'utilizzo di uno di questi formati potrebbe non essere l'ideale.

  1. Efficienza

    C'è un costo intrinseco implicato nella traduzione di tutti i dati nei loro equivalenti testuali. I tipi di dati non esisterebbero se il testo fosse il modo più efficiente per esprimere tutte le diverse forme di dati. Inoltre, la struttura di questi formati non è l'ideale per il recupero di sottoinsiemi di dati in modo asincrono o in parti.

    Ad esempio, XML e JSON presuppongono che i dati utilizzati verranno scritti e letti dall'inizio alla fine. Per elaborare set di dati molto grandi in cui la memoria è scarsa, il sistema che utilizza i dati potrebbe richiedere la capacità di elaborare i dati in parti. In tal caso, potrebbe essere necessaria un'implementazione per serializzazione / deserializzazione per gestire i dati.

  2. Precisione

    Il casting richiesto per serializzare / deserializzare i dati dal tipo desiderato a quelli di tipo agnostico dei dati determina una perdita di precisione.

Si potrebbe sostenere che produrre una rappresentazione binaria degli oggetti e dei dati sia chiaramente la soluzione più efficiente e precisa. Il principale svantaggio è che l'implementazione di tutti i sistemi che consumano e producono dati devono rimanere compatibili. È un semplice vincolo teorico, ma è un incubo mantenere in pratica i sistemi di produzione che tendono a cambiare / evolvere nel tempo.

Detto questo. La decodificazione della serializzazione / deserializzazione dai dettagli specifici del dominio ha senso come regola generale, perché i formati per scopi generali sono più robusti, supportati meglio su sistemi diversi e richiedono un sovraccarico di manutenzione da poco a nullo da utilizzare.

    
risposta data 15.12.2014 - 08:54
fonte