Protocol Buffers (Protobuf) es un formato binario de serialización de datos estructurados, desarrollado por Google para el intercambio eficiente de información entre servicios. El formato requiere una definición previa del esquema en archivos .proto, a partir de los cuales se genera código para varios lenguajes. Según la documentación oficial de Google, Protobuf proporciona tamaños de mensaje 3-10 veces menores que JSON. Protobuf se utiliza en gRPC, Google Maps y miles de servicios internos.
Puntos clave
Protocol Buffers es un mecanismo de serialización de datos estructurados desarrollado por Google, similar a JSON y XML, pero con una diferencia fundamental: los datos se codifican en formato binario. Esto significa que un mensaje Protobuf no se puede leer a simple vista, pero ocupa significativamente menos espacio y se procesa más rápido que sus contrapartes textuales.
Protobuf fue creado internamente en Google para solucionar problemas de rendimiento en el intercambio de datos entre servicios. En 2008, la tecnología se convirtió en un proyecto de código abierto con soporte para múltiples lenguajes: C++, Java, Python, Go, JavaScript, Kotlin, Swift, Dart y otros. La versión proto3, lanzada en 2016, simplificó la sintaxis y añadió soporte para más lenguajes.
La diferencia clave entre Protobuf y JSON es la necesidad de definir un esquema antes de comenzar el intercambio de datos. El archivo de esquema (.proto) describe la estructura del mensaje: campos, tipos y números únicos de campo. A partir de este esquema, el compilador protoc genera clases en el lenguaje de destino para la serialización y deserialización.
La arquitectura de Protobuf incluye tres componentes clave: el lenguaje de definición de esquemas (.proto), el compilador protoc y las bibliotecas de tiempo de ejecución para lenguajes específicos. El desarrollador describe la estructura de datos en un archivo .proto, ejecuta la compilación y recibe clases listas para trabajar con estos datos.
Cada campo en un mensaje Protobuf tiene un número único (field number) — no es un número secuencial, sino una etiqueta utilizada en el formato binario para identificar el campo. Los números del 1 al 15 se codifican en un byte, del 16 al 2047 en dos bytes. Por lo tanto, los campos importantes con alta frecuencia de uso deben numerarse del 1 al 15 para optimizar el tamaño.
Protobuf admite una amplia gama de tipos: escalares (int32, int64, float, double, bool, string, bytes), enumeraciones (enum), compuestos (message) y tipos especiales (oneof, map). Cada tipo tiene una representación binaria específica optimizada para el caso de uso correspondiente.
| Tipo .proto | Tipo C++ | Java/Kotlin | Descripción |
|---|---|---|---|
| double | double | double | Número de punto flotante de 64 bits |
| float | float | float | Número de punto flotante de 32 bits |
| int32 | int32 | int | 32 bits, codificación de longitud variable |
| int64 | int64 | long | 64 bits, codificación de longitud variable |
| string | string | String | Cadena UTF-8 |
| bytes | string | ByteString | Bytes arbitrarios |
| bool | bool | boolean | true / false |
Protobuf ofrece tres ventajas clave sobre los formatos textuales: tamaño del mensaje, velocidad de serialización y tipado fuerte. En sistemas de alta carga y aplicaciones móviles con tráfico limitado, estas ventajas se vuelven críticas.
La representación binaria de Protobuf utiliza codificación de longitud variable (Varint) para números: los números pequeños ocupan 1 byte, los grandes hasta 10 bytes. Esto permite codificar eficientemente identificadores, banderas y contadores que ocuparían decenas de bytes como cadenas de texto en JSON o XML. Por ejemplo, el número 150 en Protobuf ocupa 2 bytes, en JSON — 3 bytes (como texto “150”), en XML — 3 bytes + etiquetas.
Una ventaja adicional es la compatibilidad hacia atrás. Agregar un nuevo campo al esquema no rompe los clientes antiguos: simplemente ignoran los campos desconocidos. Eliminar un campo solo requiere reservar su número para evitar colisiones en el futuro.
El esquema .proto describe la estructura de datos en un lenguaje especial. El archivo comienza con la especificación de la sintaxis (proto3), el paquete y las dependencias de importación. Cada mensaje se define con la palabra clave message con campos, donde cada campo tiene un tipo, nombre y número único.
Buenas prácticas de esquema: números de campo del 1 al 15 para campos usados frecuentemente, nombres significativos, agrupación de campos relacionados en un mensaje separado, uso de oneof para campos que solo pueden ser una de varias opciones.
syntax = "proto3";
package mobileapp;
message User {
string user_id = 1;
string name = 2;
string email = 3;
int32 age = 4;
UserRole role = 5;
repeated string tags = 6;
map<string, string> metadata = 7;
}
enum UserRole {
USER_ROLE_UNSPECIFIED = 0;
USER_ROLE_USER = 1;
USER_ROLE_ADMIN = 2;
USER_ROLE_MODERATOR = 3;
}
Los mensajes pueden estar anidados: un campo profile de tipo Profile contendrá datos de usuario internamente. El soporte de anidación permite describir estructuras jerárquicas complejas sin duplicar definiciones.
syntax = "proto3";
package mobileapp;
message Order {
string order_id = 1;
repeated OrderItem items = 2;
double total_price = 3;
PaymentInfo payment = 4;
}
message OrderItem {
string product_id = 1;
string title = 2;
int32 quantity = 3;
double price = 4;
}
message PaymentInfo {
string method = 1;
string transaction_id = 2;
double amount = 3;
}
El compilador protoc convierte archivos .proto en código fuente en el lenguaje de destino. Para Kotlin/Java se usa el parámetro --java_out, para Swift --swift_out (a través del plugin Apple Swift Protobuf), para Dart --dart_out. Las clases generadas contienen métodos builder para construir mensajes y métodos de serialización/deserialización.
En Android, para trabajar con Protobuf se usa el plugin com.google.protobuf versión 0.9+ en Gradle. Después de agregar el plugin y especificar los archivos .proto, la compilación genera automáticamente clases Kotlin listas para usar en la aplicación.
import com.google.protobuf.kotlin.toByteString
import com.example.mobileapp.UserOuterClass.User
fun createUser(): User {
return User.newBuilder()
.setUserId("usr_001")
.setName("IT Sectr")
.setEmail("team@itsectr.com")
.setAge(5)
.setRole(UserOuterClass.UserRole.USER_ROLE_ADMIN)
.addTags("mobile")
.addTags("backend")
.build()
}
fun serializeAndDeserialize(user: User): User {
// Serialización a formato binario
val bytes = user.toByteArray()
// Deserialización desde formato binario
return User.parseFrom(bytes)
}
Protobuf es especialmente efectivo en arquitectura de microservicios y aplicaciones móviles. Consideremos un escenario típico: una aplicación móvil recibe una lista de productos del servidor a través de gRPC. El mensaje Protobuf contiene información del producto incluyendo identificador, nombre, precio y categoría. El formato binario reduce el tamaño de la respuesta entre 5 y 8 veces en comparación con JSON.
Ejemplo de un servicio gRPC con Protobuf en el lado del servidor. El servicio declara el método RPC GetProducts, que acepta una solicitud con parámetros de paginación y devuelve una lista de productos. La implementación en Kotlin usa clases generadas para trabajar con solicitudes y respuestas.
import com.example.mobileapp.ProductServiceGrpcKt
import com.example.mobileapp.ProductOuterClass.Product
import com.example.mobileapp.ProductOuterClass.GetProductsRequest
import com.example.mobileapp.ProductOuterClass.GetProductsResponse
class ProductService : ProductServiceGrpcKt.ProductServiceCoroutineImplBase() {
override suspend fun getProducts(
request: GetProductsRequest
): GetProductsResponse {
val products = fetchProductsFromDb(
page = request.page,
limit = request.limit
)
return GetProductsResponse.newBuilder()
.addAllProducts(products)
.setTotalCount(products.size)
.build()
}
}
La configuración de Protobuf en un proyecto Android se realiza a través del plugin de Gradle com.google.protobuf. El plugin ejecuta automáticamente el compilador protoc durante la compilación y genera clases Kotlin a partir de archivos .proto. Para funcionar, debes agregar el plugin al build.gradle del proyecto y aplicarlo en el módulo de la aplicación.
Después de configurar Gradle, los archivos .proto se colocan en el directorio src/main/proto. El compilador protoc los procesa durante cada compilación, generando clases Kotlin que se pueden usar en el código de la aplicación. Es importante especificar correctamente las versiones de protobuf y protoc para evitar conflictos de dependencias con otras bibliotecas del proyecto.
Para proyectos iOS, Protobuf se conecta a través de CocoaPods o Swift Package Manager. El plugin Swift Protobuf genera automáticamente estructuras Swift que cumplen con el protocolo Codable. En proyectos Dart para Flutter, se usa el paquete protobuf y la compilación se realiza mediante dart run protoc_plugin.
Preguntas frecuentes
Protobuf es un formato binario con un esquema obligatorio, de 3 a 10 veces más compacto que JSON. JSON es textual, legible por humanos y no requiere esquema. Protobuf serializa y deserializa más rápido pero requiere compilación de archivos .proto. JSON es más fácil de depurar y no requiere configuración previa.
Descargue protoc desde el lanzamiento de GitHub de protobuf para su plataforma. Para macOS, instale mediante brew install protobuf. Para Windows, descargue el archivo zip y agregue protoc.exe al PATH. Para Android/Kotlin, use el plugin de Gradle com.google.protobuf, que ejecuta automáticamente la compilación durante la construcción.
gRPC es un framework RPC de alto rendimiento de Google que utiliza Protobuf como lenguaje de definición de interfaces (IDL) y formato de serialización. gRPC define servicios y métodos RPC en archivos .proto, genera código de cliente y servidor, y admite transmisión por streaming y protocolos binarios.
Compatible oficialmente por Google: C++, Java, Kotlin, Python, Go, Ruby, C#, PHP, JavaScript, Objective-C, Swift y Dart. La comunidad ha desarrollado soporte para Rust, TypeScript, Scala, Lua y otros lenguajes. Para desarrollo móvil, están disponibles Kotlin/Java (Android) y Swift/Objective-C (iOS).
Protobuf admite compatibilidad hacia atrás mediante estas reglas: no cambie los números de campo, no elimine campos (use reserved), agregue nuevos campos con nuevos números. Los clientes antiguos ignoran los campos desconocidos, los nuevos clientes obtienen valores predeterminados para los campos antiguos faltantes.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también