Registro de esquemas y evolución de los datos
Por qué necesita un registro de esquemas
Un registro de esquemas es una fuente de verdad centralizada para contratos de datos (API, eventos, hilos, mensajes, repositorios) que proporciona:- Evolución predecible: reglas de compatibilidad y verificación automática de «roturas».
- Repetibilidad y transparencia: historial de versiones de quién/cuándo/por qué cambió.
- Estandarización: nombres únicos, formatos de error, campos de seguimiento, etiquetas PII.
- Integración con CI/CD: bloqueo de cambios de breaking antes de la producción.
El registro vincula Protocol-first y la compatibilidad contractual, lo que hace que los cambios sean rápidos y seguros.
Formatos y áreas de aplicación
JSON Schema: Cargamentos útiles, documentos, configuraciones.
Avro: bus de evento (Kafka/Pulsar), compacto/evolución a través del ID de campo.
Protobuf: gRPC/RPC, binario-eficaz, etiquetas estrictas.
GraphQL SDL: esquema de tipos y directivas, evolución a través de '@ deprecated'.
SQL DDL como artefacto: fijar representaciones contractuales (por ejemplo, escaparates externos) - con precaución.
Modos de compatibilidad
BACKWARD: los nuevos esquemas leen datos/mensajes antiguos. Adecuado para un productor que amplía el payload aditivamente.
FORWARD: los viejos consumidores leen correctamente los nuevos datos (requiere un lector tolerante).
FULL: combina ambos (más estricto, más conveniente para los contratos públicos).
NINGUNO: sin controles - sólo para sandbox.
- Eventos: más a menudo BACKWARD (el productor amplía el payload opcionalmente).
- API pública: FULL o BACKWARD + lector de tolerantes estrictos en los clientes.
- Prototipos internos: NO temporalmente, pero no en trunk.
Cambios seguros (aditivos) vs. peligrosos
Aditivo (OK):- Agrega un campo/tipo opcional.
- Extensión enum con nuevos valores (en tolerant reader).
- Agregar proyección/evento alternativo ('.enriched').
- Relajar las restricciones ('minLength', 'maximum' ↑, pero no ↓).
- Eliminar/cambiar el nombre de los campos o cambiar su tipo/obligatoriedad.
- Cambia la semántica de los estados/codecs/orden en los subprocesos.
- Volver a utilizar las etiquetas protobuf.
- Cambio de clave de partido en eventos.
Organización del registro
Neyming y direccionamiento
Grupos/espacios: 'payments', 'kyc', 'audit'.
Nombres: 'payment. authorized. v1` (events), `payments. v1. CaptureRequest` (gRPC), `orders. v1. Order` (JSON Schema).
Mayor en el nombre, menor en los metadatos/versión del esquema.
Metadatos
'owner' (comando), 'domain', 'slas' (SLO/SLA), 'security. tier` (PII/PCI), `retention`, `compatibility_mode`, `sunset`, `changelog`.
Administración del ciclo de vida
Draft → Review → Approved → Released → Deprecated → Sunset.
Validadores/linters automáticos, revisión de diseño manual (API Guild), notas de lanzamiento.
Integración en CI/CD
1. Pre-commit: linters locales (Spectral/Buf/Avro tools).
2. PR-pipeline: schema-diff → verificación del modo de compatibilidad; bloqueamos el breaking.
3. Artifact publish: push un esquema coherente en el registro + generación de modelos/SDK.
4. Runtime-guard (opcional): gateway/productor valida payload contra el esquema actual.
- `openapi-diff --fail-on-breaking`
- `buf breaking --against
` - `avro-compat --mode BACKWARD`
- generación de muestras de oro y pruebas de ejecución de CDC.
Evolución de los esquemas: prácticas
Additive-first: новые поля — `optional/nullable` (JSON), `optional` (proto3), default в Avro.
Modelo de pirámide inversa: el núcleo es estable, el enriquecimiento es cercano y opcional.
Dual-emit/dual-write para mayor: en paralelo publicamos 'v1' y 'v2'.
Plan Sunset: fechas, uso, advertencias, adaptadores.
Lector tolerante: los clientes ignoran campos desconocidos y manejan correctamente nuevos enum.
Ejemplos de esquemas y verificaciones
JSON Schema (fragmento, campo aditivo)
json
{
"$id": "orders.v1.Order",
"type": "object",
"required": ["id", "status"],
"properties": {
"id": { "type": "string", "format": "uuid" },
"status": { "type": "string", "enum": ["created", "paid", "shipped"] },
"risk_score": { "type": "number", "minimum": 0, "maximum": 1 }
},
"additionalProperties": true
}
Avro (default para compatibilidad)
json
{
"type": "record",
"name": "PaymentAuthorized",
"namespace": "payment.v1",
"fields": [
{ "name": "payment_id", "type": "string" },
{ "name": "amount", "type": "long" },
{ "name": "currency", "type": "string" },
{ "name": "risk_score", "type": ["null", "double"], "default": null }
]
}
Protobuf (no vuelva a usar las etiquetas)
proto syntax = "proto3";
package payments.v1;
message CaptureRequest {
string payment_id = 1;
int64 amount = 2;
string currency = 3;
optional double risk_score = 4; // additive
}
// tag=4 зарезервирован под risk_score, его нельзя менять/удалять без v2
Registro de eventos y lotes
Nomenclatura de eventos: 'domain. action. v{major}` (`payment. captured. v1`).
La clave de lote es parte del contrato ('payment _ id', 'user _ id').
Core vs Enriched: '.v1' (núcleo) y '.enriched. v1 '(piezas).
Compatibilidad en el registro: modos a nivel de tema/tipo; CI rechaza los cambios incompatibles.
Gestión de migraciones
Expand → Migrate → Contract (REST/gRPC):1. agregar campos/tablas 2) empezar a escribir/leer nuevos campos; 3) quitar el antiguo después de sunset.
- Dual-emit (Eventos): en paralelo 'v1 '/' v2', migración de consumers/proyecciones, luego disparando 'v1'.
- Replay: reenvía las proyecciones de un registro a un nuevo esquema (sólo si son compatibles y migradores).
- Adaptadores: gateway/proxy que traducen 'v1↔v2' para clientes complejos.
Seguridad y cumplimiento
Las etiquetas PII/PCI en el diagrama son: 'x-pii: true', 'x-sensitivity: high'.
Directivas de acceso: quién puede publicar/modificar esquemas (RBAC), firmar lanzamientos.
Criptografía: firma de versiones de esquemas, registros de auditoría (WORM) inmutables.
Derecho al olvido: especifique los campos que requieren encriptación/encriptación; guía en el registro.
Observabilidad y auditoría
Dashboards: número de cambios, tipos (menor/mayor), proporción de PR rechazados, uso de versiones.
Trail de auditoría: quién modificó el esquema, las referencias a PR/ADR, la versión asociada.
Runtime-métricas: porcentaje de mensajes que no han pasado la validación; incidentes de compatibilidad.
Herramientas (pila de ejemplo)
OpenAPI/JSON Schema: Spectral, OpenAPI Diff, Schemathesis.
Protobuf/gRPC: Buf, buf-breaking, protoc linters.
Avro/Events: Confluent/Redpanda Schema Registry, Avro-tools, Karapace.
GraphQL: GraphQL Inspector, GraphQL Codegen.
Registros/directorios: Registro de artefactos, Registro de bases Git, Catálogo de backstage, UI personalizado.
Documentación: Redocly/Stoplight, Swagger-UI, GraphiQL.
antipatterny
Swagger-wash: el esquema no refleja la realidad del servicio (o viceversa).
Comprobación de compatibilidad desactivada: «es urgente» → la apertura se rompe.
Volver a usar las etiquetas protobuf: la corrupción silenciosa de los datos.
Modo único de compatibilidad «para todo»: diferentes dominios requieren diferentes modos.
CDC crudos como circuitos públicos: fuga del modelo DB hacia el exterior, imposibilidad de evolución.
Lista de comprobación de implementación
- Se ha definido el formato de artefactos y el modo de compatibilidad por dominios.
- Los linters y schema-diff en el CI están configurados, el PR se bloquea cuando se rompe.
- Se incluye un lector de tolerantes en los clientes; 'additionalProperties = true' (cuando corresponda).
- Los cambios mayores pasan por RFC/ADR, hay un plan sunset y un dual-emit/dual-write.
- Los esquemas están marcados con PII/PCI y niveles de acceso; auditoría habilitada.
- Dashboards sobre el uso de versiones y fallos de compatibilidad.
- La generación de modelos/SDK a partir del registro es parte de la paipline.
- La documentación y los ejemplos de oro se actualizan automáticamente.
FAQ
¿Se pueden almacenar esquemas en Git sin registro?
Sí, pero el registro añade una API de compatibilidad, búsqueda, metadatos, política centralizada y validación «on-the-fly». La mejor opción es Git como storage + UI/políticas en la parte superior.
¿Cómo elegir el modo de compatibilidad?
Echa un vistazo a la dirección del cambio: si el productor expande el payload - BACKWARD. Para la API pública/SDK - FULL. Para prototipos rápidos - temporalmente NO (no en trunk).
¿Qué hacer si es necesario romper?
Preparamos v2: dual-emit/dual-run, sunset-dates, adaptadores, telemetría de uso, gaidas migratorias.
¿Es necesario validar el payload en el rantime?
Para dominios críticos, sí: evita los mensajes «basura» y acelera los diagnósticos.
Resultado
El registro de circuitos transforma la evolución de los datos de improvisación arriesgada en un proceso manejable: reglas de compatibilidad uniformes, validaciones automáticas, versiones comprensibles e historial transparente. Agregue la disciplina additive-first, tolerant reader, dual-emit y sunset - y sus contratos se desarrollarán rápidamente, sin roturas e incidentes nocturnos.