La Morte del JSON nel Backend: Perché ho migrato tutto il mio stack a gRPC e Protobuf
Inizierò questo post con una confessione che potrebbe procurarmi qualche nemico: odio il JSON.
Non è un odio irrazionale, di quelli che compaiono dal nulla. È un odio costruito, mattone dopo mattone, in anni di debug di payload malformati, campi che dovevano essere numeri ma arrivavano come stringhe, e quel classico null dove ti aspettavi un array vuoto. Il JSON è l’equivalente digitale di una conversazione telefonica con tua nonna: pensi di aver capito cosa ha detto, ma quando arrivi lì, la torta di carote non aveva quella glassa al cioccolato che ti aspettavi (i brasiliani capiranno).

Per anni, ho accettato questa tortura come parte del contratto sociale dell’essere uno sviluppatore backend. “È lo standard”, dicevano. “Lo usano tutti”, ripetevano. E io, come un bravo agnellino, continuavo a serializzare e deserializzare testo come se fossimo nel 2005 e la banda larga fosse infinita.
Finché ne ho avuto abbastanza.
Il Problema: Il Testo è Costoso
Facciamo un esercizio mentale. Immagina di dover inviare il numero 42 dal tuo backend Go alla tua app Flutter.
In JSON, questo diventa:
{"answer": 42}
Sono 14 byte di testo. Sembra pochissimo, vero? Ora immagina di star inviando una lista di 10.000 transazioni finanziarie, ognuna con 15 campi. All’improvviso, quel “testo leggibile dall’uomo” si trasforma in megabyte di spreco.
Il parsing del JSON è un rituale di sacrificio della CPU. Il tuo server deve:
- Convertire la struttura Go in testo.
- Serializzare quel testo in UTF-8.
- Inviarlo attraverso la rete.
- Il client riceve il testo.
- Il client analizza il testo di nuovo in una struttura.
- Il client prega che i tipi siano corretti.
Ognuno di questi passaggi consuma cicli di elaborazione. E come ho detto nel mio post Chi Sono: i bit consumano energia. Sprecarli è moralmente offensivo.
La Soluzione: Protobuf e la Bellezza del Binario
Protocol Buffers (Protobuf) è il formato di serializzazione creato da Google per risolvere esattamente questo problema. Invece del testo, definisci un contratto (un file .proto), e il compilatore genera codice nativo per qualsiasi linguaggio.
Quello stesso {"answer": 42} in Protobuf? 2 byte. Non è magia, è matematica. Il binario è semplicemente più efficiente del testo.
Ma il risparmio di banda è solo la ciliegina sulla torta. Il vero regalo è il tipaggio forte.
syntax = "proto3";
message Transaction {
string id = 1;
int64 amount_cents = 2;
string currency = 3;
int64 timestamp = 4;
TransactionType type = 5;
}
enum TransactionType {
UNKNOWN = 0;
CREDIT = 1;
DEBIT = 2;
}
Con questo file, genero codice per Go, Dart (Flutter) e TypeScript (SolidJS) con un singolo comando. Se cambio il tipo di amount_cents da int64 a string, il compilatore mi urla contro prima che io faccia il deploy. Non c’è più quell’incubo di “funzionava in Postman ma si è rotto nell’app”.
gRPC: Il Matrimonio Perfetto con HTTP/2
Protobuf è il formato. gRPC è il protocollo di comunicazione che usa questo formato. Ed è qui che le cose si fanno interessanti per chi tiene alla performance mobile.
gRPC funziona su HTTP/2 di default (e ha già supporto sperimentale per HTTP/3). Questo significa:
Multiplexing: Chiamate multiple sulla stessa connessione TCP. Nessuna apertura e chiusura di connessioni per ogni richiesta.
Compressione degli header: HTTP/2 usa HPACK per comprimere header ripetitivi. In REST, invii
Content-Type: application/jsonin ogni richiesta. In gRPC, questo viene negoziato una volta.Streaming bidirezionale: Vuoi una chat in tempo reale? WebSockets? Dimenticali. gRPC lo fa in modo nativo.
Per un’app mobile Flutter che consuma dati da un backend Go, la differenza è brutale. Meno byte trasferiti significa meno batteria consumata, tempi di caricamento più brevi e meno possibilità che l’utente si arrenda e vada a guardare TikTok.
Lo Stack: Go + Flutter + SolidJS
La mia architettura attuale funziona così:
- Backend in Go: Uso
protoc-gen-goeprotoc-gen-go-grpcper generare gli stub. Il server è ridicolmente veloce perché Go è già veloce, e ora non ha più bisogno di sprecare tempo a parsare JSON. - Mobile in Flutter: Uso il pacchetto Dart
grpc. Il codice generato da Protobuf è type-safe. Se il backend cambia un campo, l’app non compila finché non lo aggiorno. Questa è sicurezza. - Web in SolidJS: Qui arriva l’unico intoppo. I browser non parlano gRPC in modo nativo (ancora). La soluzione è usare gRPC-Web, un proxy che traduce chiamate HTTP/1.1 in gRPC. Non è perfetto, ma è comunque meglio del REST puro.
Il file .proto è l’unica fonte di verità. Lo modifico una volta, eseguo il compilatore e tutte le piattaforme sono sincronizzate. Basta giocare a quel gioco di mantenere tre versioni diverse di DTO in tre linguaggi diversi.
L’Elefante nella Stanza: Il Debugging
Sarò onesto: fare debug con gRPC è più difficile che con REST. Non puoi semplicemente aprire il browser e guardare il payload nella scheda Network. Il binario non è leggibile dall’uomo.
Per questo, uso grpcurl (il curl del mondo gRPC) e Kreya (un’alternativa a Postman per gRPC). Configuro anche il logging strutturato sul server per catturare le richieste deserializzate.
È un costo di setup iniziale. Ma una volta che ci prendi la mano, non torni indietro.
Quando NON Usare gRPC
Come tutto in tecnologia, non è tutto rose e fiori. gRPC è eccessivo per:
API pubbliche: Se stai creando un’API per essere consumata da terze parti, JSON/REST è ancora lo standard. Nessuno vuole imparare il tuo schema Protobuf solo per integrarsi. Non essere fastidioso.
Progetti piccoli: Se il tuo backend è un semplice CRUD con 5 endpoint, la complessità aggiuntiva non ne vale la pena.
SEO e crawler: I bot di Google non capiscono gRPC. Se hai bisogno che i tuoi contenuti siano indicizzati, REST + JSON è la strada.
Nel mio caso, mi concentro su sistemi interni dove controllo tutte le estremità. Non devo preoccuparmi della compatibilità esterna.
Conclusione: Il JSON Non è Morto, Ma Dovrebbe Essere in Ferie
Senti, il JSON non scomparirà. È l’inglese del mondo delle API: non è la lingua migliore (devo scrivere un post su quanto trovo brutto l’inglese), ma tutti la parlano. Per il consumo umano, il debug rapido e la prototipazione, ha ancora il suo posto.
TODO: Scrivi un post su quanto trovo brutto l'inglese
Ma se stai costruendo sistemi ad alte prestazioni, se tieni alla batteria del cellulare del tuo utente, se sei stanco di scoprire bug di tipizzazione in produzione… forse è il momento di considerare l’alternativa binaria.
Io ho migrato. Il mio server mi ringrazia. La mia app mi ringrazia. La mia sanità mentale? Beh, quella era già compromessa dal 7-1 che la nazionale brasiliana ha preso ai Mondiali del 2014.
In futuro, scriverò un post comparativo. Niente è più tecnico che stare zitti e farlo, giusto?
Prima che me ne dimentichi:
TODO: Scrivi un post che confronta REST x gRPC nella pratica
Ecco, io esco, ciao!
