DDD: Come evitare di rompere l'incapsulamento e far emergere problemi tecnici al dominio durante la reidratazione del modello?

0

Quando si applicano i principi DDD in Ruby, sento che il pattern Active Record finisce per inquinare il modello di dominio, mentre non sono sicuro di come implementare la deserializzazione JSON senza interrompere l'incapsulamento.

Il pattern Data Mapper potrebbe essere un'alternativa, ma non ho trovato alcuna implementazione soddisfacente di Ruby che soddisfi i miei requisiti del Database.

L'implementazione abituale di ActiveRecord introduce problemi di persistenza sulle entità di dominio, mentre la separazione delle entità di dominio e delle entità di Active Record crea una gerarchia di classi duplicate, tra le altre complessità aggiuntive.

Con la deserializzazione JSON, o devo consentire a un costruttore e a un setter pubblici vuoti, o devo dare alla classe Aggregate la responsabilità di deserializzare JSON, che non sembra un problema di dominio legittimo, ma più di una preoccupazione per l'infrastruttura . Capisco che questa dovrebbe essere una responsabilità del repository, ma non vedo come implementarlo senza rompere l'incapsulamento della classe aggregata.

Forse l'alternativa sarebbe utilizzare l'Event Sourcing invece di persistere negli stati aggregati, o solo mantenere lo stato aggregato per scopi di lettura. È corretto?

    
posta FedericoG 28.07.2017 - 00:39
fonte

2 risposte

2

Non uso Active Record nei miei progetti poiché questo pattern mi obbliga a violare la mia regola DDD dorata: mantenere gli aggregati puri, senza effetti collaterali .

Se non si divide la lettura dalla scrittura, allora si ha un aggregato misto. Devi essere in grado di comandarlo e interrogarlo. Il problema non è interrogare un singolo aggregato, puoi farlo facilmente, dopo che è stato caricato dal repository, il problema è trovare, filtrare, sfogliare un elenco di aggregati perché ti costringe a rompere l'incapsulamento aggregato in base alla sua struttura interna . È necessario conoscere la sua struttura per applicare i filtri in base ai valori delle proprietà. Ogni volta che modifichi una proprietà sull'aggregato, devi adattare anche il filtro.

Se dividi la lettura dalla scrittura (cioè utilizzando CQRS e l'individuazione degli eventi), puoi eseguire tutto quanto sopra senza interrompere l'incapsulamento aggregato perché non esegui una query sull'aggregazione, ma eseguirai una query su un modello di lettura designato appositamente, senza interrompere l'incapsulamento (perché applica i propri filtri sui propri campi).

Pertanto, l'utilizzo di Event sourcing ti aiuta molto riguardo al tuo problema .

Naturalmente, ci sono altri problemi che si verificano con il sourcing di eventi.

    
risposta data 28.07.2017 - 08:39
fonte
0

Dichiarazione di non responsabilità: non un tipo di rubino.

ActiveRecord mi sembra una trappola. Vogliamo implementazioni facili da cambiare. Se il nostro modello di dominio è strettamente collegato alla progettazione della nostra persistenza, allora abbiamo bisogno di migrare i nostri dati ogni volta che apportiamo una modifica alle strutture di dati nel modello? Non sembra un buon compromesso.

Concettualmente, la rappresentazione che memorizziamo è un ricordo ; un seme di dati, scritto dal nostro modello in passato, che può essere utilizzato per creare una rappresentazione dello stesso stato nel modello corrente. Il memento svolge efficacemente il ruolo di un messaggio, il che significa che molte delle lezioni su progettare lo schema dei messaggi si applicano.

Al confine tra i componenti del dominio e i componenti di persistenza, sono necessarie due funzioni

  • una funzione che può assumere una rappresentazione di modello e ricavarne il corrispondente ricordo
  • una funzione che può prendere un memento e costruire da essa la rappresentazione del modello correspoding

L'individuazione degli eventi in realtà non aiuta, perché affronti esattamente gli stessi problemi: devi prendere la rappresentazione dei modelli degli eventi e convertirli nella rappresentazione di archiviazione, e viceversa.

Dove è finito l'incapsulamento? Ai confini, le applicazioni non sono orientate agli oggetti .

L'unico approccio alternativo che conosco: eliminare gli oggetti. Se esamini lo stato , piuttosto che il comportamento, una modifica di stato è simile a

State current = database.getState()
State next = model.transform(current)
database.replace(current, next)

Se dai alla linea di mezzo una svolta

State current = database.getState()
State next = current.bind(model.transform)
database.replace(current, next)

E tutto inizia ad assomigliare a una sorta di DB Monad

DB<State> current = database.getState()
DB<State> next = current.bind(model.transform)
database.replace(current, next)

Un modo per immaginarlo è che l'applicazione ci sta trasmettendo un comando e ciò che stiamo realmente facendo è tradurlo in un comando - più o meno nello stesso modo in cui un ORM prende un sacco di cambiamenti di stato e li trasforma in magie nei comandi SQL.

Ciò non rende l'implementazione del codice più facile , per quanto posso dire.

    
risposta data 28.07.2017 - 04:51
fonte