Come progettare i confini aggregati?

10

Vorrei scrivere un'applicazione come e-commerce.

E sai che in applicazioni simili i prodotti potrebbero avere proprietà e caratteristiche diverse. Per simulare questa opportunità ho creato le seguenti entità del modello di dominio:

Categoria - questo è qualcosa come "elettronica > omputer", cioè tipi di prodotti. Сategories contengono un elenco di proprietà (List < Property >).

Proprietà - entità indipendente che contiene il nome, le unità di misura, il tipo di dati. Ad esempio "nome", "peso", "dimensione dello schermo". La stessa proprietà può avere prodotti diversi.

Prodotto - contiene solo il nome e l'elenco di valori relativi alle proprietà. Il valore è un oggetto che contiene solo il campo valore e l'ID campo della proprietà.

Originariamente ho deciso di creare la categoria come aggregato singolo in questo schema perché ad esempio quando aggiungo un nuovo prodotto ho bisogno di conoscere tutti i dati relativi alla categoria corrente comprese le proprietà relative alla categoria corrente ( category.AddNewProduct (prodotto ) ). Ma cosa dovrei fare quando ho solo bisogno di aggiungere una nuova proprietà che non appartiene a nessuna categoria. Ad esempio, non posso fare questo category.AddNewProperty (proprietà) perché dice chiaramente che aggiungiamo la proprietà a una categoria specifica.

Ok il prossimo passo ho deciso di separare la proprietà in un aggregato separato, ma poi sarà una lista con entità semplici.

Naturalmente posso creare qualcosa come PropertyAggregate per mantenere l'elenco delle proprietà e delle regole di business ma quando aggiungo un prodotto, ho bisogno di avere all'interno della categoria l'intero elenco di proprietà appartenenti a questa categoria per controllare gli invarianti. Ma sono anche consapevole che mantenere i collegamenti all'interno dell'aggregato su altri aggregati è una cattiva pratica.

Quali sono le opzioni per progettare questo business case?

    
posta cephei 22.11.2017 - 06:53
fonte

2 risposte

6

Nella prospettiva DDD, Category , Product e Property sono entità: tutte corrispondono a oggetti che hanno una propria identità.

Opzione 1: il tuo design originale

Hai creato Category la radice di un singolo aggregato. Da un lato questo ha senso, perché l'aggregato deve garantire la coerenza quando i suoi oggetti sono modificati, e Product deve avere il Properties del suo Category :

Madall'altraparte,ilsingoloaggregatosignificachetuttiisuoioggettisonocorrelatiaunaradicechelipossiedeetuttiiriferimentiesternidevonoesserefattitramitequestaradiceaggregata.Ciòimplicache:

  • unospecificoProductappartieneaunoesolounoCategory.SevieneeliminatoCategory,loèancheProducts.
  • unospecificoPropertyappartieneaunoesolounoCategory.Altrimenti,se"schermi TV" e "monitor per computer" fossero due categorie, "schermi TV: dimensioni" e "monitor per computer: dimensioni" sarebbero due proprietà diverse.

Il secondo punto non corrisponde alla tua narrazione: " Ma cosa dovrei fare quando ho solo bisogno di aggiungere un nuovo Property che non appartiene a nessuna categoria ". E non è chiaro se lo stesso Properties possa essere usato in Categories diverso.

Opzione 2: Proprietà al di fuori dell'aggregato

Se esiste una Property indipendentemente dal Categories , deve essere al di fuori dell'aggregato. E lo stesso se vuoi condividere Properties tra Categories (che ha senso per altezza, larghezza, dimensioni, ecc ...). Questo sembra essere il caso.

La conseguenza è sul link tra Property e cose che appartengono all'aggregato: mentre puoi navigare dall'interno dell'aggregato a Property , non ti è più permesso andare direttamente da Property a i valori corrispondenti. Questa restrizione navigabilità può essere mostrata in un diagramma UML:

NotachequestodesignnontiimpediscediavereunList<Property>inCategory,conunasemanticadiriferimento(ades.java):ogniriferimentonell'elencosiriferisceaunoggettoPropertycondivisibileinunrepository.

L'unicoproblemaconquestodesignèchepuoimodificarePropertyoeliminarlo:poichéèesternoall'aggregato,l'aggregatononpuòoccuparsidellacoerenzadeisuoiinvarianti.Maquestononèunproblema.ÈlaconseguenzadeiprincipidelDDDedellacomplessitàdelmondoreale.EccounacitazionediEricEvansnelsuolibro" Progettazione guidata dal dominio: affrontare la complessità nel cuore del software ":

Any rule that spans AGGREGATES will not be expected to be up-to-date at all times. Through event processing, batch processing, or other update mechanisms, other dependencies can be resolved within some specified time. But the invariants applied within an AGGREGATE will be enforced with the completion of each transaction.

Quindi sì, se cambi un Property , dovrai assicurarti che un servizio controlli che le Categorie che si riferiscono ad esso siano aggiornate secondo necessità.

Opzione 3: categoria, proprietà e prodotto in diversi aggregati

Mi chiedo solo se l'ipotesi che una Product appartenga a un singolo Category è stata fondata:

  • Vedo spesso negozi online che propongono un Product in più Categories . Ad esempio, nella categoria "Laptop" e categoria "Computer" e "Stampante multifunzione Z" nella categoria "stampante", "scanner" e "fax" si trova "Marca portatile X modello Y".
  • Non è possibile che qualcuno prima crei un Product e solo successivamente lo assegni a Categorie e riempi i valori?
  • Se vuoi dividere una categoria, cancelleresti davvero i suoi prodotti e poi li ricrei sotto le nuove categorie?

Non semplificherà gli aggregati e avresti ancora più regole che abbracciano gli aggregati. Ma il tuo sistema sarebbe molto più a prova di futuro.

    
risposta data 23.11.2017 - 01:06
fonte
5

Come vedo, puoi risolverlo in due modi:

La categoria è un tipo speciale di prodotto

Ciò significa che per qualsiasi prodotto specificato nel database, esso contiene una chiave esterna che punta allo stesso prodotto di tabella. Un prodotto è un prodotto solo se non esistono prodotti la cui chiave esterna è uguale all'ID di detto prodotto. In altre parole, se non ha prodotti sotto di esso, è un prodotto.

Questo semplificherebbe un po 'le cose. I prodotti alle proprietà hanno una relazione uno-a-molti e quindi anche le categorie hanno una relazione uno-a-molti in quanto sono anche prodotti. Aggiungere una proprietà a una categoria sarebbe facile come aggiungere una proprietà a un prodotto nel tuo programma. Caricare tutte le proprietà significherebbe combinare le proprietà del prodotto con le proprietà del prodotto della sua categoria associata e fino a quando non si raggiunge un prodotto di categoria senza genitore.

La tua applicazione e-commerce dovrebbe fare questa distinzione, ma se è probabile che tu carichi i prodotti di una categoria in ogni caso, non è una perdita di prestazioni sapere se hai a che fare con una categoria o un prodotto. Si presta bene anche alla ricerca in albero di moda per il livello di prodotto in quanto ogni prodotto (categoria) si aprirà a un elenco di sottoprodotti senza molto lavoro aggiuntivo.

Lo svantaggio di questo è ovviamente l'aggiunta di informazioni aggiuntive nel prodotto che non ha senso perché una categoria creerebbe dei campi inutilizzati nel prodotto. Sebbene questa soluzione sia più flessibile nella tua applicazione, è anche un po 'meno intuitiva.

Relazione molti-a-molti

I prodotti non sono più in una relazione composita con la proprietà. Si crea una tabella ProductProperty con chiavi esterne della tabella dei prodotti e della tabella delle proprietà che collegano le due. Allo stesso modo, hai una tabella delle categorie con una relazione molti-a-molti con la tabella delle proprietà e una tabella CategoryProperty con chiavi esterne sia della tabella delle categorie sia della tabella delle proprietà.

Il prodotto stesso avrebbe una relazione molti-a-uno con la categoria, consentendo di creare essenzialmente un elenco di proprietà uniche relative sia al prodotto che alla categoria attraverso un'istruzione select ben formalizzata.

Dal punto di vista del database, questo è decisamente più pulito e flessibile. La tua applicazione potrebbe probabilmente fare per la maggior parte senza trattare direttamente con CategoryProperty o ProductProperty se la query viene eseguita correttamente. Tuttavia, nessuno dei due dovrebbe trattare la categoria o il prodotto come proprietario della proprietà. Dovrebbe essere la propria entità all'interno del tuo programma. Ciò significa anche che la gestione di tali proprietà sarebbe una questione di creazione della proprietà stessa, quindi associandola a una categoria o a un prodotto in due passaggi separati. Sicuramente più lavoro della prima soluzione, ma non più difficile.

Oltre a questo, dovresti anche eseguire un controllo aggiuntivo sulla cancellazione di categoria o prodotto se una delle sue proprietà viene utilizzata da altri (a differenza della prima soluzione in cui è possibile eliminare in modo sicuro tutte le proprietà associate di un determinato prodotto /categoria).

Conclusione

In un contesto professionale, farei la categoria extra miglia e distanza dal prodotto e dal prodotto dalla proprietà usando l'approccio molti-a-molti. Non ci sarebbe alcuna possibilità di sovrapposizione dei dati e, in un certo senso, è più facile ragionare ognuno di questi tre come una propria entità. Tuttavia, la prima soluzione non è affatto negativa, in quanto consente anche di scrivere un'applicazione più semplice. Sappi solo che se pensavi di dover eventualmente passare da una soluzione all'altra, probabilmente sarebbe nel tuo stesso interesse scegliere il secondo.

Buona fortuna!

    
risposta data 22.11.2017 - 10:10
fonte

Leggi altre domande sui tag