In che modo "preparazione" e "utilizzo" degli stessi dati devono essere separati in un'applicazione DDD, se non del tutto?

0

Nella maggior parte dei domini, c'è un'app che "prepara" i dati e un'altra app che "serve" i dati preparati. I dati, tuttavia, provengono dallo stesso dominio principale, il che causa un po 'di confusione nella modellazione.

Alcuni esempi:

  1. In un'app di spedizione / carico, ci sarà un'interfaccia utente per la gestione: i membri dello staff aggiungeranno / aggiorneranno / cancelleranno carichi, viaggi e clienti. Quindi, in un'altra interfaccia utente o in una parte dell'applicazione, qualcuno sfrutterà questi dati preparati per eseguire il pesante sollevamento dei carichi corrispondenti ai viaggi, in base alle richieste dei clienti, esponendoli magari come API.
  2. In un'applicazione pubblicitaria, ci sarà un'interfaccia utente in cui il personale o gli inserzionisti possono aggiungere / aggiornare / eliminare annunci, che includeranno offerte, restrizioni (geo, dispositivi, ecc.). Un'altra app prenderà questa informazione e la userà per "servire" i dati preparati.

Ci sono un sacco di altri esempi ma condividono lo stesso schema: preparazione dei dati e pubblicazione degli stessi dati. Entrambe condividono le stesse informazioni, come le restrizioni sugli annunci e i pagamenti nel dominio pubblicitario, ma le usano in contesti diversi. "Preparare" può essere comunemente basato su CRUD, mentre "servire" è più coinvolto.

Come si modellano questi? Dovrebbe esserci un singolo contesto limitato relativo al dominio principale in cui vengono utilizzate le stesse entità? Oppure devono essere considerati contesti completamente separati, in cui un kernel condiviso può includere ID entità e forse un database sottostante condiviso?

Ho esaminato il modello CQRS che potrebbe essere utile. Per utilizzare il dominio pubblicitario, "preparare" i dati potrebbe utilizzare sia comandi che query (una specie di pattern CRUD), mentre il "serving" potrebbe utilizzare query dedicate (che ovviamente sarebbero molto diverse).

Tuttavia, non riesco a scuotere la sensazione che separare completamente questi elementi creerebbe molta duplicazione, oltre a un elevato accoppiamento, ad es. se viene aggiunta una nuova restrizione su un annuncio (forse "nome del sistema operativo"), dovrebbe essere simultaneamente aggiunta alle fasi di "preparazione" e "utilizzo".

    
posta Blossoming_Flower 09.07.2018 - 00:06
fonte

1 risposta

1

Oltre alla terminologia, hai descritto molto attentamente il CQRS. Il pezzo che sembra mancare è il modello letto.

Crea, aggiorna ed elimina tutti provenienti dall'interfaccia utente e tradotti in comandi. I comandi eseguono tutte le modifiche al modello di dominio per eseguire il desiderio dell'utente. Tieni presente che il modello di dominio è ciò che la maggior parte delle persone pensa quando immagina un sistema CRUD - in genere una terza forma normale con relazioni appropriate, ecc.

Dopo che il comando è stato eseguito apportando le modifiche necessarie, aggiornerà tutti i modelli di lettura interessati (in genere ciò avviene tramite messaggistica o flussi di eventi per consentire l'elaborazione asincrona, ma facciamo finta di avere una macchina infinitamente potente, quindi le prestazioni sono di nessuna preoccupazione). Il modello di lettura è costituito da un insieme di tabelle progettate appositamente per essere pubblicate dall'utente e SOLO per essere pubblicate per essere lette. Duplicheranno sicuramente i dati: la terza forma normale non ha posto in queste tabelle. Se il cognome di un utente è necessario su tre schermi diversi, ci saranno 3 diverse tabelle di modelli di lettura con una colonna del cognome. L'idea è che gli aggiornamenti sono molto più rari delle letture, quindi facciamo le letture il più velocemente possibile anche se costa un piccolo extra durante la fase di aggiornamento. La lettura dei dati da un modello di lettura dovrebbe idealmente essere una semplice selezione dalla tabella corretta senza join, solo una clausola where da filtrare alle righe.

Le tabelle dei modelli letti saranno strettamente accoppiate ai modelli di vista, non necessariamente al modello di dominio. Se viene aggiunta una nuova restrizione su un annuncio come "op sys name", ovviamente deve essere aggiunto al modello di dominio. Deve solo essere aggiunto ai modelli letti, tuttavia, se deve essere visualizzato sullo schermo da qualche parte. In altre parole, le modifiche al modello di dominio non guidano le modifiche al modello in lettura, cambiando i requisiti dell'utente si guidano le modifiche al modello in lettura e il codice che aggiorna tali modelli deve tenere il passo con le modifiche su entrambi i lati.

Sul tuo commento su CQRS nel dominio pubblicitario e sulla "preparazione" dei dati utilizzando comandi e query, sembra che tu abbia l'idea giusta ma la terminologia ti sta facendo saltare in aria. Le query CQRS non vengono mai utilizzate dal lato comando. I comandi spesso devono recuperare i dati (sto cercando di evitare la q-word) e aggiornare i dati prima di persistere, ma non dovrebbero mai recuperare i dati dal modello di lettura. Le query CQRS, d'altra parte, sono autorizzate a recuperare i dati dal modello di lettura, non dal modello di dominio.

A proposito, ho una certa esperienza con il settore delle spedizioni e l'elaborazione del flusso di eventi varrebbe la pena di essere investigata. La complessità dei calcoli richiede uno sforzo extra per renderli asincroni e scalabili, che possono essere resi molto più semplici con l'elaborazione del flusso (si pensi a Kafka, AWS Kinesis o all'hub eventi di Azure).

    
risposta data 09.07.2018 - 04:06
fonte

Leggi altre domande sui tag