Protobuf : un code structuré avec Protocol Buffers
Dans le développement de logiciels et de sites Internet, la structuration des données joue un rôle important. En effet, si les données d’un projet sont bien structurées, il pourra être lu par d’autres logiciels de façon efficace et précise. Sur le Web, ceci est tout particulièrement essentiel pour les moteurs de recherche basés sur du texte tels que Google, Bing ou Yahoo qui peuvent enregistrer le contenu d’un site internet de façon optimale grâce à des balises structurées correspondantes.
Dans le développement logiciel, l’utilisation des données structurées – que ce soit pour des applications Web ou de bureau – se révèle généralement avantageuse partout où les programmes et les services doivent échanger des données via des interfaces et où une vitesse de traitement des données élevée est désirée. Dans cet article, vous découvrirez quel rôle peut jouer le format de sérialisation Protocol Buffers (Protobuf) dans ce cadre et en quoi cette méthode de structuration se démarque de sa célèbre alternative JSONP.
Qu’est-ce que Protobuf (Protocol Buffers) ?
Avec Protocol Buffers, abrégé en Protobuf, Google met à disposition du grand public depuis 2008 un format d’échange de données initialement développé pour une utilisation interne sous forme de projet open source (pour partie sous licence Apache-2.0). Le format binaire permet aux applications d’enregistrer et d’échanger en toute simplicité des données structurées et ces programmes peuvent même être codés dans différents langages de programmation. Les langages suivants font notamment partie des langages supportés :
- C#
- C++
- Go
- Objective-C
- Java
- Python
- Ruby
Protobuf est notamment utilisé en association avec HTTP et RPC (Remote Procedurel Calls) pour la communication client-serveur locale et à distance – en particulier pour décrire les interfaces nécessaires dans ce cadre. La composition du protocole est également connue sous l’appellation gRPC.
Quels sont les avantages de Protocol Buffers de Google ?
Lors du développement de Protobuf, Google a fait tout particulièrement attention à deux facteurs : la simplicité et la performance. Au moment de son développement – qui, comme nous l’avons déjà indiqué plus haut, s’est déroulé en interne dans un premier temps –, ce format avait pour vocation de remplacer le format XML de nature similaire. Il fait aujourd’hui concurrence à d’autres solutions telles que JSON(P) ou FlatBuffers. Une analyse des caractéristiques et des points forts de cette méthode de structuration montre pourquoi Protocol Buffers constitue toutefois la solution idéale pour de nombreux projets.
Des schémas clairs et interapplications
Un système de base de données bien organisé constitue la base de toute application de qualité. L’organisation de ce système et des données qu’il contient se voit souvent accorder une priorité élevée, mais lorsque les données doivent être transmises à un service tiers, les structures sous-jacentes sont alors perdues. Un codage unique des données dans le schéma Protocol Buffers vous permet de veiller à ce que votre projet transmette les données structurées de la façon souhaitée, sans perdre les structures en question.
Compatibilité descendante et ascendante
L’implémentation de Protobuf rend superflue la réalisation laborieuse des contrôles de version qui se traduisent généralement par du code « moche » (en anglais « ugly code »). Afin de pouvoir maintenir la compatibilité descendante avec d’anciennes versions ou la compatibilité ascendante avec de nouvelles versions, Protocol Buffers utilise des champs numérotés servant de points de référence aux services procédant à l’accès. Pour publier de nouvelles fonctionnalités, il n’est donc pas toujours nécessaire d’adapter la totalité du code.
Confort et flexibilité
Le codage de Protobuf utilise automatiquement des modificateurs (au choix : optional, required ou repeated) permettant de simplifier considérablement la programmation. Cette méthode de structuration permet ainsi de déterminer la forme de la structure de données au niveau du schéma après quoi les détails de l’implémentation des classes utilisées sont automatiquement paramétrés pour les différents langages de programmation. D’autre part, vous pouvez modifier à tout moment le statut pour passer par exemple de « required » à « optional ». Le transport des structures de données peut également être réglé à l’aide de Protocol Buffers : un codage des structures de requête et de réponse génériques permet de garantir en toute simplicité un transfert des données plus flexible et plus sûr entre les différents services.
Moins de code boilerplate
L’importance du code boilerplate (parfois appelé simplement boilerplate) dans la programmation est fonction du type de projet et de sa complexité. En termes simples, il s’agit d’éléments de code réutilisables nécessaires en de nombreux endroits d’un logiciel et, généralement, peu personnalisables. Un tel code sert par exemple souvent à préparer l’utilisation des fonctionnalités issues des bibliothèques. Les boilerplates sont notamment répandus dans les langages web JavaScript, PHP, HTML et CSS même s’ils ne sont pas idéals pour la performance de l’application web. Un schéma Procotol Buffers adapté contribue à diminuer le code boilerplate et ainsi à améliorer la performance durablement.
Une interopérabilité linguistique simple
À l’heure actuelle, les applications standard ne sont plus uniquement codées dans un seul langage et combinent des éléments et des modules de programmes de différents types de langages. Protobuf facilite considérablement l’interaction des différents éléments de code : si de nouveaux composants avec un langage différent du langage actuel du projet sont ajoutés, il vous suffira de faire traduire le schéma Protocol Buffers dans le langage cible correspondant à l’aide du générateur de code adéquat ce qui permet de réduire les efforts nécessaires à un minimum. Pour ce faire, il est bien entendu nécessaire que les langages utilisés soient supportés par Protobuf (soit par défaut s’ils figurent dans les langages listés plus haut soit en ajoutant des plug-ins de fournisseurs tiers.
Protobuf vs. JSON : comparatif de ces deux formats
Google a tout d’abord développé Protocol Buffers comme une alternative au XML (Extensible Markup Language) et a surpassé ce langage de balisage sur de nombreux aspects. La structuration des données avec Protobuf a non seulement tendance à être plus simple, mais permettrait également – d’après le géant du numérique – une structure de données de trois à dix fois plus petite et de 20 à 100 fois plus rapide qu’une structure XML comparable.
Protocol Buffers est également souvent comparé avec le langage de balisage de JavaScript JSON (JavaScript Object Notation), mais il convient de noter que les deux technologies ont été conçues avec des objectifs différents : JSON est un format de messages découlant du JavaScript, échangeant les messages au format texte et supporté par la quasi-totalité des langages de programmation courants. La palette de fonctionnalités de Protobuf comprend plus d’un format de messages puisque la technologie de Google offre également des règles et des outils divers permettant de définir et d’échanger des messages. En principe, Protobuf supplante aussi JSON en matière de performance si l’on considère l’envoi de messages de façon générale, mais le tableau suivant « Protobuf vs. JSON » montre que les deux technologies de structuration présentent des avantages et des inconvénients :
Protobuf | JSON | |
---|---|---|
Développeur | Douglas Crockford | |
Fonction | Langage de balisage pour les données structurées (enregistrement et transmission) et les bibliothèques | Langage de balisage pour les données structurées (enregistrement et transmission) |
Format binaire | oui | non |
Standardisation | non | oui |
Lisible par l’homme | partiellement | oui |
Communauté/documentation | petite communauté, manuels en ligne pour approfondir | immense communauté, documentation officielle de qualité et divers tutoriels en ligne, etc. |
Par conséquent, si vous souhaitez un format de sérialisation bien documenté, enregistrant et transmettant les données structurées dans un format lisible par l’homme, vous devriez opter pour JSON plutôt que pour Protocol Buffers. C’est d’autant plus vrai si la partie serveur de l’application est écrite en JavaScript et si la majeure partie des données est traitée directement par les navigateurs par défaut. En revanche, si la flexibilité et la performance de la structure des données jouent pour vous un rôle essentiel, Protocol Buffers est habituellement la solution la plus efficace.
Tutoriel : introduction pratique à Protobuf avec l’exemple de Java
Protocol Buffers peut faire la différence dans de nombreux projets logiciels, mais comme souvent, il sera nécessaire dans un premier temps de connaître les particularités et les astuces syntaxiques de cette technologie de sérialisation et d’apprendre à les utiliser. Afin de vous donner un aperçu de la syntaxe et de l’échange de messages de Protobuf, le tutoriel suivant vous présente les premiers pas avec cette technologie – de la définition du format personnalisé dans un fichier .proto à la compilation des structures de Protocol Buffers. Pour l’exemple, nous avons pris comme base de code une simple application de carnet d’adresses Java qui permet de lire les données des contacts à partir d’un fichier et de les écrire dans un autre fichier. Chaque entrée du carnet d’adresses est dotée des paramètres « nom », « n° d’id. », « adresse e-mail » et « numéro de téléphone ».
Définir le format de données personnalisé dans le fichier .proto
Les structures de données que vous souhaitez réaliser avec Protocol Buffers doivent tout d’abord être décrites dans le fichier .proto. Il s’agit du fichier de configuration par défaut de ce format de sérialisation. Vous devez ajouter un message pour chaque structure que vous souhaitez sérialiser dans ce fichier (c’est-à-dire présenter sous la forme d’une suite d’informations). Spécifiez ensuite les noms et les types de chaque champ de ce message et ajoutez le/les modificateur(s) souhaité(s). Chaque champ doit comporter un modificateur.
Pour le carnet d’adresses Java, les structures de données du fichier .proto peuvent ressembler à ce qui suit :
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 syntaxe de Protocol Buffers rappelle fortement celle de C++ ou de Java. La version de Protobuf est toujours signalée en première position, ici proto3, et est suivie par la description du pack logiciel dont vous souhaitez structurer les données. Cette description inclut notamment un nom unique (« tutorial ») et dans cet exemple de code, les deux options spécifiques à Java « java_package » (paquet Java dans lequel sont enregistrées les classes générées) et « java_outer_classname » (qui définit les noms des classes).
Elle est suivie par les messages Protobuf qui peuvent comporter un nombre illimité de champs, sachant que les types de données typiques comme « bool », « int32 », « float », « double » ou « string » sont disponibles. Ces derniers sont pour partie utilisés dans l’exemple. Comme indiqué plus haut, chaque champ d’un message doit comporter au moins un modificateur parmi :
- required : ce champ impose une valeur. En l’absence de valeur, le message restera « uninitialized », c’est-à-dire non initialisé ou non envoyé.
- optional : un champ « optional » peut contenir une valeur, mais ce n’est pas impératif. En l’absence de valeur, une valeur standard est utilisée. Dans le code ci-dessus, on trouve par exemple la valeur standard « HOME » (numéro fixe du domicile) pour le type de numéro de téléphone.
- repeated : les champs avec le modificateur « repeated » peuvent être répétés à volonté (ou être absents, c’est-à-dire répétés zéro fois).
Vous trouverez un guide détaillé concernant la définition du format de données personnalisé avec Protocol Buffers sur le forum des développeurs de Google.
Compiler le schéma Protocol Buffers personnalisé
Une fois les structures de données personnalisées définies de la façon désirée dans le fichier .proto, générez les classes nécessaires à la lecture et à l’écriture des messages Protobuf. Pour ce faire, utilisez le compilateur Protocol Buffers (protoc) sur le fichier de configuration. Si vous ne l’avez pas encore installé, téléchargez simplement la dernière version dans le répertoire GitHub officiel. Décompressez le fichier ZIP à l’emplacement désiré et lancez le compilateur avec un double-clic (il se situe dans le dossier « bin »).
Veillez à bien télécharger la bonne version du compilateur Protobuf : Protoc est disponible pour les architectures 32 ou 64 bits (Windows, Linux ou macOS).
Spécifiez ensuite :
- le répertoire source dans lequel se trouve le code de votre programme (ici la balise « SRC_DIR »),
- le répertoire cible dans lequel le code généré devra être enregistré (ici la balise « DST_DIR »)
- et le chemin vers le fichier .proto.
Comme vous souhaitez aussi générer des classes Java, utilisez également l’option --java_out (il existe des options similaires pour les autres langages supportés). La commande complète pour la compilation est donc la suivante :
protoc -I=$SRC_DIR --java_out=$DST_DIR $SRC_DIR/addressbook.proto
Google propose un tutoriel Java Protobuf détaillé dans lequel est notamment expliquée la transmission des messages via Protocol Buffers (lecture/écriture) dans la section « Developers », l’espace de projet pour les développeurs du géant du numérique. Vous y trouverez également des notices pour les différents langages supportés tels que C++, Go ou Python.