Protobuf: codice strutturato con Protocol Buffers

La strutturazione dei dati svolge un ruolo importante nello sviluppo di programmi e siti web. Se i dati di un progetto sono ben strutturati, possono essere letti da altri software con facilità e precisione. Sul web, questo è particolarmente importante 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 strutturato.

In generale, l’utilizzo di dati strutturati nello sviluppo software, sia per applicazioni web sia desktop, è utile ovunque i programmi o i servizi debbano scambiare dati tramite interfacce e si desideri un’elevata velocità di elaborazione dei dati. Questo articolo spiega il ruolo che può svolgere il formato di serializzazione Protocol Buffers (Protobuf) e come questo metodo di strutturazione si differenzia dalla ben nota alternativa 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 originariamente sviluppato per uso interno come progetto open source (parzialmente con licenza Apache 2.0). Il formato binario consente alle applicazioni di memorizzare e scambiare dati strutturati in modo semplice; questi programmi possono anche essere scritti in diversi linguaggi di programmazione. Tra i linguaggi supportati vi sono:

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

Protobuf viene utilizzato, tra l’altro, in combinazione con HTTP e RPC (Remote Procedurel Calls) per la comunicazione client-server locale e remota, in particolare per la descrizione delle interfacce necessarie a questo scopo. La composizione del protocollo è definita anche con la sigla gRPC.

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 protocollo di Google?

Nello sviluppo di Protobuf, Google ha posto particolare enfasi su due fattori: semplicità e prestazione. In origine, come già detto, il formato era destinato a sostituire l’analogo formato XML all’interno dell’azienda. Oggi è in concorrenza anche con altre soluzioni, come JSON(P) o FlatBuffers. Un’analisi delle caratteristiche e dei punti di forza di questo metodo di strutturazione mostra che i Protocol Buffers rappresentano comunque la scelta migliore per molti progetti:

Schemi di applicazione chiari e incrociati

La base di ogni applicazione di successo è un sistema di database ben organizzato. L’organizzazione di questo sistema, compresi i dati in esso contenuti, è spesso oggetto di molta attenzione, ma quando successivamente i dati vengono inoltrati a un servizio esterno, le strutture sottostanti vanno perse. Codificando i dati secondo lo schema dei Protocol Buffers, è garantito che il vostro progetto inoltri i dati strutturati come desiderato, senza rompere queste strutture.

Retrocompatibilità e compatibilità in avanti

L’implementazione di Protobuf elimina il noioso compito di eseguire i controlli di versione, di solito associato al cosiddetto codice “ugly” (it. brutto, scritto male.) Per mantenere la compatibilità all’indietro con le versioni precedenti e la compatibilità in avanti con le nuove versioni, i buffer di protocollo accedono a campi numerati che fungono da punti di riferimento per l’accesso ai servizi. Ciò significa che non è sempre necessario adattare il codice completo per rilasciare nuove caratteristiche e funzioni.

Flessibilità e comfort

Con la codifica del Protobuf, si utilizzano automaticamente dei modificatori (a scelta tra richiesti, opzionali o ripetitivi) che rendono il lavoro di programmazione molto più facile. Ad esempio, il metodo di strutturazione permette di determinare la forma della struttura dei dati a livello di schema, dove i dettagli d’implementazione delle classi utilizzate per i diversi linguaggi di programmazione sono regolati automaticamente. Inoltre, è possibile modificare lo stato in qualsiasi momento, ad esempio da “richiesto” a “opzionale”. Anche la trasmissione delle strutture dati può essere regolata tramite i buffer di protocollo: codificando le strutture generiche di richiesta e risposta, si garantisce facilmente un trasferimento dati flessibile e sicuro tra più servizi.

Riduzione del codice Boilerplate

A seconda del tipo e della complessità di un progetto, il codice Boilerplate (o semplicemente Boilerplate) gioca un ruolo più o meno decisivo nella programmazione. In parole povere, si tratta di blocchi di codice riutilizzabili, necessari in molti punti di un software e di solito solo leggermente adattabili. Spesso tale codice serve, ad esempio, a predisporre l’utilizzo delle funzioni delle librerie. Essi sono comuni soprattutto nei linguaggi web JavaScript, PHP, HTML e CSS, anche se ciò non è ottimale per le prestazioni dell’applicazione web. Un adeguato schema di Procotol Buffers aiuta a ridurre il codice Boilerplate e quindi a migliorare le prestazioni a lungo termine.

Semplice interoperabilità tra linguaggi

Oggi le applicazioni non sono più scritte in un solo linguaggio, ma combinano parti di programma o moduli di diversi tipi di linguaggio. Protobuf semplifica notevolmente l’interazione dei singoli componenti del codice: se vengono aggiunti nuovi componenti il cui linguaggio differisce da quello corrente del progetto, è sufficiente far tradurre lo schema dei Protocol Buffers nel rispettivo linguaggio di destinazione utilizzando l’apposito generatore di codice, riducendo così al minimo il proprio sforzo. Naturalmente, i linguaggi utilizzati devono essere quelli supportati 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 sviluppato i Protocol Buffers come alternativa a XML (Extensible Markup Language) e ha superato il linguaggio di markup su molti aspetti. Ad esempio, la strutturazione 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 confrontati anche con il linguaggio di markup JavaScript JSON (JavaScript Object Notation), anche se va detto che entrambe le tecnologie sono state progettate con obiettivi diversi: JSON è un formato di messaggio che ha origine in JavaScript, scambia i suoi messaggi in formato testo ed è supportato praticamente da tutti i comuni linguaggi di programmazione. Protobuf ha più di un formato di messaggio, dal momento che la tecnologia Google offre anche varie regole e strumenti per definire e scambiare messaggi. Protobuf batte JSON anche in termini di prestazioni quando si guarda all’invio di messaggi in generale, ma la seguente tabella “Protobuf vs JSON” mette in evidenza che le due tecniche di strutturazione hanno ciascuna i propri vantaggi e svantaggi:

  Protobuf JSON
Sviluppatore Google Douglas Crockford
Funzioni Formato di markup per dati strutturati (memorizzazione e trasmissione) e libreria Formato di markup per dati strutturati (memorizzazione e trasmissione)
Formato binario No
Standardizzazione No
Leggibilità Parziale
Community/Documentazione Community ridotta, manuali online espandibili Community vasta, buona documentazione ufficiale, come tutorial online, ecc.

Quindi, se avete bisogno di un formato di serializzazione ben documentato che memorizzi e trasmetta i dati strutturati in forma chiaramente leggibile, dovreste usare JSON. Ciò è particolarmente vero se la componente lato server dell’applicazione è scritta in JavaScript e se gran parte dei dati viene elaborata di default direttamente dai browser. Se, d’altra parte, la flessibilità e le prestazioni della struttura dei dati giocano un ruolo decisivo, i buffer di protocollo tendono ad essere la soluzione più efficiente e più indicata.

Tutorial: introduzione pratica a Protobuf utilizzando l’esempio di Java

I buffer di protocollo possono fare la differenza in molti progetti software, ma come spesso accade, il primo passo è quello di conoscere e applicare le caratteristiche speciali e i trucchi sintattici della tecnologia di serializzazione. Per darvi una prima idea della sintassi e dello scambio di messaggi di Protobuf, nel seguente tutorial trovate i passaggi fondamentali, dalla definizione del proprio formato in file .proto alla compilazione delle strutture dei Protocol Buffers. Come esempio, viene utilizzato come codice base una semplice applicazione Java per la rubrica, che può leggere le informazioni 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 descrivere una qualsiasi struttura di dati che si intende implementare con i buffer di protocollo nel file .proto, il file di configurazione standard del formato di serializzazione. Per ogni struttura che si vuole serializzare in questo file, cioè mappare in sequenza, è sufficiente aggiungere un messaggio (“message”). Si specificano quindi i nomi e i tipi per ogni campo di questo messaggio e si aggiungono i modificatori desiderati. É obbligatorio un modificatore 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 protocollo ricorda fortemente C++ o Java. La versione Protobuf è sempre dichiarata in primo luogo qui: proto3, seguita dalla descrizione del pacchetto software di cui si vogliono strutturare i dati. Questo include un nome univoco (“tutorial”) e, in questo esempio di codice, le due opzioni specifiche per Java: “java_package” (pacchetto Java in cui sono memorizzate le classi generate) e “java_outer_classname” (nome della classe sotto la quale sono raggruppate 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 utilizzati nell’esempio. Come già detto, ad ogni campo di un messaggio deve essere assegnato almeno un modificatore e può essere:

  • required: un valore per questo campo è obbligatorio. Se questo valore manca, il messaggio rimane “uninitialized”, cioè non inizializzato o non inviato.
  • optional: un valore può essere fornito in un campo opzionale, ma non è necessario che lo sia. In caso contrario, viene utilizzato un valore definito come standard. Ad esempio, nel codice riportato sopra, per il tipo di numero di telefono viene inserito il valore predefinito “HOME” (numero di rete fissa di casa).
  • repeated: i campi con il modificatore “repeated” possono essere ripetuti tutte le volte che si desidera (anche zero volte).

Potete trovare istruzioni dettagliate su come definire il proprio formato di dati con i buffer di protocollo nel Google Developer Forum.

Compilare il proprio schema di buffer di protocollo

Una volta che le proprie strutture dati sono state definite nel file .proto come richiesto, generate le classi necessarie per leggere e scrivere i messaggi Protobuf. A tal fine applicate il compilatore di buffer di protocollo (protoc) al file di configurazione. Se non l’avete ancora installato, scaricate l’ultima versione nell’ufficiale GitHub Repository. Decomprimete il file ZIP nella posizione desiderata e avviate il compilatore con un doppio clic.

N.B.

Scaricate l’edizione appropriata del compilatore del Protobuf: Protoc è disponibile per architetture da 32 o 64 bit (Windows, Linux o macOS).

Infine, specificate

  • la directory sorgente dove si trova il codice del vostro programma (qui carattere jolly “SRC_DIR”),
  • la directory di destinazione dove deve essere memorizzato il codice generato (qui carattere jolly “DST_DIR”)
  • e il percorso per il file .proto.

Poiché si desidera generare classi Java, utilizzate anche l’opzione --java_out (opzioni simili sono disponibili anche per gli altri linguaggi supportati). Il comando completo per la compilazione è il seguente:

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

Un tutorial più dettagliato su Protobuf Java che spiega, tra le altre cose, la trasmissione di messaggi tramite buffer di protocollo (lettura/scrittura), è fornito da Google nella sezione “Developers”, l’area di progetti interni del grande motore di ricerca per gli sviluppatori. In alternativa, è possibile accedere ai tutorial per gli altri linguaggi supportati come C++, Go o Python.

Per offrirti una migliore esperienza di navigazione online questo sito web usa dei cookie, propri e di terze parti. Continuando a navigare sul sito acconsenti all’utilizzo dei cookie. Scopri di più sull’uso dei cookie e sulla possibilità di modificarne le impostazioni o negare il consenso.