DDD, microservizi e architetture evolutive: architetture antifragili
Nel precedente articolo ho spiegato l’importanza delle architetture Event-Driven.
In questo episodio, che prende spunto da un mio scritto già pubblicato nella rivista MokaByte, tratterò il concetto di antifragilità applicato al mondo dell’agilità e delle scelte architetturali.
Agile & Architecture: un rapporto complicato
Giovanni Puliti, nell’articolo “Antifragile Manifesto” pubblicato su MokaByte, affronta il tema del Manifesto Antifragile; in particolare, risulta molto interessante il passaggio dedicato alla misurazione del rischio. Riprendendo il pensiero di Nassim Taleb in Il Cigno Nero, l’autore sottolinea come la gestione del rischio non coincida con lo studio di eventi prevedibili o programmabili, come spesso si crede, ma riguardi invece scenari incerti e non lineari, proprio come quelli descritti da Taleb. La riflessione si concentra sull’applicazione dei principi dell’antifragilità alle organizzazioni. Possiamo estendere questi stessi principi anche all’architettura dei sistemi?
Quando si parla di Agilità, il ruolo dell’architettura — o quello che dovrebbe avere — non rappresenta più solo un tema tecnico, ma diventa uno dei fattori che possono determinare il fallimento delle iniziative Agile. Spesso, la figura dell’architect ne esce indebolita. Un sondaggio condotto da IASA Global su un campione di 260 aziende evidenzia che oltre il 75% di esse ha adottato pratiche Agile. Tuttavia, meno del 50% ha integrato efficacemente l’architettura all’interno di tali processi. Ne emerge un quadro in cui Agile e Architettura faticano ancora a trovare un equilibrio collaborativo.
Il paper suggerisce una terza via: adottare l’Agile attraverso l’Antifragile. In altre parole, invece di cercare di controllare il cambiamento o rinunciare del tutto al controllo, si propone di costruire sistemi — tecnici e organizzativi — in grado di trarre beneficio dal cambiamento stesso. Questo approccio consente di realizzare architetture che non solo supportano l’Agilità, ma la abilitano attraverso la capacità di essere antifragili di fronte all’evoluzione continua.
VUCA: serve un nuovo approccio
La complessità del contesto attuale rende inefficaci molte delle pratiche riportate nei manuali risalenti a oltre vent’anni fa. Come afferma Nassim Taleb nei suoi libri (“Antifragile” e “Il cigno nero”), ciò di cui abbiamo bisogno non è un approccio che provi a controllare o gestire il caos, ma la capacità di progettare sistemi in grado di prosperare all’interno di esso.
Viviamo in un mondo in costante evoluzione: il business cambia rapidamente, così come le richieste dei clienti, che ci chiedono frequenti modifiche o nuove funzionalità per software già in uso — o ancora in fase di progettazione. Questo scenario è definito con l’acronimo VUCA, che identifica quattro caratteristiche chiave del contesto contemporaneo: Volatility, Uncertainty, Complexity, Ambiguity. La capacità di adattarsi e crescere in un contesto volatile e incerto è oggi più che mai fondamentale.
Siamo di fronte a una nuova fase della crisi del software, già evidenziata nel rapporto della NATO del 1968. Oggi, però, le implicazioni sembrano essere ancora più profonde e pervasive.
Come ci ricorda Nicholas Negroponte:
Computing is not about computers anymore. It’s about living.
Alla luce di queste considerazioni, diventa evidente che il mondo VUCA richiede un approccio radicalmente nuovo.
Accettare la complessità
All’inizio degli anni 2000, Dave Snowden, durante la sua attività in IBM, ha sviluppato una “infrastruttura concettuale” per analizzare e classificare la complessità: il framework Cynefin (/kəˈnɛvɪn/), termine gallese che significa habitat.
Secondo questo modello, i sistemi aziendali moderni non sono semplicemente complicati: sono complessi. Un sistema complesso non risponde in modo lineare agli input o ai cambiamenti. Per affrontare un problema di business, siamo portati a costruire un modello del sistema. Tuttavia, il modello è, per definizione, una semplificazione della realtà: non può replicare il mondo reale in ogni suo aspetto.
Come sottolinea efficacemente Rebecca Wirfs-Brock:
A model is a simplified representation of a thing or phenomenon that intentionally emphasizes certain aspects while ignoring others. Abstraction with a specific use in mind.
Accettare la natura complessa dei sistemi significa riconoscere i limiti della modellazione e imparare a muoversi in un contesto in cui incertezza e imprevedibilità sono la norma, non l’eccezione.
Cosa rende fragile un sistema?
I problemi emergono quando il modello semplificato della realtà diventa troppo distante dalla realtà stessa. In questi casi, le risposte che offre — se ancora riesce a fornirne — non sono più affidabili. È ciò che descrive Nassim Nicholas Taleb ne Il Cigno Nero.
I problemi di business rientrano nella categoria dei sistemi complessi. Hanno comportamenti imprevedibili, e tentare di affrontarli con pratiche inadatte conduce spesso al fallimento. È l’effetto di quella che Taleb chiama piega platonica: l’illusione che un modello teorico possa spiegare o governare la realtà.
La risposta a questa fragilità non è cercare maggiore controllo, ma accettare l’imprevedibilità come una caratteristica intrinseca della complessità. In questo scenario, la soluzione consiste nel progettare sistemi antifragili, capaci non solo di resistere al cambiamento, ma di rafforzarsi attraverso di esso.
Il livello di fragilità di un sistema dipende in gran parte dalla sua struttura interna. Come abbiamo discusso in precedenti articoli, la capacità di evolvere è legata al modo in cui le sue componenti sono collegate. Più che la coesione, è il grado di accoppiamento tra le parti a incidere sulla flessibilità. Sistemi con componenti debolmente accoppiate sono più facili da modificare e meno inclini a generare effetti collaterali imprevisti.
Approcci orientati al cambiamento
Già nel 1972, David Parnas — pioniere dell’ingegneria del software — ha messo in discussione l’approccio tradizionale alla modularizzazione. Secondo la sua visione, è possibile costruire software migliori concentrandosi su ciò che cambierà nel tempo, più che sulle funzionalità immediate. Su questa linea si colloca anche l’approccio IDesign di Juval Lowy, che evidenzia la differenza tra decomposizione funzionale e volatilità, proponendo alternative progettuali che ne semplificano l’attuazione.
A differenza dei metodi che si focalizzano solo sulla suddivisione per funzione, questi approcci pongono l’attenzione sugli elementi soggetti a cambiamento, superando la logica del requisito immediato. Il libro “Anti-fragile ICT System” di Kjell Jørgen Hole elenca le caratteristiche fondamentali dei sistemi antifragili:
- Modularità: componenti indipendenti connessi tra loro;
- Legami deboli: basso livello di accoppiamento tra i moduli;
- Ridondanza: più istanze dello stesso componente per aumentare la resilienza;
- Diversità: capacità di affrontare un problema con soluzioni differenti.
Se vogliamo rispondere efficacemente alle sfide del contesto VUCA, dobbiamo ripensare radicalmente il modo in cui progettiamo i nostri sistemi. Come suggeriscono Taleb, Parnas e Lowy, è essenziale focalizzarsi su ciò che non conosciamo, accettando i nostri limiti e la naturale incertezza del futuro.
È questo lo spirito anche dell’approccio proposto da Dan North. All’inizio di ogni progetto, dovremmo riconoscere di trovarci almeno al secondo livello dell’ignoranza, come descritto nel trattato “Five Orders of Ignorance” di Phillip Armour: non sappiamo di non sapere. North approfondisce questi concetti nell’articolo “Introducing Deliberate Discovery“, che rappresenta un invito all’esplorazione consapevole dell’ignoto.
Residuality Theory
Questo nuovo approccio alla progettazione delle architetture software è al centro del libro di Barry O’Reilly, “Residues: Time, Change, and Uncertainty in Software Architecture“. L’autore propone una visione innovativa che pone al centro il concetto di residuo architetturale: ciò che rimane quando tutto il resto cambia. Un modo concreto per affrontare in modo strutturato il tempo, il cambiamento e l’incertezza nei sistemi complessi.

Secondo l’autore:
the future of a system is a function of its residues – the leftovers of the system after the impact of a stressor
Barry O’Reilly parte da presupposti di natura filosofica per arrivare a una formalizzazione matematica della sua teoria. Il punto di partenza è chiaro: gli approcci tradizionali non sono in grado di rappresentare efficacemente concetti come tempo, incertezza e cambiamento. Progettare la resilienza delle architetture basandosi unicamente su ciò che conosciamo — o crediamo di conoscere — senza uscire dai paradigmi consueti, non consente di ottenere i risultati attesi.
L’idea richiama il celebre “mito della caverna” di Platone, oppure — per una lettura più contemporanea — il film Matrix. Nel racconto della Repubblica, un prigioniero incatenato può osservare solo le ombre proiettate sul fondo della grotta e le scambia per la realtà. Ma, una volta liberato, scopre la vera origine di quelle ombre. Dopo un primo momento di smarrimento e il desiderio di tornare alla sicurezza dell’illusione, sente il bisogno di liberare anche gli altri. Tuttavia, non tutti sono disposti ad affrontare la luce del sole e preferiscono restare incatenati nella loro falsa sicurezza.
Ecco perché la citazione di Matrix non è casuale: è un invito a pensare fuori dagli schemi, esattamente come propone la Residuality Theory.

L’importanza degli stressori
Barry O’Reilly invita a non concentrarsi eccessivamente sulla prima versione dell’architettura, da lui definita architettura naive. È più utile, invece, analizzare gli stressori: eventi in grado di alterare il comportamento del sistema.
Uno stressore può assumere molte forme. Si va dal semplice errore di login al crollo dei mercati finanziari, dal blocco di un server allo scoppio di una guerra. Qualsiasi elemento che infrange il modello ideato per risolvere un problema di business può essere considerato tale.
Da qui nasce la necessità di pensare fuori dagli schemi. È fondamentale adottare un approccio di pensiero laterale, come suggerito da Edward De Bono nel libro “Sei Cappelli per Pensare“.
Per individuare quanti più stressori possibile è necessario esplorare il problema in profondità. Questo richiede il coinvolgimento attivo di tutto il team, come già discusso in precedenza. Una volta identificati gli stressori, il software architect ha il compito di valutarne l’impatto sui componenti dell’architettura naive.
Per questa attività non servono strumenti complessi: basta un semplice foglio Excel. Qui si elencano gli stressori e, per ciascuno, si evidenzia l’effetto potenziale sulle componenti architetturali. Ad esempio, nel caso di un ERP per la produzione e vendita della birra, potremmo trovarci di fronte a scenari molto diversi fra loro.
Come si può notare, gli stressori non sono soltanto di natura tecnica. Possono includere anche eventi imprevedibili e improvvisi, capaci di generare impatti significativi sul mercato di riferimento.
Reti booleane
Intorno al 1960, Stuart Kauffman introdusse il concetto di Random Boolean Network (RBN), ovvero una rete booleana randomica. Si tratta di una matrice i cui elementi assumono valori binari (0 o 1) in modo casuale quando stimolati, comportamento che ricorda quello dei sistemi complessi costituiti da numerosi componenti interagenti. Durante i suoi studi, Kauffman osservò che collegando i nodi in modalità diverse si potevano ottenere variazioni nella stabilità del sistema e nel numero di possibili configurazioni dei nodi, definite come stati di fase.
Emersero così tre fattori chiave che influenzano il numero di stati di fase: il numero di nodi (N), il numero di collegamenti tra di essi (K) e la tendenza dei nodi a comportarsi in modo simile (P). Kauffman notò inoltre che aumentando le dipendenze tra i nodi, ovvero creando connessioni più strette, il numero di stati di fase diminuiva drasticamente, anche di molti ordini di grandezza. In questi casi, il sistema tendeva a stabilizzarsi in determinati insiemi di stati, chiamati attrattori.
Le reti booleane di Kauffman hanno influenzato numerosi studi poiché gli attrattori si riscontrano in ogni sistema complesso. Nonostante l’ampia variabilità delle combinazioni possibili, un ordine emerge costantemente, e il sistema tende a tornare sempre allo stesso gruppo di attrattori. Nell’ambito sociale, ciò spiega la ripetizione di specifici pattern comportamentali; in ambito software, i pattern architetturali che adottiamo possono essere interpretati come attrattori, poiché risolvono problemi ricorrenti.
Un attrattore rappresenta uno stato verso cui il sistema converge stabilmente. Un esempio semplice: come esseri umani, siamo attratti dal riposo quando siamo stanchi e dal cibo quando abbiamo fame. Allo stesso modo, un buon software architect deve individuare quali siano gli attrattori del sistema che sta progettando, per garantirne la stabilità e l’efficacia nel tempo.
Tra criticità ed equilibrio
Nei suoi esperimenti, Kauffman individuò la proprietà di criticità: a un certo numero di nodi (N) e di collegamenti (K), un sistema risulta resiliente agli imprevisti, senza però spingersi fino al punto di consumare eccessivamente le proprie risorse. Nel nostro lavoro quotidiano, questa dinamica si riflette chiaramente nel confronto tra sistemi monolitici (caratterizzati da un basso numero di N e K) e sistemi basati su microservizi (con un alto numero di N e K). Da questo confronto emerge quanto sia cruciale trovare il giusto equilibrio tra queste due soluzioni.
Un terzo parametro, P, rappresenta la propensione (o il bias) di un nodo verso determinati comportamenti. Applicato alle architetture software, questo valore serve a limitare e definire il comportamento dei componenti all’interno del sistema. Per questo motivo, adottiamo interfacce invece di classi concrete nella comunicazione fra componenti coesi. I principi e le metodologie che utilizziamo — come OOP, SOLID, DRY, e altri — mirano proprio a bilanciare opportunamente N, K e P nei nostri sistemi. La difficoltà consiste nel trovare questo equilibrio, che spesso si basa su congetture, esperienza e confronto continuo.
Questo problema si affronta simulando in modo casuale l’ambiente operativo finché l’architettura non manifesta segni di criticità. È proprio a questo scopo che serve il foglio Excel: per riportare il livello di stress a cui il sistema è sottoposto e verificare se si è raggiunto il giusto equilibrio.
È importante distinguere tra criticità e correttezza. In un sistema complesso, la correttezza assoluta è irraggiungibile, mentre la criticità è un obiettivo realistico e auspicabile. Il compito del software architect è proprio individuare il punto di criticità del sistema che sta progettando, non quello di garantire una perfezione matematica, che resta prerogativa dei matematici o degli sviluppatori.
Come ricordato nel noto Software Architecture. The Hard Parts:
Don’t try to find the best design in software architecture. Instead, strive for the least worst combination of trade-offs.
Alla ricerca della criticità
Il primo foglio Excel ci permette di identificare gli stressori in grado di compromettere il funzionamento del sistema. Una volta individuati, dovremo intervenire — ricordando che siamo ancora in fase di progettazione — per realizzare un nuovo sistema, fondato sui residui del precedente.
Successivamente, sottoponiamo il nuovo sistema a un nuovo ciclo di test con stressori aggiornati. Come ricordato, un sistema raggiunge la criticità quando riesce a mantenere la stabilità anche di fronte all’emergere di stressori inaspettati. Il risultato di questa fase sarà un nuovo foglio Excel, che riflette lo stato aggiornato del sistema.ù
Nella prima colonna riportiamo il nostro sistema precedente, detto anche naive, mentre nella seconda il sistema derivato dai residui. A questo punto, possiamo calcolare l’indice del residuo:
Ri = (R - N) / (R + N)
Al numeratore si trova la differenza tra l’architettura residua e quella naive, mentre al denominatore la loro somma. In questo modo otteniamo un indice compreso tra
−1 ≤ Ri ≤ +1
Se l’indice è positivo, significa che il sistema risultante è più resiliente agli stressori inattesi, ma la ricerca può proseguire per migliorare ulteriormente. Se, invece, l’indice risulta negativo, vuol dire che l’intervento non ha prodotto benefici significativi o addirittura ha peggiorato la situazione.
Quando l’indice si avvicina a zero, possiamo ragionevolmente considerare di aver raggiunto il giusto equilibrio: il sistema è sufficientemente stabile per affrontare situazioni impreviste.
Conclusioni
L’agilità, intesa come capacità di adattarsi rapidamente al cambiamento, è spesso considerata la risposta ai contesti in continua evoluzione. Tuttavia, come abbiamo visto, non sempre è sufficiente. L’agilità dipende dalle risorse e dalle condizioni a disposizione, e da sola non garantisce la resilienza necessaria.
Un’architettura debole può compromettere rapidamente sia il sistema sia il business, limitando la capacità di adattamento. La Residual Architecture si propone come approccio innovativo per la progettazione di sistemi antifragili, fondando la sua teoria su principi filosofici che trovano poi riscontro in rigorose dimostrazioni matematiche.