Eseguire la migrazione di un'applicazione monolitica ai microservizi usando la progettazione basata su dominio

ASP.NET

Questo articolo descrive come usare la progettazione basata su dominio (DDD) per eseguire la migrazione di un'applicazione monolitica ai microservizi.

Un'applicazione monolitica è in genere un sistema applicativo in cui tutti i moduli pertinenti vengono inseriti in un pacchetto come singola unità di esecuzione distribuibile. Ad esempio, potrebbe trattarsi di un'applicazione Web Java (WAR) in esecuzione in Tomcat o in un ASP.Applicazione NET in esecuzione in IIS. Un'applicazione monolitica tipica usa una progettazione a più livelli, con livelli separati per l'interfaccia utente, la logica dell'applicazione e l'accesso ai dati.

Architettura monolitica tipica

Questi sistemi iniziano di piccole dimensioni, ma tendono a crescere nel tempo per soddisfare le esigenze aziendali. A un certo punto, man mano che vengono aggiunte nuove funzionalità, un'applicazione monolitica può iniziare a soffrire dei problemi seguenti:

  • Le singole parti del sistema non possono essere ridimensionate in modo indipendente, perché sono strettamente associate.
  • È difficile gestire il codice, a causa di un accoppiamento stretto e di dipendenze nascoste.
  • Il test diventa più difficile, aumentando la probabilità di introdurre vulnerabilità.

Questi problemi possono diventare un ostacolo alla crescita e alla stabilità future. I team diventano diffidenti di apportare modifiche, soprattutto se gli sviluppatori originali non lavorano più sul progetto e i documenti di progettazione sono di tipo sparse o obsoleto.

Nonostante queste limitazioni, un design monolitico può essere utile come punto di partenza per un'applicazione. I monoliti sono spesso il percorso più rapido per creare un modello di verifica o un prodotto minimo funzionante. Nelle prime fasi di sviluppo, i monoliti tendono a essere:

  • Più facile da compilare, perché è presente una singola codebase condivisa.
  • Più semplice eseguire il debug, perché il codice viene eseguito all'interno di un singolo processo e spazio di memoria.
  • Più facile da ragionare, perché ci sono meno parti in movimento.

Con l'aumentare della complessità dell'applicazione, tuttavia, questi vantaggi possono scomparire. I monoliti di grandi dimensioni spesso diventano progressivamente più difficili da compilare, eseguire il debug e il motivo. A un certo punto, i problemi superano i benefici. Questo è il punto in cui può essere utile eseguire la migrazione dell'applicazione a un'architettura di microservizi. A differenza dei monoliti, i microservizi sono in genere decentralizzati, unità di esecuzione ad accoppiamento libero. Il diagramma seguente illustra un'architettura tipica di microservizi:

Architettura di microservizi tipica

La migrazione di un monolith a un microservizio richiede tempo e investimenti significativi per evitare errori o sovraccarichi. Per garantire che qualsiasi migrazione riesca, è consigliabile comprendere sia i vantaggi che le sfide che i microservizi comportano. I vantaggi includono:

  • I servizi possono evolversi in modo indipendente in base alle esigenze degli utenti.
  • I servizi possono essere ridimensionati in modo indipendente per soddisfare la domanda degli utenti.
  • Nel corso del tempo, i cicli di sviluppo diventano più veloci man mano che le funzionalità possono essere rilasciate sul mercato più rapidamente.
  • I servizi sono isolati e sono più tolleranti di errore.
  • Un singolo servizio che non riesce non comporta l'arresto dell'intera applicazione.
  • I test diventano più coerenti e coerenti, usando lo sviluppo basato sul comportamento.

Per altre informazioni sui vantaggi e sulle sfide dei microservizi, vedere Stile dell'architettura dei microservizi.

Applicare la progettazione basata su dominio

Qualsiasi strategia di migrazione deve consentire ai team di effettuare il refactoring incrementale dell'applicazione in servizi più piccoli, garantendo comunque la continuità del servizio agli utenti finali. Ecco l'approccio generale:

  • Interrompere l'aggiunta di funzionalità al monolitico.
  • Dividere il front-end dal back-end.
  • Scomporre e separare il monolitico in una serie di microservizi.

Per facilitare questa scomposizione, un approccio di sviluppo software praticabile consiste nell'applicare i principi della progettazione basata su dominio (DDD).

Domain Driven Design (DDD) è un approccio di sviluppo software introdotto prima da Eric Evans. DDD si oppone all'idea di avere un unico modello unificato per l'intero sistema. Incoraggia invece la divisione del sistema in contesti delimitati, ognuno dei quali ha un proprio modello. DDD richiede una buona conoscenza del dominio per il quale verrà scritta l'applicazione. Le conoscenze di dominio necessarie per creare l'applicazione si trovano all'interno delle persone che lo comprendono, ovvero gli esperti di dominio.

L'approccio DDD può essere applicato retroattivamente a un'applicazione esistente, in modo da iniziare a scomporre l'applicazione.

  1. Iniziare con un linguaggio comune, un vocabolario comune condiviso tra tutti gli stakeholder.

  2. Identificare i moduli pertinenti nell'applicazione monolitica e applicarli al vocabolario comune.

  3. Definire i modelli di dominio dell'applicazione monolitica. Il modello di dominio è un modello astratto del dominio aziendale.

  4. Definire i contesti delimitati per i modelli. Un contesto delimitato è il limite all'interno di un dominio in cui si applica un particolare modello di dominio. Applicare limiti espliciti con modelli e responsabilità chiaramente definiti.

I contesti delimitati identificati nel passaggio 4 sono candidati per il refactoring in microservizi più piccoli. Il diagramma seguente mostra il monolitico esistente con i contesti delimitati sovrapposti:

Contesti delimitati all'interno di un monolitico

Per altre informazioni sull'uso di un approccio DDD per le architetture di microservizi, vedere Uso dell'analisi del dominio per modellare i microservizi.

Livello anti-danneggiamento (codice glue)

Anche se questo lavoro investigativo viene eseguito per inventariare l'applicazione monolitica, è possibile aggiungere nuove funzionalità applicando i principi di DDD come servizi separati. "Glue code" consente all'applicazione monolitica di eseguire il proxy delle chiamate al nuovo servizio per ottenere nuove funzionalità.

Livello anti-danneggiamento per consentire a un monolith di interagire con un nuovo servizio

Il livello anti-danneggiamento (modello di adattatore) agisce in modo efficace come livello anti-danneggiamento, assicurando che il nuovo servizio non sia danneggiato dai modelli di dati richiesti dall'applicazione monolitica. Il livello anti-danneggiamento consente di mediare le interazioni tra i due e garantisce che vengano passati solo i dati richiesti dal nuovo servizio per abilitare la compatibilità.

Tramite il processo di refactoring, i team possono inventariare l'applicazione monolitica e identificare i candidati per il refactoring dei microservizi, stabilendo al tempo stesso nuove funzionalità con nuovi servizi.

Per altre informazioni sui livelli anti-danneggiamento, vedere Modello di livello anti-danneggiamento.

Creare un livello di presentazione

Il passaggio successivo consiste nel separare il livello di presentazione dal livello back-end. In un'applicazione tradizionale a più livelli, il livello dell'applicazione (business) tende a essere i componenti principali dell'applicazione e ha la logica di dominio all'interno di essi. Queste API con granularità grossolana interagiscono con il livello di accesso ai dati per recuperare dati persistenti dall'interno di un database. Queste API stabiliscono un limite naturale per il livello di presentazione e consentono di disaccoppiare il livello di presentazione in uno spazio applicazione separato.

Il diagramma seguente mostra la suddivisione del livello presentazione (UI) dai livelli di accesso ai dati e alla logica dell'applicazione.

Schema gateway API

Questo diagramma introduce anche un altro livello, il gateway API, che si trova tra il livello di presentazione e la logica dell'applicazione. Il gateway API è un livello di facciata che fornisce un'interfaccia coerente e uniforme con cui interagire il livello presentazione, consentendo al contempo ai servizi downstream di evolversi in modo indipendente, senza influire sull'applicazione. Il gateway API può usare una tecnologia come Azure Gestione API e consente all'applicazione di interagire in modo RESTful.

Il livello di presentazione può essere sviluppato in qualsiasi linguaggio o framework in cui il team ha esperienza, ad esempio un'applicazione a pagina singola o un'applicazione MVC. Queste applicazioni interagiscono con i microservizi tramite il gateway, usando chiamate HTTP standard. Per altre informazioni sui gateway API, vedere Uso di gateway API nei microservizi.

Iniziare a ritirare il monolitico

In questa fase, il team può iniziare a rimuovere l'applicazione monolitica ed estrarre lentamente i servizi stabiliti dai contesti delimitati nel proprio set di microservizi. I microservizi possono esporre un'interfaccia RESTful con cui il livello dell'applicazione interagisce, tramite il gateway API, con il codice glue sul posto per comunicare con il monolith in circostanze specifiche.

Usare il livello API

Man mano che si continua a rimuovere il monolitico, alla fine ci sarà il punto in cui non è più necessario esistere e i microservizi sono stati estratti correttamente dal monolitico. A questo punto, il livello anti-danneggiamento (codice colla) può essere rimosso in modo sicuro.

Questo approccio è un esempio del modello Strangler Fig e consente una scomposizione controllata di un monolitico in un set di microservizi. Nel corso del tempo, man mano che le funzionalità esistenti si spostano in microservizi, il monolith ridurrà le dimensioni e la complessità, fino al punto in cui non esiste più.

Collaboratori

Questo articolo viene gestito da Microsoft. Originariamente è stato scritto dai seguenti contributori.

Autore principale:

Per visualizzare i profili LinkedIn non pubblici, accedere a LinkedIn.

Passaggi successivi

Quando l'applicazione è stata scomposta in microservizi costitutivi, è possibile usare strumenti di orchestrazione moderni, ad esempio Azure DevOps , per gestire il ciclo di vita di ogni servizio. Per altre informazioni, vedere CI/CD per le architetture di microservizi.