La strut­tu­ra­zio­ne dei dati svolge un ruolo im­por­tan­te nello sviluppo di programmi e siti web. Se i dati di un progetto sono ben strut­tu­ra­ti, possono essere letti da altri software con facilità e pre­ci­sio­ne. Sul web, questo è par­ti­co­lar­men­te im­por­tan­te per i motori di ricerca testuali come Google, Bing o Yahoo, che sono in grado di catturare in modo ottimale il contenuto di un sito web grazie a un markup adeguato e strut­tu­ra­to.

In generale, l’utilizzo di dati strut­tu­ra­ti nello sviluppo software, sia per ap­pli­ca­zio­ni web sia desktop, è utile ovunque i programmi o i servizi debbano scambiare dati tramite in­ter­fac­ce e si desideri un’elevata velocità di ela­bo­ra­zio­ne dei dati. Questo articolo spiega il ruolo che può svolgere il formato di se­ria­liz­za­zio­ne Protocol Buffers (Protobuf) e come questo metodo di strut­tu­ra­zio­ne si dif­fe­ren­zia dalla ben nota al­ter­na­ti­va JSONP.

Che cos’è il Protobuf (Protocol Buffers)?

Dal 2008, Google offre al grande pubblico i Protocol Buffers, in breve Protobuf, vale a dire un formato di scambio dati ori­gi­na­ria­men­te svi­lup­pa­to per uso interno come progetto open source (par­zial­men­te con licenza Apache 2.0). Il formato binario consente alle ap­pli­ca­zio­ni di me­mo­riz­za­re e scambiare dati strut­tu­ra­ti in modo semplice; questi programmi possono anche essere scritti in diversi linguaggi di pro­gram­ma­zio­ne. Tra i linguaggi sup­por­ta­ti vi sono:

  • C#
  • C++
  • Go
  • Objective-C
  • Java
  • Python
  • Ruby

Protobuf viene uti­liz­za­to, tra l’altro, in com­bi­na­zio­ne con HTTP e RPC (Remote Pro­ce­du­rel Calls) per la co­mu­ni­ca­zio­ne client-server locale e remota, in par­ti­co­la­re per la de­scri­zio­ne delle in­ter­fac­ce ne­ces­sa­rie a questo scopo. La com­po­si­zio­ne del pro­to­col­lo è definita anche con la sigla gRPC.

72mPlAfHIjs.jpg Per visualizzare questo video, sono necessari i cookie di terze parti. Puoi accedere e modificare le impostazioni dei cookie qui.

Quali sono i vantaggi dei buffer di pro­to­col­lo di Google?

Nello sviluppo di Protobuf, Google ha posto par­ti­co­la­re enfasi su due fattori: sem­pli­ci­tà e pre­sta­zio­ne. In origine, come già detto, il formato era destinato a so­sti­tui­re l’analogo formato XML all’interno dell’azienda. Oggi è in con­cor­ren­za anche con altre soluzioni, come JSON(P) o Flat­Buf­fers. Un’analisi delle ca­rat­te­ri­sti­che e dei punti di forza di questo metodo di strut­tu­ra­zio­ne mostra che i Protocol Buffers rap­pre­sen­ta­no comunque la scelta migliore per molti progetti:

Schemi di ap­pli­ca­zio­ne chiari e in­cro­cia­ti

La base di ogni ap­pli­ca­zio­ne di successo è un sistema di database ben or­ga­niz­za­to. L’or­ga­niz­za­zio­ne di questo sistema, compresi i dati in esso contenuti, è spesso oggetto di molta at­ten­zio­ne, ma quando suc­ces­si­va­men­te i dati vengono inoltrati a un servizio esterno, le strutture sot­to­stan­ti vanno perse. Co­di­fi­can­do i dati secondo lo schema dei Protocol Buffers, è garantito che il vostro progetto inoltri i dati strut­tu­ra­ti come de­si­de­ra­to, senza rompere queste strutture.

Re­tro­com­pa­ti­bi­li­tà e com­pa­ti­bi­li­tà in avanti

L’im­ple­men­ta­zio­ne di Protobuf elimina il noioso compito di eseguire i controlli di versione, di solito associato al co­sid­det­to codice “ugly” (it. brutto, scritto male.) Per mantenere la com­pa­ti­bi­li­tà all’indietro con le versioni pre­ce­den­ti e la com­pa­ti­bi­li­tà in avanti con le nuove versioni, i buffer di pro­to­col­lo accedono a campi numerati che fungono da punti di ri­fe­ri­men­to per l’accesso ai servizi. Ciò significa che non è sempre ne­ces­sa­rio adattare il codice completo per ri­la­scia­re nuove ca­rat­te­ri­sti­che e funzioni.

Fles­si­bi­li­tà e comfort

Con la codifica del Protobuf, si uti­liz­za­no au­to­ma­ti­ca­men­te dei mo­di­fi­ca­to­ri (a scelta tra richiesti, opzionali o ri­pe­ti­ti­vi) che rendono il lavoro di pro­gram­ma­zio­ne molto più facile. Ad esempio, il metodo di strut­tu­ra­zio­ne permette di de­ter­mi­na­re la forma della struttura dei dati a livello di schema, dove i dettagli d’im­ple­men­ta­zio­ne delle classi uti­liz­za­te per i diversi linguaggi di pro­gram­ma­zio­ne sono regolati au­to­ma­ti­ca­men­te. Inoltre, è possibile mo­di­fi­ca­re lo stato in qualsiasi momento, ad esempio da “richiesto” a “opzionale”. Anche la tra­smis­sio­ne delle strutture dati può essere regolata tramite i buffer di pro­to­col­lo: co­di­fi­can­do le strutture generiche di richiesta e risposta, si ga­ran­ti­sce fa­cil­men­te un tra­sfe­ri­men­to dati fles­si­bi­le e sicuro tra più servizi.

Riduzione del codice Boi­ler­pla­te

A seconda del tipo e della com­ples­si­tà di un progetto, il codice Boi­ler­pla­te (o sem­pli­ce­men­te Boi­ler­pla­te) gioca un ruolo più o meno decisivo nella pro­gram­ma­zio­ne. In parole povere, si tratta di blocchi di codice riu­ti­liz­za­bi­li, necessari in molti punti di un software e di solito solo leg­ger­men­te adat­ta­bi­li. Spesso tale codice serve, ad esempio, a pre­di­spor­re l’utilizzo delle funzioni delle librerie. Essi sono comuni so­prat­tut­to nei linguaggi web Ja­va­Script, PHP, HTML e CSS, anche se ciò non è ottimale per le pre­sta­zio­ni dell’ap­pli­ca­zio­ne web. Un adeguato schema di Procotol Buffers aiuta a ridurre il codice Boi­ler­pla­te e quindi a mi­glio­ra­re le pre­sta­zio­ni a lungo termine.

Semplice in­te­ro­pe­ra­bi­li­tà tra linguaggi

Oggi le ap­pli­ca­zio­ni non sono più scritte in un solo lin­guag­gio, ma combinano parti di programma o moduli di diversi tipi di lin­guag­gio. Protobuf sem­pli­fi­ca no­te­vol­men­te l’in­te­ra­zio­ne dei singoli com­po­nen­ti del codice: se vengono aggiunti nuovi com­po­nen­ti il cui lin­guag­gio dif­fe­ri­sce da quello corrente del progetto, è suf­fi­cien­te far tradurre lo schema dei Protocol Buffers nel ri­spet­ti­vo lin­guag­gio di de­sti­na­zio­ne uti­liz­zan­do l’apposito ge­ne­ra­to­re di codice, riducendo così al minimo il proprio sforzo. Na­tu­ral­men­te, i linguaggi uti­liz­za­ti devono essere quelli sup­por­ta­ti da Protobuf di default, come i linguaggi già elencati, o aggiunti tramite add-on di terze parti.

Protobuf vs JSON: i due formati a confronto

Per prima cosa, Google ha svi­lup­pa­to i Protocol Buffers come al­ter­na­ti­va a XML (Ex­ten­si­ble Markup Language) e ha superato il lin­guag­gio di markup su molti aspetti. Ad esempio, la strut­tu­ra­zio­ne dei dati con Protobuf tende non solo ad essere più semplice, ma, secondo il gigante dei motori di ricerca, fornisce anche una struttura dei dati che è da tre a dieci volte più piccola e da 20 a 100 volte più veloce di una simile struttura XML.

I Protocol Buffers sono spesso con­fron­ta­ti anche con il lin­guag­gio di markup Ja­va­Script JSON (JavaScript Object Notation), anche se va detto che entrambe le tec­no­lo­gie sono state pro­get­ta­te con obiettivi diversi: JSON è un formato di messaggio che ha origine in Ja­va­Script, scambia i suoi messaggi in formato testo ed è sup­por­ta­to pra­ti­ca­men­te da tutti i comuni linguaggi di pro­gram­ma­zio­ne. Protobuf ha più di un formato di messaggio, dal momento che la tec­no­lo­gia Google offre anche varie regole e strumenti per definire e scambiare messaggi. Protobuf batte JSON anche in termini di pre­sta­zio­ni quando si guarda all’invio di messaggi in generale, ma la seguente tabella “Protobuf vs JSON” mette in evidenza che le due tecniche di strut­tu­ra­zio­ne hanno ciascuna i propri vantaggi e svantaggi:

  Protobuf JSON
Svi­lup­pa­to­re Google Douglas Crockford
Funzioni Formato di markup per dati strut­tu­ra­ti (me­mo­riz­za­zio­ne e tra­smis­sio­ne) e libreria Formato di markup per dati strut­tu­ra­ti (me­mo­riz­za­zio­ne e tra­smis­sio­ne)
Formato binario No
Stan­dar­diz­za­zio­ne No
Leg­gi­bi­li­tà Parziale
Community/Do­cu­men­ta­zio­ne Community ridotta, manuali online espan­di­bi­li Community vasta, buona do­cu­men­ta­zio­ne ufficiale, come tutorial online, ecc.

Quindi, se avete bisogno di un formato di se­ria­liz­za­zio­ne ben do­cu­men­ta­to che memorizzi e trasmetta i dati strut­tu­ra­ti in forma chia­ra­men­te leggibile, dovreste usare JSON. Ciò è par­ti­co­lar­men­te vero se la com­po­nen­te lato server dell’ap­pli­ca­zio­ne è scritta in Ja­va­Script e se gran parte dei dati viene elaborata di default di­ret­ta­men­te dai browser. Se, d’altra parte, la fles­si­bi­li­tà e le pre­sta­zio­ni della struttura dei dati giocano un ruolo decisivo, i buffer di pro­to­col­lo tendono ad essere la soluzione più ef­fi­cien­te e più indicata.

Tutorial: in­tro­du­zio­ne pratica a Protobuf uti­liz­zan­do l’esempio di Java

I buffer di pro­to­col­lo possono fare la dif­fe­ren­za in molti progetti software, ma come spesso accade, il primo passo è quello di conoscere e applicare le ca­rat­te­ri­sti­che speciali e i trucchi sin­tat­ti­ci della tec­no­lo­gia di se­ria­liz­za­zio­ne. Per darvi una prima idea della sintassi e dello scambio di messaggi di Protobuf, nel seguente tutorial trovate i passaggi fon­da­men­ta­li, dalla de­fi­ni­zio­ne del proprio formato in file .proto alla com­pi­la­zio­ne delle strutture dei Protocol Buffers. Come esempio, viene uti­liz­za­to come codice base una semplice ap­pli­ca­zio­ne Java per la rubrica, che può leggere le in­for­ma­zio­ni di contatto da un file e scriverle in un altro file. I parametri “nome”, “ID”, “indirizzo e-mail” e “numero di telefono” sono assegnati ad ogni voce della rubrica.

Definire il proprio formato dati nel file .proto

Per prima cosa occorre de­scri­ve­re una qualsiasi struttura di dati che si intende im­ple­men­ta­re con i buffer di pro­to­col­lo nel file .proto, il file di con­fi­gu­ra­zio­ne standard del formato di se­ria­liz­za­zio­ne. Per ogni struttura che si vuole se­ria­liz­za­re in questo file, cioè mappare in sequenza, è suf­fi­cien­te ag­giun­ge­re un messaggio (“message”). Si spe­ci­fi­ca­no quindi i nomi e i tipi per ogni campo di questo messaggio e si ag­giun­go­no i mo­di­fi­ca­to­ri de­si­de­ra­ti. É ob­bli­ga­to­rio un mo­di­fi­ca­to­re per ogni campo.

Per la rubrica Java, una possibile mappatura delle strutture dati nel file .proto è la seguente:

syntax = "proto3";
package tutorial;
option java_package = "com.example.tutorial";
option java_outer_classname = "AddressBookProtos";
message Person {
    required string name = 1;
    required int32 id = 2;
    optional string email = 3;
    enum PhoneType {
        MOBILE = 0;
        HOME = 1;
        WORK = 2;
    }
    message PhoneNumber {
        required string number = 1;
        optional PhoneType type = 2 [default = HOME];
    }
    repeated PhoneNumber phones = 4;
}
message AddressBook {
    repeated Person people = 1;
}

La sintassi dei buffer di pro­to­col­lo ricorda for­te­men­te C++ o Java. La versione Protobuf è sempre di­chia­ra­ta in primo luogo qui: proto3, seguita dalla de­scri­zio­ne del pacchetto software di cui si vogliono strut­tu­ra­re i dati. Questo include un nome univoco (“tutorial”) e, in questo esempio di codice, le due opzioni spe­ci­fi­che per Java: “java_package” (pacchetto Java in cui sono me­mo­riz­za­te le classi generate) e “java_outer_classname” (nome della classe sotto la quale sono rag­grup­pa­te le classi).

Seguono i messaggi del Protobuf, che possono essere composti da un numero qualsiasi di campi, con tipi di dati tipici come “bool”, “int32”, “float”, “double” o “string”. Anche questi sono in parte uti­liz­za­ti nell’esempio. Come già detto, ad ogni campo di un messaggio deve essere assegnato almeno un mo­di­fi­ca­to­re e può essere:

  • required: un valore per questo campo è ob­bli­ga­to­rio. Se questo valore manca, il messaggio rimane “uni­ni­tia­li­zed”, cioè non ini­zia­liz­za­to o non inviato.
  • optional: un valore può essere fornito in un campo opzionale, ma non è ne­ces­sa­rio che lo sia. In caso contrario, viene uti­liz­za­to un valore definito come standard. Ad esempio, nel codice riportato sopra, per il tipo di numero di telefono viene inserito il valore pre­de­fi­ni­to “HOME” (numero di rete fissa di casa).
  • repeated: i campi con il mo­di­fi­ca­to­re “repeated” possono essere ripetuti tutte le volte che si desidera (anche zero volte).

Potete trovare istru­zio­ni det­ta­glia­te su come definire il proprio formato di dati con i buffer di pro­to­col­lo nel Google Developer Forum.

Compilare il proprio schema di buffer di pro­to­col­lo

Una volta che le proprie strutture dati sono state definite nel file .proto come richiesto, generate le classi ne­ces­sa­rie per leggere e scrivere i messaggi Protobuf. A tal fine applicate il com­pi­la­to­re di buffer di pro­to­col­lo (protoc) al file di con­fi­gu­ra­zio­ne. Se non l’avete ancora in­stal­la­to, scaricate l’ultima versione nell’ufficiale GitHub Re­po­si­to­ry. De­com­pri­me­te il file ZIP nella posizione de­si­de­ra­ta e avviate il com­pi­la­to­re con un doppio clic.

N.B.

Scaricate l’edizione ap­pro­pria­ta del com­pi­la­to­re del Protobuf: Protoc è di­spo­ni­bi­le per ar­chi­tet­tu­re da 32 o 64 bit (Windows, Linux o macOS).

Infine, spe­ci­fi­ca­te

  • la directory sorgente dove si trova il codice del vostro programma (qui carattere jolly “SRC_DIR”),
  • la directory di de­sti­na­zio­ne dove deve essere me­mo­riz­za­to il codice generato (qui carattere jolly “DST_DIR”)
  • e il percorso per il file .proto.

Poiché si desidera generare classi Java, uti­liz­za­te anche l’opzione --java_out (opzioni simili sono di­spo­ni­bi­li anche per gli altri linguaggi sup­por­ta­ti). Il comando completo per la com­pi­la­zio­ne è il seguente:

protoc -I=$SRC_DIR --java_out=$DST_DIR $SRC_DIR/addressbook.proto
Consiglio

Un tutorial più det­ta­glia­to su Protobuf Java che spiega, tra le altre cose, la tra­smis­sio­ne di messaggi tramite buffer di pro­to­col­lo (lettura/scrittura), è fornito da Google nella sezione “De­ve­lo­pers”, l’area di progetti interni del grande motore di ricerca per gli svi­lup­pa­to­ri. In al­ter­na­ti­va, è possibile accedere ai tutorial per gli altri linguaggi sup­por­ta­ti come C++, Go o Python.

Vai al menu prin­ci­pa­le