Un gatto circondato da gomitoli

Dipanare la matassa con Roslyn

Ti è stato chiesto di migliorare un sistema complicato di cui non conosci assolutamente nulla. Come capisci dove mettere la zampa?

Durante una consulenza, a volte ci capita di esaminare grossi sistemi che sono stati sviluppati nel corso degli anni con visioni e obiettivi differenti. In genere, ci viene chiesto di:

  • modernizzare il sistema, sostituendo vecchie tecnologie non più supportate dai produttori;
  • fornire dei suggerimenti architetturali, in modo che il sistema diventi più manutenibile;
  • suggerire migliorie alla qualità del codice, anche mediante test e documentazione, così che il numero di bug in produzione si riduca;
  • aumentare la modularità, identificando le responsabilità di ogni parte del sistema (in un precedente articolo vi abbiamo parlato del come spezzare un monolite).

Prima di agire, dobbiamo comprendere il funzionamento del sistema.
Così non rischieremo di rompere il delicato meccanismo che lo regola.

Affinché sia possibile offrire una consulenza efficace su questi temi, è utile impiegare una tecnica che – innanzitutto – ci permetta di acquisire la conoscenza che ci serve a decidere.

Trovare il filo

Alcuni sistemi non si lasciano sondare facilmente, soprattutto se sono composti da decine di progetti decennali la cui interazione non è immediatamente chiara:

  • la mancanza di documentazione rende la questione di certo più complicata;
  • le persone che hanno contribuito allo sviluppo potrebbero non essere più reperibili per darci informazioni.

Col passare degli anni, è inevitabile che parte della conoscenza vada persa e perciò dovrà essere recuperata in qualche modo.

Un gatto osserva un gomitolo nascosto sotto un divano

Quando le informazioni sono scarse, un sistema può apparire come una matassa formata da fili di vario colore e consistenza. In superficie riusciamo a vederli ma i punti in cui si intrecciano sono veramente tanti e la maggior parte di essi resta celata all’interno.

Per lavorare la matassa, dobbiamo innanzitutto dipanarla.

Possiamo rigirare la matassa tra le dita fino a trovare il capo di un filo. A questo punto lo seguiamo per scoprire in quali punti si intreccia agli altri, quindi lo districhiamo e ne facciamo un bel gomitolo uniforme. È un’attività complicata ma non complessa perché basta solo dotarsi di pazienza e meticolosità.

L'attenzione di un gatto è attirata dal filo di un gomitolo

Il software non è tangibile come i fili di una matassa, ma possiamo comunque arrivare a scoprire quali sono i punti di contatto tra i vari componenti. L’obiettivo è produrre una prima forma di documentazione tecnica che ci aiuti a orientarci nel sistema.

Investire in questa attività di analisi ci aiuterà a capire come interagiscano i vari componenti del sistema.

Il livello di comprensione che acquisiremo sarà essenziale affinché si possano formulare strategie d’intervento valide, che possano aiutare il committente in maniera significativa.

Dipanare la matassa

La .NET compiler platform, anche chiamata con il nome in codice “Roslyn”, offre un insieme di API ci permettono anche di fare analisi statica del codice. Referenziando i suoi pacchetti NuGet da una nostra applicazione console, sfrutteremo la Roslyn API per esaminare un qualsiasi progetto o soluzione .NET (C# o VB.NET). Si tratta di un’attività di meta-programmazione che ci permetterà di estrarre informazioni da uno o più progetti.

Usando la Roslyn API possiamo agire in vari modi, come ad esempio:

  • esaminare gli alberi sintattici, cioè le strutture dati che Roslyn API ottiene facendo il parsing dei nostri file di codice. Con LINQ interroghiamo tali alberi sintattici per elencare i tipi presenti nel progetto (classi, struct, enum, …) o i loro membri, eventualmente filtrandoli in base ai loro modificatori di accesso (public, private, …) o in base a criteri personalizzati;
  • riscrivere gli alberi sintattici, nel caso in cui volessimo modificare il codice del progetto in maniera massiva, come ad esempio aggiungere un’istruzione in membri specifici;
  • cercare nel modello semantico, cioè nella struttura dati in cui troveremo informazioni sul significato e sulle relazioni tra i simboli che compongono il nostro progetto. Ad esempio, possiamo elencare tutti i riferimenti a un membro di una nostra classe;
  • ottenere informazioni diagnostiche che evidenzieranno imprecisioni o parti di codice inutile, come ad esempio using namespace non necessari.

Su GitHub trovi alcuni esempi per iniziare con Roslyn API

https://github.com/Moreno-Gentili/RoslynSamples

Inoltre, Microsoft mette a disposizione un comodo Syntax Visualizer integrato in Visual Studio che offre una chiara presentazione di come sia strutturato l’albero sintattico di un nostro file di codice. Grazie ad esso, sarà più facile capire dove trovare le informazioni che ci servono.

Il Syntax Visualizer si pone fianco dell’editor, così che risulti chiaro cosa “vede” Roslyn API e come sia strutturato l’albero sintattico ottenuto dal parsing del nostro codice.

Ottenere i gomitoli

Da questa attività di analisi possiamo ottenere un insieme di dati grezzi, come la seguente tabella, che elenca i riferimenti tra i membri, comprensivi dei nomi dei progetti a cui appartengono e delle rispettive linee di codice.

Da una nostra applicazione console, possiamo esaminare un progetto C# e produrre un file CSV che elenchi i riferimenti ai membri che ci interessa tracciare.

In questo modo avremo visualizzato i punti in cui i fili della nostra matassa si intrecciano: possiamo ora cominciare a dipanarli.

Importando i dati in Excel o in un database, potremo interrogarli in base alle necessità. Ad esempio potremmo eseguire delle aggregazioni per:

  • scoprire quali sono i riferimenti più usati, cioè quelli che rappresentano i punti nevralgici del sistema;
  • evidenziare anomalie architetturali, come ad esempio view che usano direttamente servizi infrastrutturali, evitando la logica applicativa;
  • trovare duplicazioni nel codice e scovare i componenti con troppe responsabilità.

Il maggior potere informativo lo abbiamo importando i dati
in strumenti di business intelligence

Importando i dati grezzi in strumenti come Microsoft Power BI, potremo sfruttare le sue capacità di visualizzazione. Un diagramma Sankey, ad esempio, ci offre una visione d’insieme che letteralmente ci fa apprezzare i vari fili che legano un progetto all’altro.

Un diagramma Sankey porta alla luce eventuali punti da chiarire con il committente: come mai la view del carrello usa direttamente un servizio infrastrutturale per accedere ai dati?

Volendo approfondire ulteriormente le relazioni che esistono tra i componenti software, possiamo anche avvalerci di un graph database come Neo4j. Usando il suo graph query language, potremo ottenere diagrammi che mostrano in maniera chiara e dettagliata le varie dipendenze.

I risultati di una query in Neo4j sono interattivi, perciò i singoli nodi e le loro relazioni sono cliccabili per accedere alle altre informazioni che portano con sé.

Pronti per sferruzzare

Le informazioni che avremo ottenuto con questa attività di analisi serviranno sia ad integrare l’eventuale documentazione esistente, sia a porre il sistema stesso sotto nuova luce, così che venga maggiormente percepito come un insieme di gomitoli discreti e uniformi piuttosto che come una matassa. Avremo acquisito una padronanza maggiore sul sistema e gettato le basi per iniziare il lavoro in maniera più consapevole e sicura.