Luca Morelli
Software engineer e analista
Team lead

Sviluppo software .NET: definire l'architettura o lavorare dentro quella esistente.

Ho definito l'architettura nei progetti di cui avevo la responsabilità tecnica, come C-06 e C-07, progetti di lunga durata seguiti da unico sviluppatore. Gli altri casi recenti raccontano incarichi di consulenza, in cui sono entrato in team e prodotti già avviati. Il mio margine di scelta cambia molto tra queste due situazioni, e di conseguenza cambia anche il modo in cui applico metodi e pattern.

Quando progettoScelgo struttura e tecnologie in base al problema, ai vincoli e a chi manterrà il sistema.
Quando entro in un prodottoCapisco le scelte esistenti, seguo le convenzioni del team e contribuisco nel perimetro assegnato.

Due contesti di lavoro

01

Quando definisco l'architettura

Negli incarichi in cui mi è affidata la progettazione, definisco le scelte architetturali e ne assumo la responsabilità.

Parto dalle esigenze e dai vincoli, poi definisco i confini dei moduli, lo stack e il modo in cui le parti comunicano. Considero fin dall'inizio chi dovrà sviluppare, verificare e mantenere il sistema. Introduco un pattern quando risolve un problema concreto o rende più semplice l'evoluzione dell'applicazione.

Le scelte che valuto

  • Responsabilità e confini dei moduli
  • Regole di dominio e casi d'uso
  • Persistenza e integrazioni esterne
  • Testabilità, rilasci e manutenzione
02

Quando entro in un prodotto esistente

Nei progetti di consulenza l'architettura e le linee guida sono spesso già definite.

Il mio primo compito è capire il sistema: convenzioni, dipendenze, flussi tra servizi e ragioni delle scelte fatte. Seguo analisi, sviluppo e verifica dei task che mi vengono affidati, coordinandomi con il team. Se individuo un problema strutturale, propongo un intervento compatibile con il progetto e con il ruolo di chi ne governa l'architettura.

Questa è la situazione rappresentata dalla maggior parte dei casi pubblicati sul sito. La pagina sulle modalità di lavoro descrive più in dettaglio il mio perimetro nei diversi ruoli.

Il mio contributo

  • Analisi del task nel contesto del sistema
  • Sviluppo coerente con gli standard del team
  • Test e controllo delle regressioni
  • Proposte tecniche quando c'è spazio per migliorare una parte del sistema

Un esempio: far crescere un'applicazione senza frammentarla

In C-06 ho definito l'architettura e la faccio evolvere dal 2013, da unico sviluppatore.

I dati sono di due tipi: quelli nel database e i dati di progetto, scritti su file e gestiti da una libreria dedicata. All'inizio tutta la parte applicativa era concentrata in un unico blocco, e con la crescita del carico questo è diventato un problema.

Non ho riscritto il sistema né l'ho diviso in molti servizi. Con il cliente e il suo personale abbiamo analizzato i flussi e individuato i colli di bottiglia; poi ho separato solo ciò che lo giustificava:

  1. la gestione dei dati di progetto, spostata su un server separato;
  2. i processi di lunga durata, affidati a una coda RabbitMQ e a programmi che elaborano le richieste;
  3. il backend principale, rimasto a servire le API legate al database e diventato il punto di ingresso unico per le altre richieste (API gateway);
  4. la migrazione graduale del codice di backend da .NET Framework a .NET;
  5. una cache Redis nella gestione dei progetti, per non ripetere operazioni che a breve distanza danno lo stesso risultato.

Nel tempo si è aggiunta un'app Android per seguire le attività sul territorio: ha richiesto una Web API che riceve i dati grezzi dai dispositivi e un servizio che li elabora e li prepara per le analisi successive.

Il carico sul nucleo principale è diminuito e le prestazioni sono migliorate, con pochi componenti in più da gestire. Ogni componente separato aggiunge complessità e costi di gestione: l'ho introdotto solo dove il vantaggio era evidente.

La migrazione a .NET rende anche il monitoraggio più completo: oltre al codice dell'applicazione, le librerie di .NET producono già tracce e misure, che si raccolgono con poca configurazione. Il prossimo passo che sto valutando è estendere questa copertura con OpenTelemetry, per basare il monitoraggio su strumenti standard invece che su soluzioni scritte apposta.

Backend e frontend

Lavoro nello sviluppo software da quasi trent'anni. Il mio riferimento principale è l'ecosistema Microsoft, affiancato dalle tecnologie web richieste dai progetti.

Sul backend lavoro soprattutto con .NET e ASP.NET Core: API, regole applicative, dati e integrazioni. Ho seguito l'evoluzione dalla piattaforma .NET Framework alle versioni attuali, lavorando sia per piccole e medie imprese sia in contesti enterprise.

Sul frontend ho una lunga esperienza con Angular: prima AngularJS, poi Angular fin dalle sue prime versioni. Ho utilizzato anche React in progetti di grandi dimensioni. La scelta dello strumento dipende dal prodotto e dal team; in entrambi i casi mi interessa costruire interfacce che restino gestibili quando crescono funzionalità e persone coinvolte.

Organizzare il codice quando ho margine di scelta

Non parto dal nome di un'architettura: parto dalle regole che il codice deve esprimere e dalle modifiche che dovrà sostenere.

Dove la logica di business è significativa, tengo separate le regole dell'attività del cliente dai dettagli tecnici (database, messaggistica, API esterne), secondo i principi della Clean Architecture. Spesso organizzo il codice per funzionalità, con un approccio Vertical Slice: chi interviene su una feature ne segue il percorso senza cercare i file in cartelle lontane.

Uso dependency injection per rendere esplicite le dipendenze e separo comandi, query e relativi handler quando questo chiarisce i casi d'uso. Sono strumenti da dosare: in una funzione semplice, aggiungere livelli e astrazioni può rendere il codice più difficile da seguire.

Microservizi e comunicazione a eventi

Separare i moduli di un'applicazione e distribuire servizi indipendenti sono scelte diverse.

Valuto i microservizi quando esistono confini funzionali chiari e un vantaggio concreto nel far evolvere o rilasciare le parti separatamente. Questa autonomia ha un costo: comunicazioni di rete, gestione degli errori, monitoraggio e coordinamento dei rilasci. In altri contesti può essere più adatta un'applicazione unica, ma organizzata in moduli ben distinti.

Ho lavorato in progetti con comunicazioni asincrone basate su Azure Service Bus o RabbitMQ; nei prodotti esistenti ho contribuito alle integrazioni e alla diagnosi dei flussi. Il disaccoppiamento richiede attenzione a ritardi, messaggi duplicati, errori e tracciabilità.

Dominio e test

Le regole importanti devono essere comprensibili a chi conosce il prodotto e verificabili nel tempo.

Uso le idee del Domain-Driven Design nella misura richiesta dal problema: linguaggio condiviso con gli esperti del prodotto, confini tra ambiti funzionali e regole di business collocate dove possano essere comprese e testate. Non ogni applicazione richiede tutti i pattern DDD.

I test automatici servono a verificare il comportamento e a proteggere le modifiche successive. Uso il TDD quando scrivere prima il test aiuta a precisare una regola o un caso limite; in altre situazioni aggiungo test durante lo sviluppo o riproduco un bug con un test prima di correggerlo. I test permettono anche di verificare un'API prima che il client sia pronto. Nei progetti in cui i test sono una condizione per approvare la pull request, seguo i requisiti previsti dal team. Una copertura alta, da sola, non garantisce test di qualità.

Complessità proporzionata al problema

L'architettura deve aiutare il progetto a crescere, non diventare un fine in sé.

Un sistema che scambia eventi non richiede necessariamente event sourcing: aggiunge lavoro su versionamento e gestione nel tempo, e lo valuterei solo davanti a un'esigenza concreta.

Applico lo stesso criterio a livelli, pattern e servizi distribuiti: parto da una struttura proporzionata e la faccio evolvere quando emergono regole, confini o carichi che giustificano una soluzione più articolata. Nei progetti che guido, ne assumo le scelte; quando lavoro in un prodotto altrui, contribuisco a migliorarlo rispettando responsabilità e vincoli del team.

Software architect e solution architect nel cloud

Serve progettare un'applicazione o far evolvere un prodotto esistente?

Curriculum dettagliato e referenze su richiesta.