"Inversion of Control" promuove "Anemic Domain Model"?


32

Quando ho usato IoC Container nel mio ultimo progetto, sono finito con entità anemiche e la maggior parte della mia logica di business in Stateless Services.

Ho visto progetti scritti da altri sviluppatori che utilizzano "Inversion of Control" e sono sempre "Anemici".

Poiché "Anemic Domain Model" è anti-pattern, è possibile utilizzare IoC e Rich Domain? Sono dei buoni esempi, progetti open source che lo fanno?


Penso che dovremmo vedere alcuni esempi specifici del tuo caso particolare per dare una mano.
Martijn Verburg,

1
Spiacenti, intendevo frammenti di codice :)
Martijn Verburg,

Risposte:


11

Per cominciare: DI e IoC non sono sinonimi. Mi dispiace ma devo sottolinearlo (mi sembra che tu pensi che lo siano).

Per quanto riguarda la tua richiesta ... Bene, l'iniezione di dipendenza è solo uno strumento. Il modo in cui utilizzerai questo strumento è una cosa completamente separata. Esistono anche altri strumenti (modelli di progettazione) che potrebbero aggravare il problema. Ad esempio, ritengo che l'ampia adozione del modello MVC sia uno degli ingredienti chiave per formare l'anti-modello del modello di dominio anemico: i controller (in applicazioni più semplici, in applicazioni più complicate che sarebbero un livello di servizio aggiuntivo) si assumono la responsabilità di convalidare le regole aziendali , imponendoli e trasformando le entità DB in qualcosa di utile, mentre il livello aziendale si trasforma in un semplice livello di accesso ai dati che è un semplice ORM con mapping uno a uno alle entità del database.

Certamente è il modo in cui si progetta l'applicazione: è possibile creare un modello di dominio corretto se lo si desidera e tutti questi IoC, DI, MVC non ti fermano. Ciò che potrebbe fermarti è la tua squadra. In qualche modo è necessario convincerli a usare la strada giusta e potrebbe essere difficile in quanto molti sviluppatori di software non hanno un forte background architettonico.


Aggiungerò a questo che forse potresti dare un'occhiata all'approccio DDD promosso da Eric Evans et al.
Martijn Verburg,

1
Ho letto il libro di Eric Evans. È buono per la metodologia generale e il linguaggio onnipresente, ma in qualche modo manca di esempi del mondo reale.
Mag20

Grazie per aver sottolineato la differenza tra DI e IoC. Penso che il problema abbia più a che fare con l'IoC che con DI. Modificata la domanda per riflettere ciò.
Mag20,

Nella mia esperienza con i framework / container DI (Spring DI, CDI, Unity), in realtà ti impediscono di creare un "modello di dominio corretto", il che per me significa che gli sviluppatori non dovrebbero essere costretti a usare oggetti veri (cioè, stateful) . Ma DI non lo supporta davvero.
Rogério,

8

La maggior parte (se non tutte) le applicazioni sono un mix di infrastrutture e problemi di dominio. Quando si raggiunge un certo livello di complessità, sarà più facile gestire se il dominio è separato dall'infrastruttura in modo che sia più facile ragionare e possa evolversi in modo indipendente.

Naturalmente il modello di dominio deve ancora comunicare con il resto del sistema e di solito ciò avverrà con i servizi senza stato (che fanno parte del dominio) che presentano problemi di infrastruttura (come l'accesso al database). L'uso di un contenitore IoC non rimuove questa dipendenza, ma sposta la sua configurazione in un'area separata, rendendo ancora più semplice ragionare e mantenere.

Le entità stanno memorizzando lo stato e dovrebbero essere responsabili delle regole aziendali. Se i tuoi servizi stanno applicando tutti gli invarianti e altre regole commerciali, è probabile che la logica sia nel posto sbagliato.

Ora se hai la logica nei posti giusti e hai ancora finito con servizi che non sono altro che involucri attorno a cose e entità infrastrutturali che sono solo sacchi di proprietà, è molto probabile che il dominio non sia abbastanza complesso da giustificare il sovraccarico del suo modello. Quasi tutto ciò che leggerai su DDD conterrà una dichiarazione di non responsabilità che in realtà è destinata solo a domini complessi, ma questo sembra essere troppo spesso dimenticato.


7

Vai alla fonte. Inizia con il pezzo di Fowler su Anemic Domain Models . Fa riferimento al Domain Driven Design di Eric Evan come esempio di buona pratica. Il codice sorgente per questo è qui . Scaricalo.

Si noti che utilizza Inversion of Control (ricerca di @Autowired) e dispone di classi di servizio (BookingService) e classi di "processi aziendali" (ad esempio ItineraryUpdater).

L'articolo originale di Fowler dà il via all'esempio che stai cercando.


Quell'app di esempio, infatti, non è conforme a DDD come descritto nel libro. Una contraddizione specifica con il libro è che viola completamente il concetto di "infrastruttura", consentendogli di contenere codice specifico del dominio; ad esempio, la VoyageRepositoryHibernateclasse, che è stata inserita nel livello dell'infrastruttura ma in realtà dipende dal livello del dominio.
Rogério,

Sì, il libro dice a pagina 73 che il livello dell'infrastruttura è "sotto" il livello del dominio e "non dovrebbe avere alcuna conoscenza specifica del dominio che sta servendo". Questo non ha mai avuto senso per me. Si consideri un progetto che ha due implementazioni VoyageRepository: VoyageRepositoryHibernate e una classe VoyageRepositoryJDBC. Le loro implementazioni sono necessariamente molto diverse e specifiche per la tecnologia. Questi appartengono al livello del dominio? O il livello dell'infrastruttura? Nel nostro codice, secondo il libro, lo facciamo al contrario: il livello di infrastruttura può fare riferimento al livello di dominio, ma non viceversa.
Jamie,

Appartengono al livello del dominio, sì. L'implementazione basata su JDBC conterrebbe il codice SQL associato a tabelle e colonne nel database dell'applicazione, che sono specifiche del dominio. Inserire un codice specifico per dominio o applicazione nel livello dell'infrastruttura è semplicemente sbagliato, poiché il "codice infrastruttura" dovrebbe essere usato solo per risolvere problemi tecnici e dovrebbe (idealmente) essere completamente riutilizzabile tra applicazioni e domini diversi. La soluzione per avere un codice "di basso livello" (ad es. SQL) nel livello del dominio non è di spostarlo completamente, ma di implementarlo su un'infrastruttura migliore, come ORM.
Rogério,

Per me, l'implementazione di save (MyDomainObject foo) è una preoccupazione puramente tecnica. YMMV.
Jamie,

Solo se non ti porta a violare la regola fondamentale di un'architettura a strati: un livello inferiore non può dipendere da un livello superiore. Quindi, se implementato save(foo)con codice soggetto a modifiche quando cambia il modello di dominio (ad esempio, se viene aggiunto un nuovo attributo MyDomainObject), allora deve (per definizione) appartenere al livello di dominio; altrimenti, non puoi più parlare di avere "livelli" più.
Rogério,

7

è possibile utilizzare IoC e Rich Domain? Sono dei buoni esempi, progetti open source che lo fanno?

Suppongo che tu intenda DI invece di IoC, e il progetto a cui hai lavorato utilizza un contenitore DI come Spring. IoC ha due gusti principali: DI e modello Locator. Non vedo perché il modello Locator dovrebbe essere un problema, quindi concentriamoci su DI.

Non credo sia possibile, o almeno sarebbe molto impraticabile. L'aspetto principale dei contenitori DI è che controllano la creazione di oggetti quando li iniettano in altri ("oggetti gestiti"). L'insieme di oggetti gestiti che è attivo durante l'esecuzione dei progetti è indipendente da quali elementi di dominio esistono nel progetto ma dipende da come gli oggetti sono cablati e da quali ambiti (singleton, prototipo) sono assegnati a loro.

Questo è il motivo per cui non vuoi lasciare che il contenitore DI gestisca i tuoi oggetti di dominio. Ma se si creano oggetti manualmente (con nuovi), non è possibile iniettare altri oggetti nei propri oggetti di dominio. (Lasciando da parte potenziali soluzioni alternative con cablaggio manuale.) Poiché sono necessarie queste iniezioni per sostituire le implementazioni con altre, non è possibile sostituire la funzionalità di oggetti di dominio avanzati utilizzando DI. Quindi, non vorrai inserire funzionalità negli oggetti di dominio o perderai le funzionalità di DI.

Non vedo come potrebbe funzionare un ipotetico contenitore DI che non gestisca i tuoi oggetti, e nessuna delle implementazioni esistenti lo consente. Quindi è giusto affermare che DI si affida alla gestione degli oggetti. Ti tenterà quindi sempre di dividere i potenziali oggetti Rich Domain in una classe anemica e una o più classi di script di transazione.


Questa risposta colpisce davvero l'unghia della testa quando si tratta della tensione tra un Rich Domain Model e Dependency Injection.
jrahhali,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.