En Sardine usamos protocol buffers (protobuf) en todas partes. Es un formato de serialización ligero, neutral en cuanto al lenguaje y con tipado.
Usamos protobuf para definir el esquema de datos de la tabla de BigQuery y también para generar el código del servidor backend (Go) a partir del mismo archivo protobuf. Nuestros servidores backend rellenan la estructura de Go (generada desde protobuf), la envían a Pub/Sub y luego los jobs de Dataflow la consumen en BigQuery.

Este sencillo patrón funcionó bastante bien con una salvedad. Cuando empezamos, no había una solución clara sobre cómo convertir un objeto de Pub/Sub en una inserción de fila de BigQuery, así que tuvimos que escribir código repetitivo como el siguiente para copiar datos de un objeto a otro:
TableRow clientMetadataRow = new TableRow() .set("session_key", clientMetadata.getSessionKey()) .set("client_id", clientMetadata.getClientId()) .set("revision", clientMetadata.getRevision()) .set("user_id", clientMetadata.getUserId())...
Esto era muy tedioso y propenso a errores. Cuando añadíamos un nuevo campo en la tabla de BigQuery, también teníamos que actualizar el código repetitivo anterior. Debe de haber una mejor solución para esto.
(nota al margen: si hoy empiezas un nuevo servicio, podrías usar JSON en lugar de protobuf como formato de serialización para pubsub y luego usar la plantilla oficial (beta) de Google para trabajos de pubsub a bigquery —https://cloud.google.com/dataflow/docs/guides/templates/provided-streaming)
Resulta que puedes iterar dinámicamente sobre un objeto protobuf, así que en lugar de codificar los nombres de los campos, podríamos hacer lo siguiente:
void copyFields(GeneratedMessageV3 fromProto, TableRow toRow) { allFields = fromProto.getDescriptorForType().getFields(); for (Descriptors.FieldDescriptor field: allFields) { Object value = fields.get(field); String columnName = field.getName(); switch (field.getJavaType()) { case STRING: if (value != null) { toRow.set(columnName, value); } break;...
Eso es todo. Redujo nuestro código boilerplate y ahora ya no tenemos que preocuparnos por actualizar el código Java (ten en cuenta que aún necesitas volver a desplegar el job de Dataflow ante cualquier cambio de esquema para que el ejecutor del job conozca la última definición del proto).
Hicimos público el código en el siguiente repositorio para que la comunidad no tenga que reinventar la rueda — https://github.com/sardine-ai/proto-to-bq-java
Si tienes algún comentario, por favor ponte en contacto conmigo https://twitter.com/kazukinishiura
Estamos contratando para todos los puestos de ingeniería — https://www.sardine.ai/careers

