Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Suggerimento
Questo contenuto è un estratto dell'eBook, Architettura di microservizi .NET per applicazioni .NET containerizzati, disponibile in documentazione .NET o come PDF scaricabile gratuitamente leggibile offline.
La progettazione basata su dominio (DDD) supporta la modellazione basata sulla realtà aziendale in base ai casi d'uso. Nel contesto della creazione di applicazioni, DDD parla di problemi come domini. Descrive le aree problematiche indipendenti come contesti delimitati (ogni contesto delimitato è correlato a un microservizio) e sottolinea un linguaggio comune per parlare di questi problemi. Suggerisce anche molti concetti tecnici e modelli, ad esempio le entità di dominio con modelli avanzati (nessun modello di dominio anemico), oggetti valore, aggregazioni e regole radice di aggregazione (o entità radice) per supportare l'implementazione interna. Questa sezione presenta la progettazione e l'implementazione di questi modelli interni.
A volte queste regole tecniche e modelli DDD vengono percepiti come ostacoli che presentano una curva di apprendimento ripida per l'implementazione di approcci DDD. Ma la parte importante non è i modelli stessi, ma organizzare il codice in modo che sia allineato ai problemi aziendali e usando gli stessi termini aziendali (linguaggio comune). Inoltre, gli approcci DDD devono essere applicati solo se si implementano microservizi complessi con regole business significative. Le responsabilità più semplici, ad esempio un servizio CRUD, possono essere gestite con approcci più semplici.
Dove disegnare i limiti è l'attività chiave durante la progettazione e la definizione di un microservizio. I modelli DDD consentono di comprendere la complessità nel dominio. Per il modello di dominio per ogni contesto delimitato, è possibile identificare e definire le entità, gli oggetti valore e le aggregazioni che modellano il dominio. Si compila e si affina un modello di dominio contenuto all'interno di un limite che definisce il contesto. E questo è esplicito sotto forma di microservizio. I componenti all'interno di tali limiti finiscono per essere i microservizi, anche se in alcuni casi i microservizi bc o business possono essere composti da diversi servizi fisici. DDD riguarda i limiti e quindi i microservizi.
Mantenere i limiti del contesto del microservizio relativamente piccoli
Determinare dove posizionare i limiti tra contesti delimitati bilancia due obiettivi concorrenti. In primo luogo, si vuole creare inizialmente i microservizi più piccoli possibili, anche se questo non deve essere il driver principale; si dovrebbe creare un limite intorno a cose che necessitano di coesione. In secondo luogo, si vuole evitare comunicazioni di chat tra microservizi. Questi obiettivi possono contraddersi l'uno all'altro. È consigliabile bilanciare il sistema suddividendolo in quanti più piccoli microservizi possibile fino a quando i confini di comunicazione crescono rapidamente con ciascun tentativo aggiuntivo di separazione di un nuovo contesto delimitato. La coesione è fondamentale all'interno di un singolo contesto delimitato.
È simile all'odore del codice intimità inappropriato durante l'implementazione delle classi. Se due microservizi devono collaborare molto tra loro, probabilmente dovrebbero essere lo stesso microservizio.
Un altro modo per esaminare questo aspetto è l'autonomia. Se un microservizio deve basarsi su un altro servizio per gestire direttamente una richiesta, non è veramente autonomo.
Livelli nei microservizi DDD
La maggior parte delle applicazioni aziendali con notevole complessità aziendale e tecnica è definita da più livelli. I livelli sono un artefatto logico e non sono correlati alla distribuzione del servizio. Esistono per aiutare gli sviluppatori a gestire la complessità nel codice. Livelli diversi (ad esempio il livello del modello di dominio rispetto al livello di presentazione e così via) possono avere tipi diversi, che impongono traduzioni tra tali tipi.
Ad esempio, un'entità può essere caricata dal database. Quindi, una parte di tali informazioni o un'aggregazione di informazioni che includono dati aggiuntivi di altre entità, possono essere inviate all'interfaccia utente client tramite un'API Web REST. Il punto è che l'entità di dominio è contenuta all'interno del livello del modello di dominio e non deve essere propagata ad altre aree a cui non appartiene, ad esempio al livello di presentazione.
Inoltre, è necessario avere entità sempre valide (vedere la sezione Progettazione delle convalide nel livello del modello di dominio ) controllata dalle radici di aggregazione (entità radice). Pertanto, le entità non devono essere associate alle visualizzazioni client, perché a livello di interfaccia utente alcuni dati potrebbero non essere ancora convalidati. Questo è il motivo per cui viewModel è destinato. ViewModel è un modello di dati esclusivamente per le esigenze del livello presentazione. Le entità di dominio non appartengono direttamente a ViewModel. È invece necessario eseguire la conversione tra ViewModels ed entità di dominio e viceversa.
Quando si affronta la complessità, è importante avere un modello di dominio controllato dalle radici aggregate che assicurano che tutte le invarianti e le regole correlate a quel gruppo di entità (aggregazione) vengano eseguite tramite un singolo punto di ingresso o gate, la radice di aggregazione.
La figura 7-5 mostra come viene implementata una progettazione a più livelli nell'applicazione eShopOnContainers.
Figura 7-5. Livelli DDD nel microservizio di ordinazione in eShopOnContainers
I tre livelli in un microservizio DDD, ad esempio Ordering. Ogni livello è un progetto di Visual Studio: il livello applicazione è Ordering.API, Il livello di dominio è Ordering.Domain e il livello infrastruttura è Ordering.Infrastructure. Si vuole progettare il sistema in modo che ogni livello comunichi solo con determinati altri livelli. Questo approccio può essere più semplice da applicare se i livelli vengono implementati come librerie di classi diverse, perché è possibile identificare chiaramente le dipendenze impostate tra le librerie. Ad esempio, il livello del modello di dominio non deve accettare una dipendenza da qualsiasi altro livello (le classi del modello di dominio devono essere oggetti classe precedente normale o POCO). Come illustrato nella figura 7-6, la libreria dei livelli Ordering.Domain ha dipendenze solo dalle librerie .NET o dai pacchetti NuGet, ma non da altre librerie personalizzate, ad esempio la libreria di dati o la libreria di persistenza.
Screenshot delle dipendenze di Ordering.Domain.
Figura 7-6. I livelli implementati come librerie consentono un migliore controllo delle dipendenze tra i livelli
Livello del modello di dominio
L'eccellente libro Domain Driven Design di Eric Evans dice quanto segue sul livello del modello di dominio e sul livello dell'applicazione.
Livello del modello di dominio: responsabile della rappresentazione dei concetti aziendali, delle informazioni sulla situazione aziendale e delle regole business. Lo stato che riflette la situazione aziendale è controllato e usato qui, anche se i dettagli tecnici dell'archiviazione sono delegati all'infrastruttura. Questo livello è il cuore del software aziendale.
Il livello del modello di dominio è dove si esprime la logica aziendale. Quando si implementa un livello di modello di dominio di microservizio in .NET, tale livello viene codificato come libreria di classi con le entità di dominio che acquisiscano i dati più il comportamento (metodi con logica).
Seguendo i principi di ignoranza della persistenza e dell'ignoranza dell'infrastruttura , questo livello deve ignorare completamente i dettagli di persistenza dei dati. Queste attività di persistenza devono essere eseguite dal livello dell'infrastruttura. Pertanto, questo livello non deve assumere dipendenze dirette dall'infrastruttura, il che significa che una regola importante è che le classi di entità del modello di dominio devono essere poCO.
Le entità di dominio non devono avere alcuna dipendenza diretta (ad esempio derivazione da una classe di base) in qualsiasi framework dell'infrastruttura di accesso ai dati, ad esempio Entity Framework o NHibernate. Idealmente, le entità di dominio non devono derivare o implementare alcun tipo definito in qualsiasi framework di infrastruttura.
La maggior parte dei framework ORM moderni come Entity Framework Core consente questo approccio, in modo che le classi del modello di dominio non siano associate all'infrastruttura. Tuttavia, la presenza di entità POCO non è sempre possibile quando si usano determinati database e framework NoSQL, ad esempio Actors e Reliable Collections in Azure Service Fabric.
Anche quando è importante seguire il principio di ignoranza della persistenza per il modello di dominio, non dovresti ignorare i problemi di persistenza. È comunque importante comprendere il modello di dati fisico e il modo in cui esegue il mapping al modello a oggetti di entità. In caso contrario, è possibile creare disegni impossibili.
Inoltre, questo aspetto non significa che è possibile prendere un modello progettato per un database relazionale e spostarlo direttamente in un database NoSQL o orientato ai documenti. In alcuni modelli di entità, il modello potrebbe essere adatto, ma in genere non lo è. Esistono ancora vincoli che il modello di entità deve rispettare, in base alla tecnologia di archiviazione e alla tecnologia ORM.
Livello applicativo
Passando al livello dell'applicazione, è possibile citare di nuovo il libro domain driven design di Eric Evans:
Livello applicazione: Definisce i processi che il software deve eseguire e indirizza gli oggetti di dominio espressivi a risolvere i problemi. Le attività di questo livello sono significative per l'azienda o necessarie per l'interazione con i livelli dell'applicazione di altri sistemi. Questo strato viene mantenuto sottile. Non contiene regole aziendali o conoscenze, ma coordina solo le attività e delega il lavoro a collaborazioni di oggetti di dominio nel livello inferiore. Non riflette lo stato della situazione aziendale, ma può riflettere il progresso di un'attività per l'utente o il programma.
Il livello dell'applicazione di un microservizio in .NET viene comunemente codificato come progetto api Web di ASP.NET Core. Il progetto implementa l'interazione del microservizio, l'accesso alla rete remota e le API Web esterne usate dall'interfaccia utente o dalle app client. Include query se si usa un approccio CQRS, i comandi accettati dal microservizio e anche la comunicazione guidata dagli eventi tra microservizi (eventi di integrazione). L'API Web di base ASP.NET che rappresenta il livello applicazione non deve contenere regole business o conoscenze sul dominio (in particolare regole di dominio per transazioni o aggiornamenti); devono essere di proprietà della libreria di classi del modello di dominio. Il livello applicazione deve coordinare solo le attività e non deve contenere o definire alcuno stato di dominio (modello di dominio). Delega l'esecuzione delle regole business alle classi del modello di dominio stesse (radici di aggregazione e entità di dominio), che aggiorneranno infine i dati all'interno di tali entità di dominio.
In pratica, la logica dell'applicazione è la posizione in cui si implementano tutti i casi d'uso che dipendono da un determinato front-end. Ad esempio, l'implementazione correlata a un servizio API Web.
L'obiettivo è che la logica di dominio nel livello del modello di dominio, le relative invarianti, il modello di dati e le regole business correlate devono essere completamente indipendenti dai livelli presentazione e applicazione. Soprattutto, il livello del modello di dominio non deve dipendere direttamente da alcun framework di infrastruttura.
Il livello dell'infrastruttura
Il livello dell'infrastruttura è il modo in cui i dati inizialmente contenuti nelle entità di dominio (in memoria) vengono mantenuti nei database o in un altro archivio permanente. Un esempio è l'uso del codice Entity Framework Core per implementare le classi di criteri di repository che usano un DBContext per rendere persistenti i dati in un database relazionale.
In conformità ai principi di persistenza e di ignoranza dell'infrastruttura menzionati in precedenza, il livello dell'infrastruttura non deve "contaminare" il livello del modello di dominio. È necessario mantenere indipendenti le classi di entità del modello di dominio dall'infrastruttura usata per rendere persistenti i dati (EF o qualsiasi altro framework) non prendendo dipendenze difficili dai framework. La libreria di classi del livello del modello di dominio deve avere solo il codice di dominio, solo le classi di entità POCO che implementano il cuore del software e completamente disaccoppiate dalle tecnologie dell'infrastruttura.
Pertanto, i livelli o le librerie di classi e i progetti devono dipendere in definitiva dal livello del modello di dominio (libreria), non viceversa, come illustrato nella figura 7-7.
Figura 7-7. Dipendenze tra livelli in DDD
Le dipendenze in un servizio DDD, il Livello Applicazione dipende da Dominio e Infrastruttura e l'Infrastruttura dipende dal Dominio, ma il Dominio non dipende da nessun livello. La progettazione di questo livello deve essere indipendente per ogni microservizio. Come indicato in precedenza, è possibile implementare i microservizi più complessi seguendo i modelli DDD, implementando microservizi più semplici basati sui dati (crud semplice in un singolo livello) in modo più semplice.
Risorse aggiuntive
DevIQ. Principio di ignoranza della persistenza
https://deviq.com/persistence-ignorance/Oren Eini. Ignoranza dell'infrastruttura
https://ayende.com/blog/3137/infrastructure-ignoranceAngel Lopez. Architettura a più livelli nella progettazione di Domain-Driven
https://ajlopez.wordpress.com/2008/09/12/layered-architecture-in-domain-driven-design/