Skip to content
Luca Zanchi / Tech Blog

Integrare API e sistemi senza costruire un altro punto fragile

Integrare due sistemi sembra spesso un’attività lineare.

Un’applicazione espone un’API, l’altra deve ricevere alcuni dati e tra le due viene costruita una connessione.

Un ordine creato nell’e-commerce deve arrivare nell’ERP. Un cliente aggiornato nel CRM deve essere sincronizzato con una piattaforma di marketing. Un catalogo prodotti deve passare dal PIM al sito. Una disponibilità di magazzino deve essere comunicata a più canali di vendita.

All’inizio, una connessione diretta può sembrare la soluzione più semplice e ragionevole:

Sistema A → Sistema B

In molti casi lo è davvero.

Il problema emerge quando la connessione smette di trasferire semplicemente dei dati e inizia ad assumere altre responsabilità.

Deve trasformare formati, applicare regole, gestire eccezioni, memorizzare stati, riprovare operazioni fallite, coordinare più destinazioni e compensare comportamenti differenti tra i sistemi coinvolti.

A quel punto compare spesso una domanda:

Serve un middleware?

La risposta non dipende soltanto dal numero di sistemi o dalla tecnologia utilizzata.

Dipende soprattutto da quanta complessità l’integrazione deve assorbire e da dove vogliamo che quella complessità rimanga visibile e governabile.

Una connessione diretta può essere la scelta migliore.

Un middleware può diventare necessario.

Entrambe le soluzioni, però, possono trasformarsi in un nuovo punto fragile se vengono adottate senza chiarire responsabilità, dipendenze e modalità di gestione degli errori.

1. Una connessione diretta non è un errore architetturale

Le integrazioni punto-punto vengono spesso descritte come qualcosa da evitare.

In realtà, collegare direttamente due sistemi non è necessariamente una cattiva scelta.

Può essere la soluzione più appropriata quando:

In questo scenario, introdurre una piattaforma intermedia potrebbe aggiungere più complessità di quanta ne risolva.

Una connessione diretta riduce il numero di componenti da distribuire, configurare e monitorare. Può essere compresa più facilmente e, se realizzata bene, mantenuta senza particolari difficoltà.

Il problema non è quindi il collegamento punto-punto.

Il problema nasce quando una soluzione progettata per un rapporto semplice tra due sistemi viene estesa progressivamente fino a sostenere una rete di responsabilità che non erano previste all’inizio.

2. Come cresce la complessità di un’integrazione

Le integrazioni raramente diventano fragili in un solo momento.

La complessità tende ad accumularsi attraverso richieste singolarmente ragionevoli.

All’inizio il requisito può essere:

Quando viene creato un ordine, invialo all’ERP.

Successivamente arrivano nuove condizioni:

La connessione non sta più trasferendo soltanto un ordine.

Sta implementando una parte del processo operativo dell’azienda.

Questo cambiamento è importante perché modifica la natura del componente.

Da semplice collegamento tecnico, l’integrazione diventa il luogo in cui vengono coordinate regole, dati e responsabilità appartenenti a sistemi diversi.

Quando questa evoluzione non viene riconosciuta, la logica tende a distribuirsi in modo poco controllato:

Il risultato può continuare a funzionare, ma diventa sempre più difficile capire dove venga presa una decisione e quale componente debba essere modificato.

3. Il vero problema delle integrazioni punto-punto

Una singola connessione diretta può essere semplice.

Il problema emerge quando ogni sistema viene collegato direttamente a molti altri sistemi.

E-commerce ─────→ ERP
│ ↑
├───────────→ CRM
│ ↑
└───────────→ PIM
│
Magazzino ──────────┘

Con l’aumento delle connessioni, aumentano anche:

Supponiamo, per esempio, che il codice prodotto utilizzato nell’ERP sia diverso da quello presente nell’e-commerce.

La regola di conversione potrebbe essere implementata nella connessione tra e-commerce ed ERP.

Quando anche il CRM e il sistema di magazzino hanno bisogno dello stesso dato, la stessa logica potrebbe essere copiata in altre integrazioni.

A quel punto una variazione nella codifica richiede modifiche coordinate in più punti.

Il problema non è soltanto la duplicazione del codice. È la perdita di una responsabilità chiara.

Quale sistema possiede la corrispondenza tra gli identificativi? Dove deve essere aggiornata? Quale componente rappresenta la fonte corretta?

Le integrazioni diventano fragili quando le risposte a queste domande dipendono dalla storia del progetto anziché da una scelta esplicita.

4. Che cosa dovrebbe fare un middleware

Il termine middleware viene utilizzato per indicare soluzioni molto diverse.

Può essere:

La tecnologia, però, è meno importante della responsabilità che il componente deve assumere.

Un middleware è utile quando crea un confine comprensibile tra sistemi differenti.

Può occuparsi di:

Una struttura minima può essere rappresentata così:

Sistema sorgente
↓
Acquisizione
↓
Validazione e normalizzazione
↓
Regole di orchestrazione
↓
Connettori verso i sistemi destinatari
↓
Registrazione dell’esito

Il middleware non elimina la complessità.

La raccoglie in un punto in cui può essere resa più esplicita, coerente e controllabile.

Questo vantaggio esiste soltanto se il componente intermedio ha responsabilità chiare. In caso contrario, il middleware rischia di diventare un ulteriore livello opaco aggiunto tra sistemi già difficili da comprendere.

5. Quando una connessione diretta è sufficiente

Prima di introdurre un middleware, considero utile verificare se il problema può essere risolto con una connessione più semplice.

Una connessione diretta è spesso sufficiente quando ricorrono queste condizioni.

5.1 Il flusso ha un solo produttore e un solo destinatario

Se un dato nasce in un sistema e deve essere utilizzato soltanto da un altro, non è sempre necessario introdurre un livello intermedio.

La relazione rimane comprensibile e il numero di dipendenze è limitato.

5.2 La trasformazione è minima

Rinominare alcuni campi, convertire una data o adattare una struttura semplice non richiede necessariamente una piattaforma dedicata.

La trasformazione deve però rimanere locale al rapporto tra i due sistemi e non rappresentare una regola di business condivisa.

5.3 Gli errori sono recuperabili

Se un fallimento può essere individuato facilmente e l’operazione può essere ripetuta senza conseguenze, la semplicità della connessione diretta può essere un vantaggio.

Questo presuppone comunque la presenza di log, identificativi e una modalità di recupero.

5.4 Il flusso cambia raramente

Una connessione stabile, con requisiti limitati e sistemi poco variabili, può rimanere semplice per molto tempo.

Non tutte le integrazioni sono destinate a crescere.

Progettare fin dall’inizio una piattaforma estensibile per un flusso che probabilmente resterà isolato può produrre un investimento sproporzionato.

5.5 La responsabilità è chiara

Deve essere evidente chi gestisce la connessione, dove si trova il codice o la configurazione, come viene distribuita e chi interviene quando qualcosa non funziona.

Una soluzione semplice con responsabilità esplicite è spesso più affidabile di un’architettura sofisticata senza una gestione definita.

6. Quando il middleware inizia a essere utile

Il passaggio a un componente intermedio diventa più ragionevole quando la complessità non appartiene più a una singola connessione.

Esistono alcuni segnali ricorrenti.

6.1 Più sistemi richiedono gli stessi dati

Se diversi sistemi devono ricevere lo stesso evento o la stessa informazione, collegarli tutti direttamente alla sorgente aumenta l’accoppiamento.

Ogni nuovo destinatario richiede una modifica o una nuova responsabilità nel sistema che produce il dato.

Un livello intermedio può separare la pubblicazione dell’informazione dalla sua distribuzione.

6.2 Le stesse trasformazioni vengono duplicate

Quando più connessioni implementano la stessa normalizzazione, mappatura o regola di conversione, diventa utile individuare un punto in cui quella responsabilità possa essere gestita una sola volta.

Non significa necessariamente centralizzare ogni trasformazione.

Significa distinguere tra adattamenti specifici di una destinazione e regole che rappresentano un concetto condiviso dall’organizzazione.

6.3 Il processo attraversa più sistemi

Alcuni flussi non consistono in un semplice trasferimento.

Per completare un’operazione può essere necessario:

  1. ricevere un ordine;
  2. verificare il cliente nel CRM;
  3. recuperare i dati fiscali;
  4. creare il documento nell’ERP;
  5. prenotare la disponibilità;
  6. comunicare l’esito all’e-commerce.

In questo caso esiste un processo distribuito che deve mantenere uno stato e coordinare più passaggi.

Inserire tutta la logica in uno dei sistemi coinvolti può attribuirgli responsabilità che non gli appartengono.

6.4 Gli errori richiedono una gestione coordinata

Se un fallimento parziale lascia i sistemi in stati differenti, serve un punto capace di registrare ciò che è già avvenuto e decidere come proseguire.

Il middleware può gestire:

Senza questo coordinamento, ogni sistema conosce soltanto una parte della storia.

6.5 I sistemi cambiano con frequenze differenti

Un ERP legacy, un e-commerce SaaS e un’applicazione interna possono avere cicli di evoluzione molto diversi.

Il middleware può funzionare come livello di adattamento, evitando che ogni cambiamento di un sistema si propaghi immediatamente a tutti gli altri.

Questo non elimina la necessità di aggiornare le integrazioni, ma limita il numero di componenti direttamente coinvolti.

6.6 Serve una visibilità unificata

Quando i flussi sono numerosi, cercare gli errori separatamente in ogni applicazione diventa inefficiente.

Un componente intermedio può offrire una vista comune su:

Questa visibilità è spesso uno dei motivi più concreti per introdurre un middleware.

7. Come anche un middleware diventa fragile

L’introduzione di un middleware non risolve automaticamente i problemi di integrazione.

Può, al contrario, creare un nuovo punto critico.

Questo accade quando il componente assume troppe responsabilità, rimane poco documentato o diventa l’unico luogo in cui è possibile comprendere il processo.

7.1 Tutta la logica finisce nel middleware

Centralizzare ogni regola può sembrare conveniente.

Con il tempo, però, il middleware può trasformarsi in una grande applicazione che conosce dettagli di tutti i sistemi e contiene una parte crescente della logica aziendale.

A quel punto ogni modifica richiede di intervenire nello stesso componente, anche quando la responsabilità dovrebbe appartenere a un dominio specifico.

Il middleware dovrebbe coordinare i sistemi, non sostituirli.

7.2 Il formato condiviso diventa troppo generico

Per ridurre il numero di trasformazioni si può introdurre un modello dati comune.

È una scelta utile, ma difficile da mantenere quando il modello cerca di rappresentare ogni possibile variante di tutti i sistemi.

Un formato condiviso troppo astratto diventa complicato da comprendere. Un formato troppo vicino a un singolo sistema trasferisce invece il suo modello interno a tutte le altre applicazioni.

Il punto di equilibrio consiste nel rappresentare i concetti realmente condivisi, senza tentare di costruire un modello universale.

7.3 La piattaforma nasconde il comportamento

Alcuni strumenti permettono di creare integrazioni rapidamente attraverso interfacce visuali e configurazioni.

Questo accelera lo sviluppo iniziale, ma può rendere difficile capire:

La semplicità dell’interfaccia non garantisce la semplicità del sistema risultante.

7.4 Tutto dipende da un solo componente

Se ogni flusso passa attraverso lo stesso middleware, un problema della piattaforma può coinvolgere l’intera organizzazione.

La centralizzazione migliora la governance, ma aumenta anche l’impatto di alcuni guasti.

Diventano quindi importanti:

Il middleware deve essere trattato come un sistema operativo critico, non come un semplice contenitore di connessioni.

7.5 La conoscenza rimane concentrata

Cambiare tecnologia senza cambiare il modo in cui viene condivisa la conoscenza non risolve la dipendenza dalle singole persone.

Un middleware amministrato da un solo specialista può diventare fragile quanto gli script che avrebbe dovuto sostituire.

Servono convenzioni, documentazione, revisioni e responsabilità operative accessibili a più persone.

8. Separare trasporto, trasformazione e processo

Uno dei modi più utili per mantenere comprensibile un’integrazione è distinguere responsabilità che spesso vengono mescolate.

8.1 Trasporto

Il trasporto riguarda il modo in cui un’informazione passa da un sistema all’altro.

Può avvenire tramite:

Questa scelta risponde a domande come: quando viene trasferito il dato, con quale affidabilità e con quali garanzie di consegna?

8.2 Trasformazione

La trasformazione adatta il dato tra modelli differenti.

Può includere:

È importante distinguere le trasformazioni tecniche dalle decisioni di business.

Convertire una data è un adattamento tecnico. Decidere che alcuni clienti debbano seguire un flusso differente è una regola operativa.

8.3 Processo

Il processo stabilisce l’ordine delle operazioni e gestisce il loro risultato.

Risponde a domande come:

Separare questi livelli rende più semplice modificare il modo in cui un dato viene trasportato senza riscrivere le regole, oppure cambiare un connettore senza alterare il processo complessivo.

9. Contratti chiari tra sistemi

Ogni integrazione si basa su un contratto, anche quando non è stato documentato.

Il contratto comprende almeno:

Quando questi aspetti rimangono impliciti, i sistemi possono avere interpretazioni differenti dello stesso scambio.

Un campo vuoto, per esempio, può significare:

La struttura tecnica può essere valida, ma il significato operativo ambiguo.

Per questo un buon contratto non descrive soltanto il formato. Descrive anche le aspettative.

9.1 Stabilire chi possiede il dato

Per ogni informazione importante dovrebbe essere chiaro quale sistema ne rappresenta la fonte autorevole.

Il CRM possiede i dati del cliente? L’ERP possiede le condizioni commerciali? Il PIM possiede le descrizioni dei prodotti? Il magazzino possiede la disponibilità?

Senza questa distinzione, due sistemi possono modificare lo stesso dato e sovrascriversi reciprocamente.

9.2 Rendere espliciti gli identificativi

Molti problemi di integrazione derivano dal modo in cui i record vengono riconosciuti.

Un cliente può avere:

Basare la sincronizzazione su un attributo modificabile, come l’email, può produrre errori quando quel valore cambia.

Serve quindi una strategia esplicita per correlare gli identificativi dei diversi sistemi.

9.3 Gestire l’evoluzione

Le API e i modelli dati cambiano.

Un contratto dovrebbe chiarire come vengono introdotte variazioni compatibili e incompatibili.

Aggiungere un campo facoltativo, per esempio, ha conseguenze diverse rispetto a cambiare il significato di un valore esistente.

L’obiettivo non è impedire il cambiamento, ma renderlo prevedibile.

10. Sincrono o asincrono

Una delle decisioni più importanti riguarda il rapporto temporale tra i sistemi.

10.1 Comunicazione sincrona

In una comunicazione sincrona, il sistema chiamante attende una risposta immediata.

Sistema A → richiesta → Sistema B
Sistema A ← risposta ← Sistema B

Questo modello è utile quando:

Il principale limite è l’accoppiamento temporale.

Se il sistema B non è disponibile, anche il processo del sistema A può bloccarsi.

10.2 Comunicazione asincrona

In una comunicazione asincrona, il sistema produce un messaggio o registra un’attività che verrà elaborata successivamente.

Sistema A → coda o evento → elaborazione → Sistema B

Questo modello è utile quando:

L’asincronia migliora il disaccoppiamento, ma introduce nuove responsabilità:

Non è quindi una soluzione automaticamente più robusta. È un diverso modo di distribuire la complessità.

11. Idempotenza e duplicazioni

Nelle integrazioni è prudente assumere che una richiesta possa essere ricevuta più di una volta.

Un timeout, per esempio, non indica necessariamente che l’operazione non sia stata eseguita.

Il sistema chiamante potrebbe non aver ricevuto la risposta e decidere di riprovare, mentre il destinatario ha già completato l’operazione.

Senza protezioni, il secondo tentativo può creare:

Un’operazione idempotente produce lo stesso risultato anche quando viene richiesta più volte con lo stesso identificativo.

Per ottenerlo si possono utilizzare:

Non tutte le azioni possono essere rese idempotenti nello stesso modo.

È però importante decidere esplicitamente cosa debba accadere quando una richiesta viene ripetuta.

12. Osservabilità dell’integrazione

Un’integrazione affidabile non deve soltanto trasferire dati.

Deve permettere di ricostruire il percorso di un singolo elemento.

Per un ordine, per esempio, dovrebbe essere possibile sapere:

Questo richiede identificativi di correlazione coerenti tra i diversi passaggi.

Ordine: ORD-4821
Correlation ID: 8f19...
↓
Ricezione completata
↓
Validazione completata
↓
Creazione ERP fallita
↓
Retry programmato

Senza questa continuità, ogni sistema contiene soltanto un frammento dell’accaduto.

L’osservabilità è particolarmente importante quando il processo è asincrono o coinvolge più destinazioni, perché non esiste una singola risposta capace di rappresentare l’esito complessivo.

13. Un percorso progressivo

Non sempre è necessario passare direttamente da alcune connessioni punto-punto a una piattaforma di integrazione completa.

È possibile procedere per fasi.

13.1 Rendere visibili le connessioni esistenti

Il primo passo consiste nel creare un inventario:

Anche un semplice diagramma può mostrare dipendenze che non erano più evidenti.

13.2 Uniformare gli aspetti operativi

Prima di modificare l’architettura si possono introdurre convenzioni comuni per:

Questa standardizzazione riduce la fragilità senza richiedere una riscrittura immediata.

13.3 Estrarre le responsabilità condivise

Le trasformazioni duplicate, la correlazione degli identificativi e le regole utilizzate da più flussi sono buoni candidati per essere spostati in componenti condivisi.

L’estrazione dovrebbe avvenire quando esiste un’esigenza concreta, non soltanto per anticipare una possibile riutilizzabilità futura.

13.4 Introdurre asincronia dove serve

Code ed eventi possono essere aggiunti nei punti in cui l’accoppiamento temporale crea problemi reali:

Non è necessario trasformare ogni comunicazione in un evento.

13.5 Centralizzare la visibilità

Anche mantenendo tecnologie differenti, può essere utile raccogliere in un unico punto lo stato operativo dei flussi più critici.

La centralizzazione della visibilità può produrre valore prima della centralizzazione dell’esecuzione.

14. La scelta dipende dal costo della complessità

La domanda “middleware o connessione diretta?” non ha una risposta universale.

Una connessione diretta ha un costo iniziale ridotto e mantiene semplice un problema realmente semplice.

Un middleware richiede un investimento maggiore, ma può ridurre duplicazioni, accoppiamento e difficoltà operative quando il numero di sistemi e responsabilità cresce.

La decisione dovrebbe considerare almeno:

Il punto non è scegliere l’architettura più sofisticata.

È scegliere quella che rende visibile e gestibile la complessità realmente presente.

15. Integrare significa definire responsabilità

Le integrazioni vengono spesso trattate come semplici attività di collegamento.

In realtà, rappresentano confini tra sistemi con modelli, tempi, responsabilità e vincoli differenti.

Una connessione diretta può essere robusta se il suo scopo rimane limitato, i contratti sono chiari e gli errori sono governabili.

Un middleware può essere utile quando coordina responsabilità condivise, isola i cambiamenti e rende osservabili processi distribuiti.

Entrambe le soluzioni diventano fragili quando la complessità rimane implicita.

Per questo, prima di scegliere una tecnologia, considero più importante rispondere ad alcune domande:

Un’integrazione è governabile quando queste responsabilità sono comprensibili.

Il middleware, quando serve, non dovrebbe essere un luogo in cui nascondere la complessità.

Dovrebbe essere il punto in cui quella complessità viene resa esplicita.