Ricalcolo del percorso: scegliere un'architettura senza seguire tutte le best practice
Venerdì sera, il navigatore propone tre percorsi e internet il suo «consigliato»: microservizi, Kubernetes, Kafka, Redis. Quattro bivi per un negozio online piccolo e serio, compromessi scritti con la loro condizione di uscita, e le cinture che non si negoziano.
Venerdì 19 settembre 2025, ore 18:40. Sei in macchina sulla tangenziale, direzione frantoio di famiglia, in collina. Il navigatore ti propone tre percorsi: «Più veloce: 1 h 52, pedaggi», «Senza pedaggi: 2 h 04», «Più breve: 1 h 58, strade strette». Sopra il primo, in verde, la scritta che ti fa sentire in colpa a prescindere: «Percorso consigliato».
Sul telefono, nel gruppo del team (due persone e mezza, e la mezza sei tu), da giorni si discute del nuovo negozio online. Entro metà ottobre deve accettare le prenotazioni dell'olio nuovo. Fra ottobre e novembre si aspettano qualche migliaio di ordini: il traffico di un negozio piccolo e serio. E internet, come il navigatore, ha già pronto il suo percorso consigliato: microservizi, Kubernetes, una coda di messaggi dedicata, Redis per la cache, tutto nel cloud. Le famose best practice.
Il navigatore non è stupido. Ottimizza una cosa sola, i minuti, per un'automobile media. Non sa che hai il serbatoio a un quarto, che il portabagagli è pieno di bottiglie vuote e che sulla statale c'è il bar con la vista sul lago. Le best practice funzionano allo stesso modo: sono percorsi ottimi per qualcun altro, spesso aziende con centinaia di sviluppatori, milioni di utenti e problemi che tu non hai. Seguirle tutte, sempre, è come prendere l'autostrada per andare dal panettiere.
Stasera hai due ore di strada e quattro bivi da decidere. Nessuno ti obbliga a prendere il percorso consigliato.
18:52 · Primo bivio: autostrada o statale?
Il primo bivio è il più famoso. Da una parte i microservizi: l'applicazione divisa in tanti piccoli programmi separati, ognuno con il suo rilascio, che si parlano attraverso la rete. Dall'altra il monolite: un unico programma che fa tutto. I microservizi sono l'autostrada. Reggono traffici enormi e permettono a squadre diverse di correre su corsie diverse senza pestarsi i piedi, ma hanno caselli a ogni chiamata di rete, pedaggi in server e manutenzione, e se sbagli uscita fai venti chilometri prima di poter tornare indietro.
Chi ha preso l'autostrada senza averne bisogno, a volte, è tornato indietro, e lo ha raccontato. Nel 2018 Segment, che smistava dati verso decine di servizi esterni, aveva più di 140 microservizi, uno per ogni destinazione. In un articolo intitolato «Goodbye Microservices», Alexandra Noonan, del loro team di ingegneria, raccontò come li avevano fusi in un unico servizio. Uno dei risultati, tradotto: «Non dovevamo più rilasciare più di 140 servizi per una modifica a una delle librerie condivise».
Nel 2023 è toccato a un pezzo di Prime Video. Lo strumento che controlla la qualità audio e video degli stream era stato costruito «a regola d'arte» con servizi serverless di AWS, che si passavano i fotogrammi attraverso lo storage S3. Secondo il racconto del team, reggeva solo il 5% circa del carico previsto. Lo hanno rimesso tutto in un unico processo, e i costi di infrastruttura sono scesi del 90%. Attenzione però a non trasformare anche questo in una regola: era uno strumento, non tutto Prime Video, e Amazon non ha rinunciato ai microservizi. Il punto è proprio questo: lo stesso team, su quella strada specifica, ha scelto un altro percorso.
E poi c'è la via di mezzo, la statale a scorrimento veloce. Nel 2019 Shopify, con uno dei codici Ruby on Rails più grandi in circolazione e più di mille sviluppatori che ci avevano lavorato in dieci anni, invece di spezzarlo in microservizi scelse il monolite modulare: un unico programma, diviso in moduli con confini rigorosi. Nello stesso articolo c'è una frase che dovresti appendere in ufficio: «nei primi tempi di un sistema, spesso la migliore architettura è nessuna architettura».
Per il negozio dell'olio prendi la statale. Un solo programma, con le corsie dipinte per terra: ordini, magazzino, pagamenti. E per evitare che qualcuno, un venerdì sera, tagli dritto da una corsia all'altra, i confini li fai controllare a una macchina. In Python esiste import-linter, che verifica chi può importare chi:
[importlinter]
root_package = shop
[importlinter:contract:confini]
name = Magazzino e pagamenti non si conoscono
type = independence
modules =
shop.magazzino
shop.pagamenti
[importlinter:contract:direzione]
name = Nessuno importa gli ordini
type = forbidden
source_modules =
shop.magazzino
shop.pagamenti
forbidden_modules =
shop.ordiniGli ordini possono chiedere al magazzino e ai pagamenti; magazzino e pagamenti non si parlano tra loro e non conoscono gli ordini. L'ho provato su un negozio giocattolo: tutto in regola. Poi ho aggiunto nel magazzino la classica scorciatoia «solo per una cosa veloce», un from shop.pagamenti import addebita, e il controllo si è fermato così:
Magazzino e pagamenti non si conoscono BROKEN
Nessuno importa gli ordini KEPT
Contracts: 1 kept, 1 broken.
shop.magazzino is not allowed to import shop.pagamenti:
- shop.magazzino -> shop.pagamenti (l.7)Ecco il vantaggio della statale con le corsie dipinte: se un giorno un modulo avrà davvero bisogno di diventare un servizio a sé, i suoi confini saranno già puliti, e staccarlo costerà settimane invece di mesi.
19:20 · Secondo bivio: la stazione di servizio
Il navigatore ti segnala una grande area di servizio fra dieci chilometri. Ma hai ancora mezzo serbatoio, e ti basta.
Nel negozio, la grande area di servizio è l'infrastruttura dedicata. Dopo ogni ordine ci sono lavori da fare «poco dopo», senza far aspettare il cliente: la mail di conferma, l'etichetta della spedizione. Si mettono in una coda, e qualcuno li smaltisce. La best practice dice: un sistema di messaggistica dedicato, tipo RabbitMQ o Kafka. Il compromesso dice: hai già un database PostgreSQL, usa una tabella.
CREATE TABLE coda (
id bigserial PRIMARY KEY,
tipo text NOT NULL, -- 'mail-conferma', 'etichetta'...
dati jsonb NOT NULL,
creato_il timestamptz NOT NULL DEFAULT now(),
fatto_il timestamptz
);
CREATE INDEX coda_da_fare ON coda (id) WHERE fatto_il IS NULL;E ogni lavoratore, in un ciclo, fa così:
BEGIN;
SELECT id, tipo, dati FROM coda
WHERE fatto_il IS NULL
ORDER BY id
FOR UPDATE SKIP LOCKED
LIMIT 1;
-- ...manda la mail, stampa l'etichetta...
UPDATE coda SET fatto_il = now() WHERE id = $1;
COMMIT;Il trucco sta in FOR UPDATE SKIP LOCKED: blocca la riga che prendi e salta quelle che stanno già lavorando gli altri. È come al bancone del bar: ogni barista prende il primo scontrino che nessun altro ha in mano. Non è un uso improprio: è la documentazione di PostgreSQL a dire che serve proprio a evitare conflitti quando più consumatori accedono a una tabella usata come coda. E se la mail fallisce, la transazione viene annullata, la riga si sblocca e il lavoro torna in coda da solo.
L'ho provato con PostgreSQL 17: 2.000 lavori, tre lavoratori in parallelo e un 5% di errori simulati (110 mail «fallite»). Risultato: tutti i 2.000 lavori completati, ognuno una volta sola, divisi quasi in parti uguali (650, 681, 669), con i 110 falliti ripresi automaticamente. Per qualche migliaio di ordini al mese è più che sufficiente. Se un giorno arriveranno centinaia di lavori al secondo, ci si fermerà all'area di servizio. Quel giorno, non oggi.
Stesso ragionamento per la cache, cioè la memoria veloce dove tieni le cose che leggi spesso, come il listino prezzi. Best practice: Redis. Compromesso: un dizionario che dimentica.
import time
class CacheConScadenza:
"""Un dizionario che dimentica. Vale per UN processo: con tre processi, tre cache."""
def __init__(self, secondi):
self.secondi, self.dati = secondi, {}
def prendi(self, chiave, calcola):
valore, scade = self.dati.get(chiave, (None, 0))
if time.monotonic() >= scade:
valore = calcola()
self.dati[chiave] = (valore, time.monotonic() + self.secondi)
return valore
listino = CacheConScadenza(secondi=300)
def prezzi():
return listino.prendi("prezzi", carica_prezzi_dal_db)Nel test, mille letture del listino fanno una sola query al database. Il prezzo da pagare è scritto nella prima riga della classe: ogni processo ha la sua cache, quindi con tre processi, per un massimo di cinque minuti, potrebbero mostrare prezzi diversi. Per un listino che cambia due volte l'anno è accettabile. Per le quotazioni di borsa no. Ed è questo, un compromesso: un prezzo che conosci e decidi di pagare.
Se ti sembra roba da dilettanti, guarda Stack Overflow, uno dei siti più visitati dagli sviluppatori di tutto il mondo. Nel 2016 Nick Craver, allora nel loro team, pubblicò l'elenco completo delle macchine: 11 server web (9 per il sito vero e proprio), 4 server SQL, 2 Redis, 3 Elasticsearch. Solo il 9 febbraio di quell'anno avevano servito più di 66 milioni di pagine. Sì, avevano anche Redis: il compromesso non è rinunciare a tutto, è prendere solo quello che ti serve, e farlo funzionare benissimo.
19:45 · Terzo bivio: auto tua o a noleggio?
Qui il compromesso cambia direzione, e conviene guardarlo bene.
Per anni la best practice è stata «tutto nel cloud». Poi 37signals, l'azienda di Basecamp e HEY, ha fatto il contrario: ha comprato i suoi server ed è uscita quasi del tutto dai servizi di Amazon. Nell'ottobre 2024 David Heinemeier Hansson, CTO dell'azienda, ha fatto i conti in pubblico: la bolletta del cloud è passata da circa 3,2 a circa 1,3 milioni di dollari l'anno, con un risparmio stimato di oltre 10 milioni in cinque anni. Sono stime dell'azienda, non un bilancio certificato, ma il senso è chiaro.
Quindi anche tu ti compri i server? No. 37signals ha persone che si occupano di macchine da vent'anni e un carico prevedibile. Il tuo team è di due persone e mezza, e nessuno vuole svegliarsi alle tre di notte perché un disco si è rotto. Per te il pedaggio vale la pena: un database PostgreSQL gestito, con i backup automatici, e un solo server applicativo. Stessa domanda, risposta opposta. Il compromesso giusto dipende dalla tua macchina, non dalla strada.
20:10 · Lavori in corso
Sul display compare un cartello: «Lavori in corso, possibili rallentamenti». Anche nel software ci sono i lavori in corso, e si chiamano «versione nuova». PostgreSQL 18 è previsto per giovedì prossimo, 25 settembre, e porta novità golose, come il nuovo sottosistema di I/O asincrono. Ma il negozio apre a metà ottobre, e il giorno del lancio non è il momento di provare l'asfalto appena steso. Parti con la 17, che conosci, e aggiorni a gennaio, a olio venduto. Anche questo è un compromesso: rinunci a qualcosa di meglio, per un po', in cambio di una sorpresa in meno.
20:25 · Ricalcolo del percorso
Tra un ragionamento e l'altro, sbagli uscita. Il navigatore non ti sgrida. Dice soltanto: «Ricalcolo del percorso». È la funzione più saggia che abbia.
Nel 2016, nella lettera agli azionisti, Jeff Bezos divise le decisioni in due tipi. Alcune sono «porte a senso unico»: irreversibili o quasi, e vanno prese con calma, lentamente, consultandosi. Ma la maggior parte sono «porte a doppio senso»: si possono cambiare, si può tornare indietro. Quelle vanno prese in fretta, da poche persone con buon giudizio.
Guarda le tue scelte di stasera con questi occhi. Il monolite modulare è una porta a doppio senso: i confini puliti servono proprio a poter staccare un modulo domani. La coda nel database è a doppio senso: vive in un modulo solo, e cambiarla tocca poche righe. La cache, ancora di più. Le porte a senso unico sono altrove: come sono fatti i dati dei clienti e degli ordini, quale servizio di pagamento usi, cosa prometti ai clienti. Lì sì, rallenta.
E soprattutto, ogni compromesso lo scrivi. Bastano quattro righe, come un post-it sul cruscotto:
DECISIONE coda dei lavori in una tabella PostgreSQL
PERCHÉ qualche migliaio di ordini al mese; un pezzo in meno da gestire
COSTO niente priorità sofisticate; un po' di carico in più sul database
RIVEDERE sopra i 50 lavori al secondo, o se il database comincia a soffrireLa riga che conta è l'ultima. Un compromesso con la sua condizione di uscita è una decisione. Un compromesso senza è un debito che nessuno si ricorda di aver fatto.
Le cinture non sono un compromesso
Attenzione, però. Non essere rigido non vuol dire che tutto sia negoziabile. Puoi prendere la statale invece dell'autostrada, ma la cintura la allacci lo stesso. Nel negozio dell'olio le cinture sono queste:
- backup, e una prova di ripristino vera, almeno una volta, prima del lancio: un backup mai ripristinato è una speranza;
- HTTPS ovunque;
- pagamenti affidati a un fornitore specializzato: i numeri delle carte non devono mai passare dai tuoi server;
- password salvate con un algoritmo fatto apposta (bcrypt, Argon2), mai in chiaro;
- aggiornamenti di sicurezza applicati, senza aspettare gennaio.
La flessibilità serve a scegliere dove risparmiare, non a risparmiare dappertutto.
20:58 · Arrivo
Arrivi al frantoio alle 20:58. Non hai fatto il percorso più veloce, né il più breve, né quello consigliato. Hai fatto il tuo, con una sosta al bar sul lago e un ricalcolo per l'uscita sbagliata. Le bottiglie sono intere, e il serbatoio è bastato.
Prima di scendere scrivi nel gruppo del team: «Monolite modulare, PostgreSQL 17 gestito, coda nel database, cache in memoria. Le cinture tutte. I compromessi sono nel file DECISIONI. Rivediamo a gennaio». Due pollici in su e mezzo, perché la mezza sei tu.
Prima di scegliere la strada
Una checklist da tenere nel cassetto del cruscotto.
- Per chi è nata questa best practice? Quante persone, quanti utenti, quali problemi aveva chi l'ha inventata? Sono anche i tuoi?
- Quanto traffico hai davvero? Oggi, e realisticamente fra un anno, non fra dieci.
- Chi lo mantiene alle tre di notte? Ogni pezzo in più è qualcuno che deve saperlo riparare.
- È una porta a doppio senso? Se sì, decidi in fretta. Se no, rallenta e chiedi in giro.
- Cosa ti costa il compromesso? Se non riesci a scriverlo in una riga, non lo hai ancora capito.
- Quando lo rivedi? Scrivi la condizione: un numero, una data, un sintomo.
- Cosa non è negoziabile? Backup, sicurezza, dati dei clienti: quelli non si mettono sulla bilancia.
- Il pezzo nuovo risolve un problema che hai, o uno di cui hai letto?
Fonti
- Alexandra Noonan (Segment), Goodbye Microservices: From 100s of problem children to 1 superstar (10 luglio 2018)
- InfoQ, il servizio di monitoraggio di Prime Video passa da serverless a ECS (3 maggio 2023) e DevClass, Reduce costs by 90% by moving from microservices to monolith (5 maggio 2023)
- Kirsten Westeinde (Shopify), Deconstructing the Monolith (21 febbraio 2019)
- Nick Craver, Stack Overflow: The Architecture – 2016 Edition (17 febbraio 2016)
- The Register, i risparmi di 37signals dopo l'uscita dal cloud (21 ottobre 2024)
- Jeff Bezos, lettera agli azionisti 2015 (pubblicata nel 2016), le decisioni di Tipo 1 e Tipo 2
- PostgreSQL, documentazione di SELECT … FOR UPDATE SKIP LOCKED, annunci di PostgreSQL 18 Beta 1 (8 maggio 2025) e PostgreSQL 18 RC 1 (4 settembre 2025)
- Import Linter, documentazione