Die Struk­tu­rie­rung von Daten spielt bei der Ent­wick­lung von Pro­gram­men und Websites eine wichtige Rolle. Sind die Daten eines Projekts nämlich gut struk­tu­riert, lässt es sich von anderer Software gut und präzise auslesen. Im Web ist das vor allem wichtig für die text­ba­sier­ten Such­ma­schi­nen wie Google, Bing oder Yahoo, die den Inhalt einer Website dank ent­spre­chen­der, struk­tu­rier­ter Aus­zeich­nun­gen optimal erfassen können.

Generell lohnt sich der Einsatz von struk­tu­rier­ten Daten in der Soft­ware­ent­wick­lung – ob für Web- oder Desktop-An­wen­dun­gen – überall dort, wo Programme bzw. Dienste Daten über Schnitt­stel­len aus­tau­schen müssen und eine hohe Da­ten­ver­ar­bei­tungs­ge­schwin­dig­keit gewünscht ist. Welche Rolle dabei das Se­ria­li­sie­rungs­for­mat Protocol Buffers (Protobuf) spielen kann und wie sich diese Struk­tu­rie­rungs­me­tho­de von der bekannten Al­ter­na­ti­ve JSONP un­ter­schei­det, erfahren Sie in diesem Artikel.

Was ist Protobuf (Protocol Buffers)?

Seit 2008 bietet Google mit Protocol Buffers, kurz Protobuf, ein ur­sprüng­lich für die interne Ver­wen­dung ent­wi­ckel­tes Da­ten­aus­tausch­for­mat als Open-Source-Projekt (teilweise Apache-2.0-Lizenz) der breiten Öf­fent­lich­keit an. Das binäre Format er­mög­licht An­wen­dun­gen die Spei­che­rung sowie den un­kom­pli­zier­ten Austausch struk­tu­rier­ter Daten, wobei diese Programme sogar in ver­schie­de­nen Pro­gram­mier­spra­chen ge­schrie­ben sein können. Zu den un­ter­stütz­ten Sprachen zählen unter anderem folgende:

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

Protobuf wird unter anderem in Kom­bi­na­ti­on mit HTTP und RPCs (Remote Procedure Calls) für die lokale und die entfernte Client-Server-Kom­mu­ni­ka­ti­on verwendet – ins­be­son­de­re zur Be­schrei­bung der hierfür be­nö­tig­ten Schnitt­stel­len. Die Pro­to­koll­zu­sam­men­set­zung wird auch unter der Be­zeich­nung gRPC zu­sam­men­ge­fasst.

Welche Vorteile bietet Google Protocol Buffers?

Bei der Ent­wick­lung von Protobuf hat Google ins­be­son­de­re auf zwei Faktoren Wert gelegt: Sim­pli­zi­tät und Per­for­mance. Zum damaligen Ent­wick­lungs­zeit­punkt sollte das Format – wie bereits erwähnt zunächst un­ter­neh­mens­in­tern – das ähnlich geartete XML-Format ablösen. Heute steht es zudem in Kon­kur­renz zu anderen Lösungen wie JSON(P) oder Flat­Buf­fers. Dass Protocol Buffers dennoch für viele Projekte die bessere Wahl ist, macht eine Analyse der Merkmale und Stärken dieser Struk­tu­rie­rungs­me­tho­de deutlich:

Über­sicht­li­che, an­wen­dungs­über­grei­fen­de Schemata

Die Basis jeder er­folg­rei­chen Anwendung ist ein gut or­ga­ni­sier­tes Da­ten­bank­sys­tem. Der Or­ga­ni­sa­ti­on dieses Systems inklusive der ent­hal­te­nen Daten wird häufig eine hohe Beachtung geschenkt – doch spä­tes­tens, wenn die Daten an einen fremden Dienst wei­ter­ge­lei­tet werden, gehen die zu­grun­de­lie­gen­den Struk­tu­ren verloren. Durch die einmalige Kodierung der Daten im Protocol-Buffers-Schema lässt sich si­cher­stel­len, dass Ihr Projekt struk­tu­rier­te Daten wie gewünscht wei­ter­lei­tet, ohne dass diese Struk­tu­ren auf­ge­bro­chen werden.

Rückwärts- und Vor­wärts­kom­pa­ti­bi­li­tät

Die Im­ple­men­tie­rung von Protobuf erübrigt die lästige Durch­füh­rung von Ver­si­ons­über­prü­fun­gen, die in der Regel mit „ugly“ Code (dt. häss­li­cher, un­sau­be­rer Code) verbunden ist. Um die Ab­wärts­kom­pa­ti­bi­li­tät zu älteren Versionen bzw. Vor­wärts­kom­pa­ti­bi­li­tät zu neuen Versionen auf­recht­erhal­ten zu können, greift Protocol Buffers auf num­me­rier­te Felder zurück, die zu­grei­fen­den Services als Be­zugs­punk­te dienen. Um neue Features und Funk­tio­nen zu ver­öf­fent­li­chen, müssen Sie also nicht immer unbedingt den kom­plet­ten Codes anpassen.

Fle­xi­bi­li­tät und Komfort

Bei der Protobuf-Codierung greifen Sie au­to­ma­tisch auf Mo­di­fi­ka­to­ren (wahlweise: vor­aus­ge­setzt, optional oder sich wie­der­ho­lend) zurück, die Ihnen die Pro­gram­mier­ar­beit erheblich ver­ein­fa­chen. So er­mög­licht die Struk­tu­rie­rungs­me­tho­de, dass Sie die Form Ihrer Da­ten­struk­tur auf Sche­mae­be­ne bestimmen, woraufhin die Im­ple­men­tie­rungs­de­tails der ver­wen­de­ten Klassen für die ver­schie­de­nen Pro­gram­mier­spra­chen au­to­ma­tisch geregelt werden. Zudem können Sie den Status jederzeit anpassen, bei­spiels­wei­se von „vor­aus­ge­setzt“ auf „optional“. Auch der Transport der Da­ten­struk­tu­ren lässt sich durch Protocol Buffers re­gu­lie­ren: Durch die Kodierung ge­ne­ri­scher Anfrage- und Ant­wort­struk­tu­ren ist ein flexibler und sicherer Da­ten­trans­fer zwischen mehreren Diensten auf einfache Weise ge­währ­leis­tet.

Weniger Boi­ler­p­la­te-Code

Je nach Typ und Kom­ple­xi­tät eines Projekts spielt Boi­ler­p­la­te-Code (oder einfach nur Boi­ler­p­la­te) eine mehr oder weniger ent­schei­den­de Rolle bei der Pro­gram­mie­rung. Ver­ein­facht gesagt handelt es sich dabei um wie­der­ver­wend­ba­re Code-Bausteine, die an vielen Stellen einer Software benötigt werden und für ge­wöhn­lich nur ge­ring­fü­gig anpassbar sind. Häufig dient solcher Code bei­spiels­wei­se dazu, die Nutzung von Funk­tio­nen aus Bi­blio­the­ken vor­zu­be­rei­ten. Ins­be­son­de­re in den Web­spra­chen Ja­va­Script, PHP, HTML und CSS sind Boi­ler­pla­tes ver­brei­tet, obgleich das nicht optimal für die Per­for­mance der Web­an­wen­dung ist. Ein passendes Procotol-Buffers-Schema hilft dabei, den Boi­ler­p­la­te-Code zu re­du­zie­ren und somit die Leistung lang­fris­tig zu ver­bes­sern.

Einfache Sprach­in­ter­ope­ra­bi­li­tät

Es zählt zum heutigen Standard, dass An­wen­dun­gen nicht einfach nur mehr in einer Sprache ge­schrie­ben sind, sondern Pro­gramm­tei­le bzw. -module ver­schie­dens­ter Sprach­ty­pen vereinen. Protobuf ver­ein­facht das Zu­sam­men­spiel der einzelnen Code-Be­stand­tei­le erheblich: Werden neue Kom­po­nen­ten hin­zu­ge­fügt, deren Sprache von der aktuellen Pro­jekt­spra­che abweicht, lassen Sie das Protocol-Buffers-Schema einfach mithilfe des passenden Code-Ge­ne­ra­tors in die jeweilige Ziel­spra­che über­set­zen, wodurch der eigene Aufwand auf ein Minimum reduziert wird. Vor­aus­set­zung ist natürlich, dass es sich bei den ver­wen­de­ten Sprachen um solche handelt, die von Protobuf un­ter­stützt werden – stan­dard­mä­ßig, wie die bereits auf­ge­zähl­ten Sprachen, oder per Dritt­an­bie­ter-Add-on.

Protobuf vs. JSON: Die beiden Formate im Vergleich

In erster Linie hat Google Protocol Buffers als Al­ter­na­ti­ve zu XML (Ex­ten­si­ble Markup Language) ent­wi­ckelt und die Aus­zeich­nungs­spra­che in vielerlei Hinsicht auch über­trof­fen. So ist die Struk­tu­rie­rung der Daten mit Protobuf ten­den­zi­ell nicht nur einfacher, sondern sorgt laut den Angaben des Such­ma­schi­nen­rie­sens auch für eine Da­ten­struk­tur, die zwischen drei bis zehn Mal kleiner und 20 bis 100 Mal schneller als eine ver­gleich­ba­re XML-Struktur ist.

Auch mit der Ja­va­Script-Aus­zeich­nungs­spra­che JSON (JavaScript Object Notation) tritt Protocol Buffers häufig in den direkten Vergleich, wobei aber zu erwähnen ist, dass beide Tech­no­lo­gien mit un­ter­schied­li­chen Ziel­set­zun­gen designt wurden: JSON ist ein Nach­rich­ten­for­mat, das aus Ja­va­Script her­vor­ge­gan­gen ist, seine Nach­rich­ten im Text­for­mat aus­tauscht und von praktisch allen gängigen Pro­gram­mier­spra­chen un­ter­stützt wird. Der Funk­ti­ons­um­fang von Protobuf umfasst mehr als ein Nach­rich­ten­for­mat, denn die Google-Technik bietet zu­sätz­lich auch diverse Regeln und Werkzeuge, um die Nach­rich­ten zu de­fi­nie­ren und aus­zu­tau­schen. Grund­sätz­lich sticht Protobuf JSON auch in Sachen Per­for­mance aus, wenn man den Nach­rich­ten­ver­sand im Ge­ne­rel­len be­trach­tet, doch die folgende ta­bel­la­ri­sche „Protobuf vs. JSON“-Auf­lis­tung zeigt, dass beide Struk­tu­rie­rungs­tech­ni­ken ihre Vor- und Nachteile haben:

Protobuf JSON
Ent­wick­ler Google Douglas Crockford
Funktion Aus­zeich­nungs­for­mat für struk­tu­rier­te Daten (Spei­che­rung und Über­tra­gung) und Bi­blio­thek Aus­zeich­nungs­for­mat für struk­tu­rier­te Daten (Spei­che­rung und Über­tra­gung)
Binäres Format ja nein
Stan­dar­di­sie­rung nein ja
Men­schen­les­bar­keit teilweise ja
Community/Do­ku­men­ta­ti­on kleine Community, aus­bau­fä­hi­ge Online-Manuals riesige Community, gut of­fi­zi­el­le Do­ku­men­ta­ti­on sowie diverse Online-Tutorials etc.

Wer also ein gut do­ku­men­tier­tes Se­ria­li­sie­rungs­for­mat benötigt, das die struk­tu­rier­ten Daten in für Menschen lesbarer Form speichert und überträgt, sollte anstelle von Protocol Buffers auf JSON zu­rück­grei­fen. Das gilt ins­be­son­de­re dann, wenn der ser­ver­sei­ti­ge Teil der Anwendung in Ja­va­Script ge­schrie­ben ist und wenn ein Großteil der Daten stan­dard­mä­ßig direkt von Browsern ver­ar­bei­tet wird. Spielt hingegen die Fle­xi­bi­li­tät und Per­for­mance der Da­ten­struk­tur eine ent­schei­den­de Rolle, ist Protocol Buffers ten­den­zi­ell die ef­fi­zi­en­te­re und bessere Lösung.

Tutorial: Prak­ti­sche Ein­füh­rung in Protobuf am Beispiel von Java

Protocol Buffers kann in vielen Soft­ware­pro­jek­ten den Un­ter­schied ausmachen, doch wie so häufig gilt es zunächst, die Be­son­der­hei­ten und syn­tak­ti­schen Kniffe der Se­ria­li­sie­rungs­tech­no­lo­gie kennen und anwenden zu lernen. Um Ihnen einen ersten Eindruck von der Syntax und dem Nach­rich­ten­aus­tausch von Protobuf zu ver­schaf­fen, erklärt das folgende Tutorial die ele­men­ta­ren Schritte mit Protobuf – von der De­fi­ni­ti­on des eigenen Formats in einer .proto-Datei bis hin zum Kom­pi­lie­ren der Protocol-Buffers-Struk­tu­ren. Ex­em­pla­risch wird dabei eine einfache Java-Adress­buch--Anwendung als Code-Grundlage verwendet, die Kon­takt­in­for­ma­tio­nen aus einer Datei lesen und in eine Datei schreiben kann. Jedem Adress­buch­ein­trag sind dabei die Parameter „Name“, „ID“, „E-Mail-Adresse“ und „Te­le­fon­num­mer“ zu­ge­ord­net.

Das eigene Da­ten­for­mat in der .proto-Datei de­fi­nie­ren

Jegliche Da­ten­struk­tur, die Sie mit Protocol Buffers rea­li­sie­ren möchten, be­schrei­ben Sie zunächst in der .proto-Datei, der stan­dard­mä­ßi­gen Kon­fi­gu­ra­ti­ons­da­tei des Se­ria­li­sie­rungs­for­mats. Für jede Struktur, die Sie in dieser Datei se­ria­li­sie­ren – also auf­ein­an­der­fol­gend abbilden – möchten, fügen Sie hierfür einfach eine Nachricht („message“) hinzu. An­schlie­ßend spe­zi­fi­zie­ren Sie Namen und Typen für jedes Feld dieser Nachricht und hängen den bzw. die ge­wünsch­ten Mo­di­fi­ka­tor(en) an. Ein Mo­di­fi­ka­tor pro Feld ist dabei Pflicht.

Für das Java-Adress­buch sieht eine mögliche Abbildung der Da­ten­struk­tu­ren in der .proto-Datei fol­gen­der­ma­ßen aus:

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;
}

Die Syntax von Protocol Buffers erinnert also stark an C++ oder Java. Die Protobuf-Version wird dabei immer an erster Stelle de­kla­riert (hier proto3), gefolgt von der Be­schrei­bung des Soft­ware­pa­kets, dessen Daten Sie struk­tu­rie­ren möchten. Dazu zählen ein ein­deu­ti­ger Name („tutorial“) und in diesem Code-Beispiel die beiden Java-spe­zi­fi­schen Optionenjava_package“ (Java-Paket, in dem die ge­ne­rier­ten Klassen ge­spei­chert werden) und „java_outer_classname“ (definiert den Klas­sen­na­men, unter dem die Klassen zu­sam­men­ge­fasst werden).

Es folgen die Protobuf-Nach­rich­ten, die sich aus beliebig vielen Feldern zu­sam­men­set­zen können, wobei die typischen Da­ten­ty­pen wie „bool“, „int32“, „float“, „double“, oder „string“ verfügbar sind. Diese kommen im Beispiel auch teilweise zum Einsatz. Jedem Feld einer Message muss dabei wie bereits erwähnt min­des­tens ein Mo­di­fi­ka­tor zu­ge­ord­net sein – also entweder …

  • required: Ein Wert für das Feld ist ver­pflich­tend. Fehlt dieser Wert, bleibt die Message „un­in­itia­li­zed“, also nicht in­itia­li­siert bzw. un­ver­schickt.
  • optional: In einem op­tio­na­len Feld kann ein Wert geliefert werden, muss aber nicht. Ist dies nicht der Fall, wird ein als Standard de­fi­nier­ter Wert verwendet. Im vor­an­ste­hen­den Code ist bei­spiels­wei­se der Stan­dard­wert „HOME“ (Fest­netz­num­mer Zuhause) für den Te­le­fon­num­mern­typ ein­ge­tra­gen.
  • repeated: Felder mit dem Mo­di­fi­ka­tor „repeated“ können beliebig oft wie­der­holt werden (ein­schließ­lich null Mal).

Eine aus­führ­li­che Anleitung zur De­fi­ni­ti­on des eigenen Da­ten­for­mats mit Protocol Buffers finden Sie im Google-Developer-Forum.

Das eigene Protocol-Buffers-Schema kom­pi­lie­ren

Sind die eigenen Da­ten­struk­tu­ren wie gewünscht in der .proto-Datei definiert, ge­ne­rie­ren Sie die Klassen, die zum Lesen und Schreiben der Protobuf-Nach­rich­ten benötigt werden. Zu diesem Zweck wenden Sie den Protocol-Buffers-Compiler (protoc) auf die Kon­fi­gu­ra­ti­ons­da­tei an. Sofern Sie diesen noch nicht in­stal­liert haben, laden Sie einfach die aktuelle Version im of­fi­zi­el­len GitHub-Re­po­si­to­ry herunter. Entpacken Sie die ZIP-Datei an ge­wünsch­ter Stelle und starten den Compiler an­schlie­ßend per Dop­pel­klick (befindet sich im „bin“-Ordner).

Hinweis

Achten Sie darauf, dass Sie die passende Edition des Protobuf-Compilers her­un­ter­la­den: Protoc ist wahlweise für 32- oder 64-Bit-Ar­chi­tek­tu­ren (Windows, Linux oder macOS) verfügbar.

Ab­schlie­ßend spe­zi­fi­zie­ren Sie

  • das Quell-Ver­zeich­nis, in dem der Code Ihres Programms liegt (hier Platz­hal­ter „SRC_DIR“),
  • das Ziel-Ver­zeich­nis, in das der ge­ne­rier­te Code ge­spei­chert werden soll (hier Platz­hal­ter „DST_DIR“)
  • und den Pfad zur .proto-Datei.

Da Sie Java-Klassen ge­ne­rie­ren möchten, nutzen Sie außerdem die Option --java_out (ähnliche Optionen gibt es auch für die anderen un­ter­stütz­ten Sprachen). Der voll­stän­di­ge Befehl für die Kom­pi­lie­rung lautet fol­gen­der­ma­ßen:

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

Ein aus­führ­li­che­res Protobuf-Java-Tutorial, in dem unter anderem auch die Nach­rich­ten­über­tra­gung via Protocol Buffers (Lesen/Schreiben) erklärt wird, bietet Google in der „De­ve­lo­pers“-Sektion an, dem haus­ei­ge­nen Pro­jekt­be­reich des Such­ma­schi­nen­rie­sens für Ent­wick­ler. Al­ter­na­tiv haben Sie dort auch Zugriff auf An­lei­tun­gen für die anderen un­ter­stüt­zen Sprachen wie C++, Go oder Python.

Zum Hauptmenü