Modello di dominio ricco vs modello di strategia in DDD

6

Recentemente ho visto alcuni corsi Pluralshigh su DDD di Vladimir Khorikov. Era incoraggiante nel creare un rich invece di anemico modelli di dominio. Sembra tutto molto bello in un piccolo progetto di test, tuttavia non ho ancora idea di come mettere la estensiva logica aziendale all'interno del modello di dominio ricco .

Nel modello di dominio ricco dovremmo inserire la logica di dominio in entità. Quindi diciamo che vogliamo modellare un Employer che paga lo stipendio il loro Employees . Vedo datore di lavoro come radice aggregata qui.

Quindi aggiungiamo un metodo Employer.PayTo(someEmployeeIdentificator) . Le regole aziendali per il calcolo dello stipendio potrebbero essere molto elaborate e dipendere da cose come:

  • Paesi del datore di lavoro e dei dipendenti
  • Modulo di lavoro
  • Modulo per la tassazione dei dipendenti
  • Quanto ha funzionato un dipendente il mese scorso
  • e molto altro ancora, ottieni il punto

Potenzialmente, potrebbero esserci alcune dozzine di algoritmi. Alcuni potrebbero persino richiedere la comunicazione con servizi esterni. Un caso perfetto per il modello di strategia, ma:

  • La logica doveva essere implementata all'interno delle entità
  • Employees sono nascosti all'interno di Employer radice aggregata
  • Posso non usare IOC per iniettare cose nelle mie entità (di solito sono create da un ORM). E fornire gli alberi delle dipendenze non è divertente.
  • L'inserimento di alcune implementazioni di SalaryCalculator nell'entità Employer potrebbe essere una cattiva idea, poiché le calcolatrici potrebbero non essere "pure" . Potrebbero avere riferimenti ad alcune risorse esterne (ad esempio, il tracker di problemi)

Come lo modellerai?

    
posta Andrzej Gis 17.05.2018 - 00:08
fonte

4 risposte

9

The logic was supposed to be implemented inside the entities

Sì, anche se di solito è più specifico di quello - la logica che calcola il nuovo stato di un'entità dovrebbe essere "dentro" l'entità.

Employees are hidden inside the Employer aggregate root

Potrebbe non essere un modello efficace da utilizzare per questo tipo di problema; potrebbe essere più sensato concentrarsi sulle transazioni (scambi di denaro) o sui registri, piuttosto che sulle persone.

Trovo utile ricordare che gli aggregati sono elementi digitali ; sono (parti di) documenti che descrivono qualcosa, non la cosa stessa.

I cannot use IOC to inject stuff into my entities

Ricorda, l'inversione del controllo "è in realtà solo un modo pretenzioso di dire prendere una discussione ." Di solito non iniettiamo materiale in entità, è vero. Invece, passiamo le cose alle entità come argomenti (servizi di dominio).

Injecting the some implementations of SalaryCalculator to the Employer entity might be a bad idea, as the calculators might not be 'pure'. They might have references to some external resources (e.g. issue tracker)

Le prime discussioni sul modello di dominio (Evans nel libro blu, Fowler in Patterns of Enterprise Application Architecture) non richiedono che sia puro. Sono oggetti che chiamano altri oggetti, con l'aspettativa di effetti collaterali.

Come meglio posso dire, hai davvero due opzioni: puoi rendere l'orchestrazione tra gli oggetti parte del modello di dominio, oppure puoi trattare il modello stesso come un singolo collaboratore e gestire l'orchestrazione altrove.

How would you model it?

"Dipende". Probabilmente inizierei separando diversi processi

  • Calcolo della somma maturata durante un periodo di pagamento
  • Calcolo della dispersione di una certa quantità di compensazione
  • Monitoraggio e conferma dei trasferimenti di risorse

Inoltre, prestate molta attenzione a modellare correttamente sottili distinzioni; se nel tuo dominio esistono compensi salariali, retribuzioni orarie e vendite commissionate, devono essere identificabili separatamente nel tuo modello. "Quasi lo stesso" è solo un modo di ortografia sdolcinato diverso .

    
risposta data 17.05.2018 - 04:08
fonte
3

In rich domain model we are supposed to put domain logic into entities

Il problema con questa frase è, la gente lo interpreta male come

  • "dovremmo inserire tutte le logiche di dominio in entità" .

Un'interpretazione migliore potrebbe essere:

  • "dovremmo inserire alcune logiche di dominio in entità"

dove "alcuni" indica la logica del dominio che ha più senso. Non esiste una regola "hard & fast" per prendere una decisione su dove tracciare la linea, ma un buon inizio è mettere qualsiasi logica che possa essere espressa principalmente attraverso le proprietà dell'oggetto stesso nell'oggetto.

Come hai già dimostrato, una grande operazione come PayTo non rientra in quella categoria, quindi consiglierei di implementarla non direttamente nella classe Employer . Ciò non significa che finirai con un modello di dominio anemico, sicuramente quando il tuo programma evolverà, troverai molte piccole operazioni che si adattano perfettamente a una classe Employer .

    
risposta data 17.05.2018 - 04:53
fonte
1

I see Employer as the aggregate root here.

Quando esegui la modellazione OO, in genere una funzione aziendale viene definita sull'oggetto dell'azione, non sull'iniziatore dell'azione.

Dipende dai requisiti, naturalmente, ma forse modellerei questo come Employee.receiveSalary() .

Un altro indicatore che questo potrebbe essere "migliore" è che nel tuo caso il metodo ha bisogno dell'id dipendente (fondamentalmente un riferimento a un altro oggetto) per fare il suo lavoro. Indica che il metodo vuole essere in un altro oggetto.

Injecting the some implementations of SalaryCalculator...

Probabilmente non creare un oggetto denominato SalaryCalculator . Il problema è che è non parte del "dominio". Anche se vuoi creare diverse "strategie", è meglio trovare un modo per incorporarlo nel dominio stesso.

Potrebbe essere semplice come nominare la cosa Salary invece di SalaryCalculator . Possono esserci HourlySalary , MonthlySalary , qualunque sia. Questo ha senso nel dominio invece di attaccarlo.

The logic was supposed to be implemented inside the entities

Sì. Se non riesci a trovare un buon posto dove fare le cose, probabilmente ti manchi una buona astrazione. (Vedi l'esempio con SalaryCalculator ). Se lo fai correttamente, non ti serviranno servizi o calcolatori o altre cose che non fanno parte del dominio.

Employees are hidden inside the Employer aggregate root

Se questo è un problema, allora non farlo. La modellazione corretta viene prima, le cose tecniche arrivano seconde! Forse Employee dovrebbe essere la radice aggregata, oppure esiste una terza astrazione che può fungere da radice per questo caso specifico.

I cannot use IOC to inject stuff into my entities...

Ancora una volta, modellazione corretta prima, seconda tecnologia. Se la tecnologia non supporta un modello corretto, puoi scegliere un'altra tecnologia (ce ne sono molte).

Gli oggetti collaborano tra loro, dicendo che un insieme di oggetti non può definire i collaboratori mi sembra irragionevole.

    
risposta data 17.05.2018 - 10:28
fonte
0

Non è necessario che le entità aziendali siano uguali alle entità di persistenza. Puoi usare qualsiasi strumento per creare facilmente la mappatura tra loro (in C #, abbiamo Automapper).

In questo modo è possibile iniettare qualsiasi dipendenza necessaria nelle entità aziendali. Inoltre, può aiutarti a nascondere proprietà / attributi che potresti aver reso pubblici solo perché il tuo ORM ne aveva bisogno.

    
risposta data 17.05.2018 - 01:03
fonte