Atto IV: L'incastro
Il middleware più economico è quello che non hai mai scritto
Esiste un tipo di software che non compare nella demo, non appare nella vetrina, e non ha una sola schermata che un cliente vedrà mai, eppure è il software che più probabilmente ti sveglierà alle tre di notte. È il tessuto connettivo—il codice che sta tra il tuo store Shopify e gli altri sistemi senza cui la tua azienda non può vivere, e che traduce l’idea di ordine dell’uno nell’idea di ordine dell’altro, porta le giacenze dal sistema di magazzino dentro il catalogo, spinge il cliente che ha appena fatto checkout dentro l’ERP che prima o poi lo fatturerà. Lo chiamiamo middleware, e su scala enterprise a volte è l’unica risposta onesta a un problema reale. Ed è anche, quasi sempre, più costoso di quanto creda la versione di te che sta leggendo la proposta. L’intero capitolo si può comprimere in una sola riga che vorremmo ti portassi via da qui e ripetessi nelle riunioni di pianificazione finché i tuoi colleghi non la trovino irritante: il middleware più economico è quello che non hai mai scritto.
Lo intendiamo come incoraggiamento, non come ramanzina. Ci sono due situazioni in cui il middleware è davvero giustificato, e vale la pena nominarle con chiarezza così puoi confrontarci il tuo caso. La prima è quando un sistema da cui dipendi non ha un modo nativo di parlare con Shopify—un vendor di terze parti, un fornitore di logistica, un ERP di un’epoca in cui integrazione significava un file notturno su un server FTP—e qualcuno deve scrivere la cosa che fa parlare i due sistemi. La seconda è più sottile e più comune di quanto la gente ammetta: hai già un’integrazione, off-the-shelf o ereditata, e tecnicamente funziona, solo che i dati che ne escono sono sbagliati in un modo che avvelena silenziosamente tutto ciò che sta a valle. Entrambe sono reali. Entrambe giustificano il costruire. Nessuna delle due giustifica il costruire più di quanto il caso richieda, e il motivo per cui questa distinzione conta così tanto è esattamente ciò di cui l’epigrafe ti stava avvertendo.
Il middleware non si complica gradualmente. È questa la trappola. Costruisci la prima integrazione—da Shopify al magazzino, mettiamo—ed è pulita e piccola e un singolo engineer la tiene tutta in testa, e funziona, e tutti sono contenti, e tu concludi ragionevolmente che la prossima integrazione costerà più o meno lo stesso. Non sarà così. Da qualche parte intorno al terzo sistema, la cosa supera una soglia che nessuno aveva segnato sulla mappa, e il costo smette di essere additivo e comincia a essere qualcosa di più simile al moltiplicativo. Il modello dati che usa il magazzino e il modello dati che usa il CRM e il modello dati che usa Shopify non concordano, e adesso il tuo middleware non sta connettendo dei sistemi, sta arbitrando tra loro, tenendo tre versioni leggermente incompatibili della verità e decidendo, su ogni record, quale vince. Una cache che andava benissimo diventa una fonte di sottili dati stantii. Una visibilità di cui non avevi mai avuto bisogno diventa la cosa per cui daresti parecchio pur di averla. Questo è il complexity creep, e la parola creep lo sottostima, perché strisciare implica che tu possa vederlo accadere. Per lo più non puoi. Sembra tutto controllabile fino al momento della discontinuità, e poi all’improvviso ogni cosa pretende attenzione nello stesso istante.
L’immagine utile, se ne vuoi una da tenere in testa, è un pezzo di puzzle. Il tuo middleware è un pezzo tagliato su misura con sporgenze e incavi—le sporgenze e gli incavi sono i canali attraverso cui parla con ciascun sistema—e ha un colore, che è il suo modello dati. Perché l’immagine funzioni, le sporgenze devono incastrarsi negli incavi vicini e i colori devono armonizzarsi. Aggiungi una connessione e ritagli un bordo. Aggiungine un’altra e ne ritagli un altro, e aggiusti leggermente il colore così che continui a combaciare con il primo, il che ora significa ricontrollare il primo bordo, e così via. Ogni nuovo sistema non è un pezzo nuovo che se ne sta tranquillo accanto agli altri; è un nuovo ritaglio dell’unico pezzo che hai già, e il pezzo diventa solo più intricato, mai più semplice. Ecco perché la seconda integrazione non è come la prima, ed ecco perché la quinta non assomiglia a nessuna delle due.

Quindi, prima che qualcuno scriva una riga, il lavoro è rendere la cosa più piccola—o, idealmente, fare in modo che non esista. Tre discipline fanno gran parte di questo lavoro, e valgono più di qualsiasi astuzia architetturale che venga dopo.
La prima è mettere in discussione la necessità, onestamente e in modo un po’ spietato. Prima di impegnarti a costruire, esaurisci ciò che i tuoi vendor attuali possono già fare—leggi la loro documentazione, chiama il loro supporto, scopri se la capacità che stai per costruire da zero sta lì inutilizzata dietro una pagina di impostazioni che non hai mai aperto. Poi costruisci il business case, e costruiscilo con la tassa di manutenzione inclusa, perché il middleware non è una cosa che scrivi una volta; è una cosa che possiedi per sempre. Se l’integrazione è una vera comodità più che un bisogno pressante, la mossa corretta è spesso aspettare. (Non sei una startup tech. Sei un brand che vende cose, e ogni dollaro che non spendi a scrivere software di collegamento è un dollaro che puoi spendere sulla parte del business per cui i clienti effettivamente ti pagano.) E quando fai i conti, falli nel modo in cui un capitolo precedente ti ha chiesto di farli—al doppio della tua dimensione attuale, non alla tua dimensione attuale. L’integrazione che è soltanto fastidiosa da mantenere ai volumi di oggi è quella che diventa un secondo lavoro a tempo pieno al doppio degli ordini, e il momento per scoprirlo è adesso, sulla carta, non dopo, in produzione.
La seconda disciplina è mappare i workflow prima di costruirli—tutti, non solo l’happy path che passa per il centro. La versione onesta di questo è un workshop, e la versione onesta del workshop è lunga; otto ore sono un pavimento ragionevole, non un soffitto, perché tutto il punto è far emergere la dipendenza a monte che nessuno aveva menzionato e il consumatore a valle che nessuno ricordava e il processo adiacente che salta fuori legga gli stessi dati per una ragione del tutto diversa. La maggior parte dei disastri di middleware non sono fallimenti di codice. Sono il fallimento di aver capito, la mattina in cui hai iniziato, a cosa servissero davvero quei dati.
La terza disciplina è costruire come attraverseresti un fiume di cui non vedi il fondo: un piede prima dell’altro, invece di un unico salto gigantesco. Resisti alla consegna monolitica—la tentazione di specificare tutta l’integrazione in anticipo e costruirla per intero prima che vada in produzione qualcosa. Prendi un caso d’uso, costruiscilo, mettilo davanti al mondo reale, e lascia che ciò che il mondo reale ti dice plasmi il prossimo. Lo sviluppo evolutivo è più lento a sembrare impressionante e molto più veloce a essere giusto, perché il feedback arriva mentre il costo di cambiare idea è ancora basso.

Supponiamo che tu abbia fatto tutto questo, onestamente, e che la risposta sia comunque: sì, costruisci. Va bene. Da questo momento la cosa non è più un progetto; è infrastruttura. Gestisce ordini e clienti e spedizioni, il che significa che quando crolla, qualcosa a cui un cliente tiene crolla insieme a lei, e sarai giudicato di conseguenza. Quindi la domanda diventa una questione di forma, e il primo bivio sulla strada è tra due architetture che su una lavagna sembrano simili e in produzione non si comportano per niente allo stesso modo.
Il middleware reattivo risponde agli eventi nel momento in cui accadono—viene piazzato un ordine, scatta un webhook, il tuo codice reagisce. È la scelta giusta quando l’operazione è davvero time-sensitive, ed è anche la scelta che morde. Shopify disattiva una subscription a un webhook dopo ripetuti fallimenti o timeout, il che significa che un sistema reattivo che non riesce a stare al passo non si limita a rimanere indietro, viene disiscritto—la manichetta antincendio viene chiusa proprio perché facevi fatica a berci. Quindi un design reattivo ha bisogno di una coda tra Shopify e la tua logica, per assorbire i picchi e tenere gli eventi al sicuro mentre recuperi. E il codice dall’altro lato di quella coda deve essere costruito per un mondo ostile: idempotente, così che lo stesso evento che arriva due volte non fatturi il cliente due volte; resiliente alle race condition, dove due eventi sullo stesso oggetto arrivano abbastanza vicini da pestarsi i piedi a vicenda; e indifferente agli eventi che arrivano fuori ordine, perché Shopify non ti promette che le cause precedano gli effetti. Niente di tutto questo è esotico. Tutto quanto è il genere di cosa che devi progettare fin dal primo giorno, perché reinserire l’idempotenza in un sistema che dava per scontato di non averne mai bisogno è una piccola migrazione a sé.
Il middleware schedulato è il fratello più tranquillo. Gira a intervalli—ogni quindici minuti, ogni notte—e fa il suo lavoro in blocco, ed è molto spesso la risposta migliore quando ti stai integrando con un sistema di terze parti che ha le proprie idee su rate limit e dimensioni dei payload. Lo ottimizzi facendo batching, rispettando i limiti da entrambi i lati, essendo un cittadino educato dell’API di qualcun altro invece di un attacco denial-of-service dalle buone intenzioni. Gli manca il dramma del real-time, e la mancanza di dramma è la feature. Un gran numero di cose che sembrano dover reagire in realtà devono solo essere corrette entro mattina, e il sistema corretto più economico è quello che fa i suoi ragionamenti una volta sola, secondo una schedule, mentre tutti dormono.
Poi c’è la questione di quante cose deployi, e qui saremo brevi, perché il capitolo precedente ha già fatto questo discorso per esteso e non abbiamo alcun interesse a fartelo leggere due volte.
La proposta che sentirai—dal palco di una conferenza, dai gentili upsell della console cloud, dal collega che ha appena finito un ottimo articolo sulla service-oriented architecture—è di spezzare il middleware in pezzi. Un servizio per integrazione, una funzione per ambito, ciascuno piccolo e indipendente e scalabile per conto suo. È un’immagine allettante ed è, per la maggior parte del middleware enterprise, premature optimization travestita da buona ingegneria. I pezzi vanno deployati separatamente, il che moltiplica le tue pipeline. Condividere codice tra loro smette di essere una chiamata a funzione e diventa un pacchetto pubblicato con un numero di versione. La rete che ora si frappone tra i tuoi stessi componenti può fallire, e fallisce, in modi che una chiamata a funzione non potrebbe mai. E i modelli dati divergono tra i servizi finché tenerli coerenti diventa un progetto permanente a sé. Ti sei comprato l’intera tassa operativa di un sistema distribuito, e te la sei comprata prima di avere la scala che ne giustificherebbe anche solo una riga.
La risposta è quella che il capitolo precedente ha attaccato al tuo monitor, e ci limiteremo a indicartela di nuovo: il Majestic Monolith. Una sola applicazione ben strutturata e di lunga durata. I cambiamenti ortogonali diventano atomici perché vivono in un’unica codebase; l’endpoint API e il job schedulato condividono codice semplicemente stando nello stesso posto; una sola pipeline di deploy; nessuna complessità di sistema distribuito da gestire mentalmente perché non c’è alcun sistema distribuito. È, come abbiamo detto, noioso da operare, e questo resta esattamente il punto. La disciplina che ti ha fatto guadagnare un monolite pulito per la tua app custom è la stessa disciplina che ti fa guadagnare un monolite pulito per il tuo middleware—stesso temperamento, puntato su una superficie diversa.
Questo non è fanatismo, e vogliamo stare attenti a non venderlo come tale. I microservizi hanno case legittime. Un pezzo di middleware così banale da essere legato a esattamente un webhook e fare esattamente una cosa può ragionevolmente vivere da solo—non c’è niente da condividere e niente da tenere coerente, quindi il monolite ti regala poco. E ogni tanto una fetta della tua logica di business ha davvero bisogno di una particolare tecnologia—una libreria, un runtime, un modello—che non appartiene all’applicazione principale, e isolarla è la mossa onesta. La regola non è non spezzare mai. La regola è che il beneficio dello spezzare deve chiaramente e dimostrabilmente superare la complessità che aggiunge, e che l’onere della prova sta in capo allo spezzare, non al monolite. Parti intero. Stacca un pezzo solo quando puoi indicare il grafico che lo esige.
Tutto fin qui presuppone che tu stia costruendo. C’è un’alternativa rispettabile a cui finora abbiamo solo accennato, e per un certo tipo di brand è la scelta giusta: puoi comprare l’impianto idraulico invece di posarlo da solo. Il nome dominante qui è Celigo, una iPaaS—integration platform as a service—che è un modo lungo per dire impianto idraulico centralizzato per il tuo stack tecnologico. Invece di scrivere codice, configuri dei flow: un flow si mette in ascolto di un evento (un nuovo ordine Shopify), trasforma i dati nella forma che la destinazione si aspetta, e crea il record corrispondente nel sistema all’altro capo (un ordine di vendita nel tuo ERP). Nessun deploy, nessuna codebase, nessun engineer reperibile alle tre di notte. Per il brand giusto, è uno scambio eccellente.
Il brand giusto ha una sagoma piuttosto specifica. Usa NetSuite, perché i connettori più profondi e più mantenuti di Celigo puntano a NetSuite—gli uffici delle due aziende sono, per fama, abbastanza vicini da lasciarti trarre le tue conclusioni sul perché la storia di NetSuite sia così insolitamente forte—ed è abbastanza grande, diciamo dai cinquanta milioni di fatturato in su, che i fallimenti di integrazione costano soldi veri e il prezzo della piattaforma è rumore di fondo rispetto a quel costo. Ha molti sistemi da connettere piuttosto che pochi, perché il valore di Celigo si compone con il numero di connessioni: consolidare Shopify, NetSuite, il tuo ESP, i tuoi marketplace e il tuo magazzino in un unico posto è una vera leva operativa. E, cosa cruciale, ha qualcuno il cui lavoro include il possedere la cosa.
Perché la struttura di costo di una iPaaS è per lo più nascosta, ed è nascosta in posti che ti lusingano all’ingresso e ti fatturano all’uscita. La promessa “no-code” è la prima da leggere con attenzione: il visual builder rende le cose semplici davvero più semplici, ma non elimina il bisogno di competenza tecnica—un’integrazione complessa resta un’integrazione complessa, e adesso la stai costruendo in un’interfaccia drag-and-drop invece che in un editor di testo, il che è un’attività diversa, non una più facile. Il testing è la seconda: non c’è unit test, non c’è pipeline di CI, non c’è spunta verde prima di andare in produzione; stai, nel senso letterale, testando in produzione, e la disciplina che davi per scontata nella tua codebase va ricostruita a mano. La terza è quella che fa il danno silenzioso. Poiché i flow sono così facili da creare, si moltiplicano, e poiché nessuno possiede ciò che si moltiplica, non vengono mai potati. Siamo entrati in brand che facevano girare più di quaranta flow attivi dove dodici erano effettivamente necessari—il resto un sedimento di duplicati, esperimenti abbandonati e workaround una tantum che qualcuno aveva costruito sotto scadenza e nessuno aveva mai spento. Ognuno è debito tecnico e una voce sul conto. E i fallimenti, quando arrivano, sono silenziosi: i dati semplicemente smettono di sincronizzarsi, e nessun allarme suona, e te ne accorgi quando le giacenze sono sbagliate o un ordine è sparito, vale a dire che te ne accorgi da un cliente. Più a lungo tutto questo gira, più i flow si accumulano, e più diventa costoso andarsene mai—che è il lock-in, che arriva non come una decisione ma come una lenta accrezione.

Quindi il custom vince su Celigo nella situazione speculare: quando hai solo due o tre sistemi da connettere e i loro bisogni sono semplici; quando hai un solido team di sviluppo interno che preferirebbe avere version control e code review e una vera suite di test invece di un visual builder; quando i tuoi workflow sono altamente personalizzati e rappresentano qualcosa di vicino a un vantaggio competitivo; e quando la qualità del codice e la copertura dei test non sono negoziabili nella tua cultura. E se scegli Celigo, il prezzo per tenerlo in salute è una disciplina operativa che rispecchia il modo in cui tratteresti qualsiasi sistema critico: assegnagli un proprietario chiaro invece di lasciare che tutta l’azienda lo modifichi; tratta ogni modifica a un flow come un commit di codice, con una nota su cosa è cambiato e perché e cosa ti aspettavi che facesse; fai l’audit dell’intero parco ogni trimestre e disabilita ciò che non serve a nessuno prima che si formi il sedimento; e configura allarmi veri sui flow mission-critical, così che il fallimento silenzioso abbia qualcosa che ne rompa il silenzio. Celigo si guadagna il suo posto quando il tuo vantaggio competitivo vive da tutt’altra parte—quando la sincronizzazione dei dati è infrastruttura necessaria ma non la cosa che ti distingue. Se è così, pagare qualcun altro perché faccia girare l’impianto idraulico è esattamente la cosa giusta, e ti libera per spendere i tuoi engineer su ciò che davvero distingue il brand.
Il che ci riporta da dove l’epigrafe era partita, solo che adesso hai tutta la mappa dietro l’avvertimento. Il middleware sembra facile perché il primo pezzo è facile, e il primo pezzo ti sta dicendo onestamente la verità sul primo pezzo e ti sta mentendo su tutto il resto. Che tu lo costruisca o lo compri, la cosa per cui stai firmando non è una feature; è un obbligo permanente, un piccolo pezzo di infrastruttura che pretenderà attenzione per tutto il tempo in cui il business ci girerà sopra. Quindi metti in discussione la necessità prima di impegnarti. Mappa l’intero workflow prima di costruire. Costruisci un piede alla volta. Tienilo intero finché il grafico non ti costringe a spezzarlo. E fai i conti al doppio della tua dimensione, perché l’integrazione che è economica oggi è quella che silenziosamente diventa uno stipendio domani.
Qui giace l’integrazione che nessuno possedeva: quaranta flow, dodici portanti, tutti che sincronizzavano fedelmente fino alla mattina in cui non lo hanno fatto.
Il middleware più economico è quello che non hai mai scritto. Il secondo più economico è quello che hai scritto di proposito, hai tenuto piccolo, e potresti spiegare a una persona appena assunta in un pomeriggio. Tutto ciò che va oltre, lo stai pagando che la voce sul conto lo dica o no.