L’utilizzo del cloud non porta di per sé vantaggi in termini di scalabilità e flessibilità se non è accompagnato da un design delle applicazioni che permetta di sfruttare al massimo le funzionalità offerte dalle infrastrutture cloud. Per raggiungere questo scopo è necessario abbandonare l’approccio monolitico nello sviluppo delle applicazioni in favore di soluzioni che permettano di sfruttare tutte le potenzialità del cloud come ad esempio impiegando servizi del tipo “Function as a Service” quali le Lambda di AWS, le Cloud Functions di Google Cloud e le Functions di Microsoft Azure. 

Nello sviluppo delle nostre applicazioni web in ambito cloud utilizziamo una architettura a microservizi. L’utilizzo di tale architettura  offre molti vantaggi in termini di manutenibilità, flessibilità, scalabilità e disponibilità.

In questo breve articolo diamo una panoramica sulle differenze tra una soluzione software monolitica e una modulare per poi, più nello specifico, illustrare le caratteristiche delle architetture a microservizi.

 

Principali obiettivi nello sviluppo del software

Gli obiettivi principali che ci poniamo nello sviluppo di una applicazione sono, oltre ovviamente al rispetto dei requisiti funzionali, di sicurezza e all’assenza di bug, quelli di costruire un software facilmente manutenibile e modificabile per permettere di soddisfare requisiti futuri senza dover stravolgere l’implementazione iniziale. Oltre a questo vogliamo sviluppare applicazioni scalabili e resilienti con implicazioni nelle scelte delle architetture software e nelle infrastrutture.

Per questo motivo vengono periodicamente proposti nuovi paradigmi architetturali e design pattern che, se utilizzati correttamente, permettono di raggiungere gli obiettivi prefissati. Ovviamente il continuo cambiamento di tecnologie e requisiti finali delle applicazioni porta alla nascita di nuovi approcci e nuovi paradigmi nella progettazione e nello sviluppo del software.

L’approccio più comune è quello di sviluppare le applicazioni  in modo “monolitico”, ovvero creando  un unico software contenente tutte le funzionalità richieste. In questo tipo di soluzioni le varie funzionalità offerte dall’applicazione sono generalmente sfruttate solo per gli scopi dell’applicazione stessa, presentando modalità di accesso spesso valide solo per le finalità della soluzione monolitica, non permettendone così un riuso, all’esterno di questa.

Con il tempo gli sviluppatori hanno iniziato a riconoscere il beneficio della modularità nelle architetture, un chiaro esempio è il noto design pattern MVC (Model-View-Controller) nel caso delle interazioni tra frontend e backend. Questo pattern è un pilastro fondante di ogni nuovo framework che permette di avere una separazione chiara tra i il modello dati, la loro elaborazione (business logic) e la loro visualizzazione. La separazione di questi elementi permette ai team di sviluppo di modificare con poco impegno l’aspetto grafico dell’applicazione senza sconvolgere i processi.

Questo approccio non risolve però alcuni problemi intrinseci di un’architettura monolitica in quanto manca una chiara separazione di responsabilità nel back-end, per le varie funzionalità che questo realizza, e risolve quindi solo in parte il problema e costringendo, ad esempio, a prevedere il testing completo dell’applicazione ad ogni modifica, rallentando così la messa in produzione di nuove versioni. 

 

I vantaggi di un approccio modulare

Per questo motivo un trend degli ultimi anni è quello di utilizzare un approccio modulare nello sviluppo del software, isolando le varie responsabilità realizzate dalla business logic di una applicazione, separandole in moduli distinti, permettendo ad ogni modulo di offrire le proprie funzionalità attraverso un servizio che espone una semplice interfaccia (API) che ne permetta il riuso. 

Alcuni vantaggi di un approccio modulare sono ad esempio:

 – Separazione delle responsabilità: ogni modulo è responsabile di un determinato set di operazioni. Il suo sviluppo è indipendente dagli altri moduli. Può essere sviluppato e testato indipendentemente dagli altri moduli ed ha un suo proprio ciclo di vita.

 – Maggiore manutenibilità: I moduli sono piccoli e più semplici da capire rispetto alla soluzione monolitica in quanto lo sviluppatore deve preoccuparsi di un insieme di concetti ridotto, solo quelli che interessano il micro servizio e che sono dichiarati nel contratto rappresentato dalle sue API. Un eventuale problema è confinato su un determinato modulo e potrà quindi essere analizzato e corretto in modo più semplice e puntuale.

– Riutilizzo: una volta che una determinata funzionalità è stata incapsulata in un servizio potrà essere riutilizzata non soltanto all’interno di un’applicazione specifica ma anche da altre applicazioni che necessitano della stessa funzionalità (pensiamo ad esempio ad un modulo di gestione di un calendario).

 

L’architettura a microservizi si rende particolarmente indicata nello sviluppo in ambiente cloud, nel quale fornisce maggiori vantaggi. A seconda infatti delle specifiche funzionalità del micro servizio questo potrà utilizzare la soluzione cloud PaaS (Platform as a service) più adatta (function-as-a-service, microapp, message based communication, etc.). 

 

Inoltre, a seconda della business logic che il micro servizio dovrà implementare potrà scegliere la base di dati più adatta, sia essa un classico database relazionale, un database noSQL o un bucket di file.

Un vantaggio che ne deriva è legato alla scalabilità. Immaginiamo infatti che la nostra applicazione debba improvvisamente supportare un carico maggiore e che questo carico interessi soltanto un certo numero di funzionalità. In un approccio monolitico o comunque in un approccio dove le risorse non sono allocabili in maniera indipendente alle funzionalità offerte, si dovrà fornire maggiori risorse all’intera applicazione con inutile aumento dei costi complessivi (scaling verticale). In un approccio a microservizi, invece, basterà far scalare, in modo puntuale e soltanto quando è necessario, lo specifico micro servizio interessato (scaling orizzontale). Il micro servizio partirà infatti soltanto quando invocato, utilizzerà le risorse del cloud soltanto per il tempo di vita, più un overhead di start-up, e scalerà a seconda della particolare richiesta.

A questo scopo le piattaforme cloud dispongonooffrono, con le varie soluzioni PaaS, di molti strumenti per facilitare la prototipazione di tali servizi, offrendo tool per la gestione di scaling, availability (load balancing, controllo del traffico e delle istanze necessarie, etc.), configurazione e soluzioni off-the-shelf per problemi comuni come l’autenticazione e l’integrazione tra microservizi (e.g.: sistemi di messaging).

 

Criticità da considerare nell’uso di architetture a microservizi

Non bisogna pensare però all’architettura a microservizi come alla soluzione di ogni problema. Maggiore flessibilità e scalabilità sono ottenute ovviamente in cambio di una maggiore complessità. 

Tale complessità si manifesta principalmente nella fase di design della API del micro servizio e si deve principalmente a due aspetti:

 – Riuso: al fine di garantire il riuso del servizio, quest’ultimo dovrà essere epurato da elementi non necessari che fanno parte dell’applicazione monolitica, rendendolo un servizio standalone.

 – Gestione delle condizioni di errore – Manutenzione/Monitoraggio: in una architettura composta da vari microservizi può essere complicato stabilire quale servizio sia all’origine dell’errore. A questo scopo le piattaforme di cloud già offrono strumenti che permettono di mitigare questo problema. E’ importante tuttavia che l’API del servizio sia definita in maniera esaustiva, dichiarando nella propria documentazione: regole di validazione di input, formato degli output, eventuali condizioni di errore.

 

Il team di sviluppo di Wondersys