Recentemente mi è stato chiesto di realizzare uno spike1 per valutare la fattibilità nella realizzazione di un’architettura micro frontends con Blazor Server.

Ti dico subito che è stato un fallimento; ma andiamo con ordine, analizzando dapprima la declinazione del termine fallimento e le ragioni che mi hanno portato ad usarlo per poi cercare di ricapitolare quanto emerso da questa esplorazione che mi ha fatto giungere a questa conclusione.

Mi piace molto la definizione che da Treccani.

Riconoscere l’inutilità dei propri sforzi, l’impossibilità e incapacità di raggiungere gli scopi fissati, rinunciando definitivamente alla lotta, all’azione.

Treccani

Lo trovo particolarmente appropriato perché utilizza il termine scopi fissati, e quindi quali sono questi scopi?

Il contesto conta.

Nulla si fa per caso, e questa non è certo un’eccezione. Il lavoro svolto è parte di un contesto più ampio che riguarda la necessità di migrare una serie di applicativi ASP.NET MVC 5 ad ASP.NET Core combinata alla volontà di rendere l’attuale architettura più flessibile introducendo il concetto di programmazione modulare2.

Senza girarci troppo intorno, lo scopo finale era quello di misurare la fattibilità di “realizzare” un’architettura a micro frontends renderizzati lato server grazie a Blazor Server.

A tal proposito sul blog di Martin Fowler è presente un articolo bell’articolo di Cam Jackson nel quale viene fatta una panoramica su questa architettura e dal quale ho tradotto la loro definizione di micro frontends

Uno stile architettonico in cui le applicazioni frontend, consegnabili in modo indipendente, sono composte in un insieme più grande.

Thoughtworks su martinfowler.com

Ho messo realizzare fra virgolette in quanto la pubblicazione dei vari siti sarebbe avvenuta sempre e soltanto in modo unitario.
Magari affronteremmo questo problema in un prossimo post.

Non tutte le ciambelle riescono col buco.

Andando dritti al punto, la motivazione principe che ha decretato il fallimento è legata all’impossibilità di dare completa autonomia ai team, per due principali motivi ben precisi.

Omonimia nel supporto alle pagine ed alle viste Razor.

Per comporre il sito ogni frontend viene contenuto all’interno di una libreria di classi Razor la quale contiene anche la vista che si occupa di fare hosting dell’applicazione Blazor.

Questo è reso possibile grazie alla funzionalità esposta dal SDK che consente ad una web app di utilizzare viste, pagine Razor o layout da librerie di classi e, come definito nella documentazione ufficiale, in caso di omonimia la precedenza viene data alla vista, pagina, layout presente nella web app.

Nel mio caso mi trovo in una situazione del genere

Figura 1: una applicazione ASP.NET Core che referenzia due Razor Class Library che rappresentano due moduli.

Figura 1: una applicazione ASP.NET Core che referenzia due Razor Class Library che rappresentano due moduli.

dove entrambi i moduli internamente fanno uso di layout contenuti al percorso /Pages/Shared/_Layout.cshtml.

Ecco, in questo caso accadrebbe che uno dei due team sarebbe scontento in quanto, se andasse bene vedrebbe la sua applicazione renderizzata all’interno di un altro layout, nel peggiore dei casi una parte o tutte le viste andrebbero in errore (es. una vista cerca di valorizzare una sezione non dichiarata nel layout).
E notiamo bene che entrambi i moduli eseguiti indipendentemente si comporterebbero come atteso.

Le rotte, il percorso di base che non vuole funzionare.

Ho che almeno io non sono riuscito a far funzionare.

Anche in questo caso, seguendo il principio dell’autonomia, il desiderata era quello di separare le rotte del modulo da quelle del contenitore, per esempio all’interno del Modulo A avremmo trovato / oppure /index mentre dal punto di vista del contenitore le rotte sarebbero state /module-a/ o /module-a/index.

Quello che ho trovato è stata una “coperta corta”, quando funzionava la navigazione interna al modulo non funzionava la generazione di rotte utilizzando Anchor Tag Helper (ricordo che questo spike è frutto di un processo di migrazione), in quanto per la realizzazione del requisito ho utilizzato il middleware UsePathBaseMiddleware.

Questo ha comportato che nella generazione dei link all’interno del modulo verso l’esterno venisse aggiunto sempre il /module-a in testa all’indirizzo anche quanto il collegamento avrebbe dovuto semplicemente puntare la contenitore.

Diversamente utilizzando il middleware sarei stato costretto ad utilizzare il nome del modulo in testa a tutte le direttive @page.

Conclusioni.

Tirando le somme di quanto fatto e ragionando a mente fredda potrei dire che qualcosa di buono ce lo possiamo comunque portare a casa, infatti, non abilitando il supporto alle pagine e viste Razor in una RCL3 ed evitando l’utilizzo di Anchor Tag Helper nel markup HTML che contribuisce al rendering della vista non incorreremmo in questi problemi.


  1. Uno spike è un metodo di sviluppo del prodotto originato dalla programmazione estrema che utilizza il programma più semplice possibile per esplorare potenziali soluzioni. Fonte Wikipedia↩︎

  2. La programmazione modulare è una tecnica di progettazione software che enfatizza la separazione della funzionalità di un programma in moduli indipendenti e intercambiabili, in modo tale che ognuno contenga tutto il necessario per eseguire solo un aspetto della funzionalità desiderata. Fonte Wikipedia↩︎

  3. Le librerie di classi Razor (RCL) sono state introdotte in ASP.NET Core 2.1 come metodo per impacchettare e distribuire componenti dell’interfaccia utente da referenziare e utilizzare all’interno di un’applicazione host. ↩︎