{
 "subtemas": [],
 "tarjetas": [
  {
   "sub": "Datos y consistencia",
   "q": "Integración directa a la BD de otro servicio: por qué está prohibido",
   "a": "El dueño del esquema no puede cambiar nada sin romper a los demás (acoplamiento por schema), no hay control de acceso por negocio, no hay boundary de transacciones, dificulta refactor total.\nCorrecto: API (para queries puntuales) o eventos (para replicar datos que el otro necesita localmente).\nLa BD de un servicio es un detalle de implementación PRIVADO.",
   "nivel": "intermedio",
   "clave": true
  },
  {
   "sub": "Datos y consistencia",
   "q": "Replicación de datos entre servicios: read model local",
   "a": "Patrón: B necesita datos de A frecuentemente (nombre del cliente en 10k queries/min).\nEn vez de llamar a A siempre: A publica eventos de cambio → B mantiene COPIA LOCAL (tabla cliente_basico) actualizada por eventos.\nTrade-off: consistencia eventual + almacenamiento duplicado a cambio de latencia local e independencia de A.\nEs CQRS sin nombrarlo.",
   "nivel": "avanzado",
   "clave": true
  },
  {
   "sub": "Datos y consistencia",
   "q": "API composition: el agregador simple y su límite",
   "a": "Orquestador llama a N servicios y junta la respuesta (página de producto = catálogo + precio + stock).\nSimple y consistente-en-tiempo-real.\nLímite: latencia = suma/máx de llamadas, disponibilidad = producto de las partes, JOINs complejos (filtros cross-service) imposibles.\nEscala mal para queries analíticas → ahí entra CQRS con read model materializado.",
   "nivel": "intermedio",
   "clave": true
  },
  {
   "sub": "Datos y consistencia",
   "q": "Outbox pattern: implementación paso a paso",
   "a": "1) En la MISMA tx de negocio: INSERT entidad + INSERT outbox(event_id, tipo, payload, status=PENDING).\n2) Relay: poller SELECT ... WHERE pending FOR UPDATE SKIP LOCKED, o CDC (Debezium leyendo el WAL).\n3) Publicar a broker → marcar SENT (o dejar que el offset/CDC haga de marcador).\nGarantiza: evento sale si y solo si la tx confirmó. Nunca dual-write directo.",
   "nivel": "avanzado",
   "clave": true
  },
  {
   "sub": "Datos y consistencia",
   "q": "Inbox pattern: el complemento del outbox",
   "a": "El consumidor también tiene el problema: procesar mensaje + guardar resultado deben ser atómicos.\nSolución: en la tx de negocio, INSERT INTO inbox(message_id) — si viola unique, ya procesado (dedup atómica).\nOutbox (emisor) + Inbox (receptor) = entrega efectivamente exacta entre servicios con brokers at-least-once.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Datos y consistencia",
   "q": "2PC/XA: por qué los microservicios lo evitan",
   "a": "Two-phase commit bloquea recursos entre fases (prepare/commit): latencia y locks largos, el coordinador es SPOF, muchos recursos modernos (Kafka, HTTP APIs) no lo soportan.\nEscala mal horizontalmente.\nAlternativa: Saga (tx locales + compensaciones) — disponible eventualmente pero disponible siempre.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Datos y consistencia",
   "q": "Saga coreografiada: ejemplo pedido→pago→inventario",
   "a": "PedidoService crea pedido(PENDING) → publica PedidoCreado.\nPagoService escucha, cobra → PagoConfirmado / PagoRechazado.\nInventarioService reserva → StockReservado.\nPedidoService escucha todo → COMPLETADO (todo ok) o compensa (CANCELADO + reembolso si pago ya había ido).\nSin coordinador: cada servicio reacciona. Difícil de rastrear → tracing obligatorio.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Datos y consistencia",
   "q": "Saga orquestada: cuándo el coordinador central gana",
   "a": "Un orquestador (PedidoSaga) dirige: cobrar → reservar → crear envío, con estados y timeout por paso.\nVentaja: flujo visible en UN lugar, fácil de auditar/modificar, timeouts y compensaciones explícitas.\nDesventaja: coordinador puede engordar ('god service'), acople al conocer los pasos.\nRegla: flujos con >3 pasos o ramas → orquestada; simples 2-3 reacciones → coreografiada.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Datos y consistencia",
   "q": "Compensaciones de saga: transacciones que no son reversibles",
   "a": "Compensar NO es rollback: un pago compensable es reembolso (no 'deshacer'), un email enviado no se des-envía (compensación = enviar aviso de corrección).\nClasificar pasos: compensables (reembolso), pivot (el punto de no retorno — el pago capturado), retriable (envíos con retry).\nDiseño: poner el pivot LO MÁS TARDE posible.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Datos y consistencia",
   "q": "CQRS: read model materializado en la práctica",
   "a": "Write side: Cloud SQL normalizado, validación de invariantes.\nEventos (outbox) → proyección (worker) → read store: Elasticsearch (búsqueda), Redis (hot), Firestore (por usuario).\nReglas: proyecciones IDEMPOTENTES (reprocesar no rompe), versionadas (rebuild desde evento 0), lag monitoreado.\nConsulta nunca escribe: comandos van al write side.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Datos y consistencia",
   "q": "Event sourcing: aggregates, streams y snapshots",
   "a": "Stream por agregado (pedido-42): eventos ordenados con version/sequence (optimistic lock natural).\nEstado actual = fold de eventos; para performance: snapshot cada N eventos y aplicar solo los posteriores.\nComandos validan contra el estado reconstruido y APPENDIAN nuevos eventos (nunca UPDATE).\nConcurrencia: dos comandos sobre versión vieja → conflicto, reintentar.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Datos y consistencia",
   "q": "Event sourcing: upcasting y GDPR (crypto-shredding)",
   "a": "Upcasting: eventos versionados (PedidoCreado_v1, _v2) — transformer de versión vieja a nueva al leer; NUNCA reescribir historia.\nGDPR/borrar usuario: los eventos son inmutables → crypto-shredding: datos personales cifrados con clave POR USUARIO; borrar la clave = datos irrecuperables, eventos intactos.\nAlternativa: tokenización (el evento guarda token, los datos reales en vault borrable).",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Datos y consistencia",
   "q": "Anomalías de consistencia eventual (y sus defesas)",
   "a": "Stale read (saldo viejo), read-your-writes roto (creo pedido, no lo veo), monotonic read roto (veo versión nueva, luego vieja).\nDefensas: read-your-writes → leer del write model o sticky routing tras escritura; versiones/ETags; UI optimista (mostrar 'pendiente'); UX que tolera lag ('procesando...').\nDocumentar QUÉ tan eventual es cada dato (p50/p99 de lag) — el negocio decide si acepta.",
   "nivel": "avanzado",
   "clave": true
  },
  {
   "sub": "Datos y consistencia",
   "q": "Conflict resolution: LWW, versiones y CRDTs en una pincelada",
   "a": "Last-Write-Wins (timestamp): simple, pierde writes concurrentes — solo si la pérdida es aceptable (perfil de usuario).\nVersiones/tickets: rechazar writes sobre versión vieja (optimistic) → cliente resuelve.\nCRDT (counters, sets que convergen): cuando múltiples editores deben converger sin coordinación (carrito offline móvil).\nEvitar 'resolver en la BD' sin definir semántica de negocio.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Datos y consistencia",
   "q": "Migraciones entre servicios: expand-contract a través de límites",
   "a": "Mover 'cliente' del monolito a su servicio: 1) sincronizar por CDC a la nueva BD (dual write implícito), 2) monolito Lee de nuevo servicio vía API, 3) escrituras migradas (feature flag), 4) monitorear paridad, 5) cortar el flujo viejo, 6) drop tabla en monolito.\nCada paso reversible; cutover con flag, no con deploy.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Datos y consistencia",
   "q": "Caché distribuida en microservicios: dónde y con qué TTL",
   "a": "Niveles: caché de app local (Caffeine, microsegundos, por pod) + caché distribuida (Redis, ms, compartida) + HTTP/CDN (bordes).\nTTL por tolerancia al stale: precios 30-60s, catálogo 5-15min, config 1min.\nInvalidación activa por eventos cuando el stale duele (precio cambió → publish invalidation).\nJamás cachear autorización por largo TTL.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Datos y consistencia",
   "q": "Locks distribuidos: Redis SET NX y el fencing token",
   "a": "SET lock:key value NX PX 30000 → solo un cliente obtiene el lock; liberar con script Lua (comparar value para no borrar el lock ajeno).\nAdvertencia de Kleppmann: Redis async replication puede perder el lock (dos dueños) → usar FENCING TOKENS (número creciente verificado por el recurso) o etcd/ZooKeeper/Consul para correctividad estricta.\nPreguntarse siempre: ¿de verdad necesito el lock o basta optimismo (versiones)?",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Datos y consistencia",
   "q": "Materialized views: cuándo pre-construir la respuesta",
   "a": "Query costosa y frecuente (dashboard de ventas por región por mes) → materializar en tabla de lectura actualizada por eventos/agendado.\nCloud SQL: vistas materializadas; BigQuery: scheduled queries/MVs.\nTrade-off: espacio + staleness vs velocidad de lectura.\nPerfecto para reportes donde 'hace 5 minutos' es aceptable.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Datos y consistencia",
   "q": "Sharding de datos: cuándo y por qué casi nunca al inicio",
   "a": "Partir datos por clave (tenant, región) en múltiples BDs para escalar escrituras más allá de una máquina.\nCosto: queries cross-shard, rebalanceo, clave de shard mal elegida = hotspots, joins imposibles.\nAntes de sharding: índices, particionado, read replicas, caché, hardware mayor, CQRS.\nPostgres/Cloud SQL escala muchísimo antes de necesitar shards.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Datos y consistencia",
   "q": "CDC (Change Data Capture): Debezium y su rol moderno",
   "a": "Captura cambios del WAL/binlog de la BD y los publica como eventos en Kafka — SIN tocar el código de la app.\nUsos: outbox relay, sincronizar monolito→nuevos servicios (strangler), alimentar analítica/elastic en tiempo real.\nCuidados: eventos capturan CAMBIOS de fila (no eventos de negocio semánticos), schema evolution, orden por tabla.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Datos y consistencia",
   "q": "Exactly-once en la práctica: el stacking de garantías",
   "a": "Ningún sistema solo da exactly-once end-to-end; se compone:\nEmisor: outbox + (broker con dedup/idempotent producer).\nBroker: at-least-once con orden por clave o exactly-once (Kafka tx).\nConsumidor: inbox/dedup por message-id en la misma tx del efecto.\nEl 'exactly-once' real = at-least-once + idempotencia verificada en cada salto.",
   "nivel": "avanzado",
   "clave": false
  },
  {
   "sub": "Datos y consistencia",
   "q": "Weak vs strong consistency por tipo de dato: tabla de decisiones",
   "a": "Fuerte requerido: saldos, stock vendible, permisos, pagos.\nEventual aceptable: feeds, notificaciones, contadores de vistas, rankings, perfiles.\nGray zone (strong en escritura del dueño, eventual para lecturas de otros): catálogo, inventario mostrado.\nElegir por dato, no por sistema — mezclar en el mismo micro es normal.",
   "nivel": "intermedio",
   "clave": false
  },
  {
   "sub": "Datos y consistencia",
   "q": "CAP aplicado (de verdad): qué eliges cuando la red se parte",
   "a": "Ante partición, DEBES elegir: disponibilidad (aceptar writes que divergen — eventual, CRDTs) o consistencia (rechazar writes — locks, quorums).\nCP: Spanner, ZooKeeper/etcd (consenso). AP: Cassandra, Dynamo-style, DNS.\nPACELC añade: aún sin partición, eliges latencia vs consistencia (sync replication = latencia).\nEn la entrevista: di qué hace TU sistema por dato, no recites la teoría.",
   "nivel": "avanzado",
   "clave": false
  }
 ]
}