2014-11-14 3 views
11

I servizi di dominio possono accedere ai repository? Oppure dovrebbero lavorare su aggregati/entità trasmessi loro da Application Services?I servizi di dominio possono accedere ai repository?

Considerare due esempi di codice della stessa operazione commerciale - trasferimento di denaro. Come primo passo, modifico i saldi dei conti. Quindi ottengo l'e-mail di notifica e invio la notifica. Lo so, probabilmente dovrei astrarre il modo in cui vengono inviate le notifiche (e-mail, SMS, piccione viaggiatore), ma per semplicità supponiamo che ora supportiamo solo le e-mail.

La variante 1 utilizza repository all'interno del servizio di dominio. La variante 2 risolve le dipendenze nel servizio dell'applicazione e le passa a TransferDomainService.

In questo esempio l'operazione è semplice (sottrarre denaro da un account e aggiungerlo a un altro). Ma se ci fossero più regole aziendali coinvolte (possibile richiedere l'accesso a più aggregati)? Se viene applicata la variante 2, il servizio dell'applicazione deve essere a conoscenza di cosa richiede esattamente il servizio di dominio. Se viene scelta la variante 1, il servizio di dominio richiede ai repository ciò che richiede per eseguire il proprio compito.

(Note su frammenti:. Codice Groovy per mettere a nudo la verbosità di Java blocchi DDD inclusi nei nomi)

Variante 1

class TransferApplicationService { 
    def transferDomainService 
    def customerDomainService 
    def emailNotifierInfrastructureService 

    def transfer(fromAccount, toAccount, amount) { 
     transferDomainService.transfer(fromAccount, toAccount, amount) 
     def email = customerDomainService.accountNotificationEmail(toAccount) 
     emailNotifierInfrastructureService.notifyAboutTransfer(email, amount) 
    } 
} 

class TransferDomainService { 
    def accountRepository 
    def transfer(fromAccount, toAccount, amount) { 
     def from = accountRepository.findByNumber(fromAccount) 
     def to = accountRepository.findByNumber(toAccount) 
     to.decreaseBalance(amount) 
     from.increaseBalance(amount) 
    } 
} 

Variante 2

class TransferApplicationService { 
    def accountRepository 
    def transferDomainService 
    def customerDomainService 
    def notifierInfrastructureService 

    def transfer(fromAccount, toAccount, amount) { 
     def from = accountRepository.findByNumber(fromAccount) 
     def to = accountRepository.findByNumber(toAccount) 
     transferDomainService.transfer(from, to, amount) 
     def email = customerDomainService.accountNotificationEmail(toAccount) 
     notifierInfrastructureService.notifyAboutTransfer(email, amount) 
    } 
} 

class TransferDomainService { 
    def transfer(fromAccount, toAccount, amount) { 
     to.decreaseBalance(amount) 
     from.increaseBalance(amount) 
    } 
} 
+0

Sì.Un servizio di dominio è ancora un orchestratore solo la sua area di competenza è più limitata – MikeSW

+0

@MikeSW intendi per "Sì" "Servizi di accesso ai repository" o "funzionano su aggregati/entità passate loro da Application Services"? – mgryszko

+0

Sì alla domanda del titolo. – MikeSW

risposta

10

Bene, direi che se si scelgono le entità da caricare si riduce a una buona dose di logi di dominio c, quindi potrei delegare tale attività al servizio di dominio. Tuttavia, mi sforzerò di solito di risolvere i riferimenti radice aggregati nei servizi applicativi.

Tuttavia, penso che potresti avere qualche altro problema qui o almeno potresti usare alcuni altri schemi tattici DDD come Eventi di dominio per migliorare il tuo design.

A mio parere, non si dovrebbe avere alcuna notifica che invia il codice nel servizio di applicazione a tutti. Invece, un evento di dominio MoneyTransferred potrebbe essere generato dal servizio di dominio. Avresti quindi un abbonato a questo evento che sarebbe responsabile per l'invio dell'email.

Oltre a disaccoppiare i componenti, si sta arricchendo il linguaggio onnipresente del dominio. L'invio di una notifica avviene ora in risposta a un trasferimento di denaro effettuato piuttosto che come parte dello stesso processo e anche molte altre parti interessate potrebbero reagire.

Infine, il servizio di dominio sta attualmente violando la regola di modifica di una sola radice aggregata per transazione. Non sto dicendo che non si può mai infrangere la regola, ma di solito è un buon indicatore che si dovrebbe usare coerenza finale, o forse che i propri confini aggregati sono sbagliati.

Se ci pensate, i trasferimenti di denaro tra conti si verificano raramente in modo atomico (se mai lo fanno). Immagino che potrebbe essere il caso se i due account sono nella stessa banca, ma la consistenza finale deve essere utilizzata quando il trasferimento si estende su più banche.

+0

Non prendere il mio esempio come codice come qualcosa preso dal codice di produzione :). Volevo solo impostare un contesto per le varianti del servizio di dominio - repository. – mgryszko

+0

@mgryszko Bene, in DDD non puoi avere risposte sui domini fictionnal e poi applicarli al tuo dominio. Tutte le risposte arrivano sempre a "dipende". Hai una serie di regole e linee guida, ma nulla che sia mai stato definito nella pietra. Quello che sto dicendo è che i servizi applicativi dovrebbero risolvere gli aggregati al servizio di dominio, a meno che ciò non trapelhi la logica di dominio nel servizio dell'applicazione (ad esempio, la ricerca di tali dipendenze si basa su regole di dominio). Inoltre, quello che sto dicendo è che, se non stavi modificando entrambi gli aggregati nella stessa transazione, forse non avresti nemmeno bisogno di un servizio di dominio. – plalx

+2

Non esiste una "regola" tale che un solo AR debba essere modificato da un solo servizio. – MikeSW