Módulo 8: Project Ship Mercados Recommendations
Presentación del capstone: el primer vuelo real, con pasajeros
Por qué existe este módulo
La lección 1 de esta guía abrió con una analogía: un piloto no vuela con pasajeros el mismo día que aprueba el examen — antes, cada sistema del avión se prueba por separado, en tierra, en condiciones controladas. Eso es, exactamente, lo que hicieron los módulos 1 a 7: cada uno tomó una pieza del lanzamiento de recommendations y la probó a fondo, aislada de las demás. El módulo 1 midió el radio de impacto. El módulo 2 construyó y verificó el flag. El módulo 3 diseñó la rampa completa. El módulo 4 la vigiló en vivo hasta el HALT. El módulo 5 decidió revertir y midió el MTTR. El módulo 6 escribió el postmortem sin culpar a nadie. El módulo 7 validó, en shadow mode, que un modelo nuevo es seguro antes de tocar producción.
Siete sistemas, siete pruebas en tierra, siete piezas que funcionan — cada una, por separado, ya demostrada. Lo que ningún módulo anterior hizo todavía es volar con las siete juntas, en el orden real, sobre el mismo lanzamiento, de principio a fin. Ese es el trabajo de este módulo: no un sistema nuevo, sino el primer vuelo real — con la turbulencia real que ya conoces (el guardrail de latencia que se rompe a los 10%), y con cada sistema respondiendo exactamente cuando le toca.
La promesa de este módulo, resumida:
De siete piezas probadas por separado a UN lanzamiento completo: flag -> rampa gradual ->
monitorea guardrails -> frena/revierte si rompe -> postmortem -> itera y migra el modelo
seguro -> re-lanza. La prueba de que el proceso, y no la suerte, es lo que vuelve segura
la decisión de lanzar un ganador que rompe un guardrail.
El caso que retoma este módulo
Todo lo que sigue parte de dos hechos que la guía de métricas ya estableció, y que esta guía ha usado en cada uno de sus siete módulos: recommendations gana el experimento con significancia estadística real, y rompe un guardrail de latencia conocido.
// Donde nos deja la guia completa hasta este punto: el resultado del experimento
// (guia de metricas) y el metodo de siete piezas que esta guia construyo, modulo
// a modulo, para lanzarlo con seguridad.
const handoff = {
feature: 'recommendations',
primaryMetric: { name: 'checkoutConversion', lift: 0.1875, pValue: 0.0114, win: true },
guardrailKnown: { name: 'checkoutLatencyP95Ms', before: 650, after: 910, ceiling: 800, broken: true },
totalUsers: 250000,
};
console.log('=== estado al abrir el capstone: donde nos dejo la guia de metricas ===\n');
console.log('feature=' + handoff.feature + ' totalUsers=' + handoff.totalUsers.toLocaleString('en-US'));
console.log('primary: ' + handoff.primaryMetric.name + ' +' + (handoff.primaryMetric.lift * 100) +
'% (p=' + handoff.primaryMetric.pValue + ', significativo) -- win=' + handoff.primaryMetric.win);
console.log('guardrail conocido: ' + handoff.guardrailKnown.name + ' ' + handoff.guardrailKnown.before + 'ms -> ' +
handoff.guardrailKnown.after + 'ms (techo ' + handoff.guardrailKnown.ceiling + 'ms) -- roto=' + handoff.guardrailKnown.broken);
console.log('\nEste modulo lanza EXACTAMENTE eso: un ganador que rompe un guardrail. Las siete piezas de M1-M7,');
console.log('encadenadas, son el metodo completo para hacerlo sin que ese guardrail se convierta en un incidente sin control.\n');
console.log('=== el metodo completo, en una cadena ===\n');
const method = [
{ m: 'M1', tool: 'blastRadius()', answers: 'cuanta gente expones primero' },
{ m: 'M2', tool: 'isEnabled()', answers: 'quien ve la feature, de forma estable y reversible' },
{ m: 'M3', tool: 'rolloutPlan()', answers: 'la rampa completa: canary -> 10% -> 50% -> 100%' },
{ m: 'M4', tool: 'guardrailWatch()', answers: 'vigila los guardrails EN VIVO, etapa por etapa' },
{ m: 'M5', tool: 'rollbackDecision() + mttr()', answers: 'revertir o arreglar hacia adelante, medido' },
{ m: 'M6', tool: 'buildPostmortem()', answers: 'que aprendio el equipo, sin culpar a nadie' },
{ m: 'M7', tool: 'shadowCompare()', answers: 'migrar el modelo de recomendaciones sin adivinar' },
];
method.forEach((s) => console.log(s.m + ' ' + s.tool.padEnd(28) + s.answers));
console.log('\nEste modulo 8 corre las siete piezas, en orden, sobre UN lanzamiento real: recommendations.');
Qué esperar. Al correr el archivo con Node, la salida es exactamente esta:
=== estado al abrir el capstone: donde nos dejo la guia de metricas ===
feature=recommendations totalUsers=250,000
primary: checkoutConversion +18.75% (p=0.0114, significativo) -- win=true
guardrail conocido: checkoutLatencyP95Ms 650ms -> 910ms (techo 800ms) -- roto=true
Este modulo lanza EXACTAMENTE eso: un ganador que rompe un guardrail. Las siete piezas de M1-M7,
encadenadas, son el metodo completo para hacerlo sin que ese guardrail se convierta en un incidente sin control.
=== el metodo completo, en una cadena ===
M1 blastRadius() cuanta gente expones primero
M2 isEnabled() quien ve la feature, de forma estable y reversible
M3 rolloutPlan() la rampa completa: canary -> 10% -> 50% -> 100%
M4 guardrailWatch() vigila los guardrails EN VIVO, etapa por etapa
M5 rollbackDecision() + mttr() revertir o arreglar hacia adelante, medido
M6 buildPostmortem() que aprendio el equipo, sin culpar a nadie
M7 shadowCompare() migrar el modelo de recomendaciones sin adivinar
Este modulo 8 corre las siete piezas, en orden, sobre UN lanzamiento real: recommendations.
Fíjate en la primera línea del handoff: win=true y broken=true conviven en el mismo objeto, sin que ninguno de los dos cancele al otro. Esa tensión sin resolver es, literalmente, el punto de partida de las siete lecciones que siguen — y la razón por la que un lanzamiento cuidadoso no es "lanzar" ni "no lanzar", sino un proceso completo que sabe qué hacer con las dos verdades a la vez.
Una analogía: el primer vuelo real, con la turbulencia ya conocida
Vuelve a la analogía que abrió esta guía entera, en la lección 1 del módulo 1: el piloto no vuela con pasajeros el mismo día que aprueba el examen. Ahora imagina el día siguiente: el piloto ya aprobó cada prueba por separado —despegue, aterrizaje, procedimiento de emergencia con un motor apagado, comunicación con la torre— y hoy vuela por primera vez con pasajeros reales, en una ruta donde ya sabe, por los reportes meteorológicos, que hay una zona de turbulencia a cierta altitud.
Un piloto sin entrenamiento, frente a esa turbulencia conocida, tiene dos malas opciones: evitar la ruta por completo (perder el vuelo, y el valor de llegar a destino), o volar directo a través de ella sin ningún plan, confiando en que "va a estar bien". Un piloto entrenado hace algo distinto: vuela la ruta, sube gradualmente, vigila los instrumentos exactamente en la zona donde sabe que puede haber problema, y tiene un procedimiento claro —ya practicado— para lo que hace si los instrumentos confirman que la turbulencia es peor de lo esperado: reducir velocidad, cambiar de altitud, o si hace falta, dar la vuelta. Ninguna de esas respuestas es una improvisación en el momento — son el resultado de todo el entrenamiento anterior, aplicado en tiempo real.
Este módulo es ese vuelo. La "turbulencia conocida" es el guardrail de latencia que ya sabes que se rompe a los 10% de rollout. Las siete piezas de M1 a M7 son el entrenamiento completo. Y el resultado de este módulo no es "evitamos la turbulencia" ni "volamos a ciegas a través de ella" — es exactamente lo que un piloto entrenado hace: subir con cuidado, confirmar el problema con los instrumentos en el momento exacto en que ocurre, responder con un procedimiento ya decidido, y — la parte que ningún simulacro puede enseñar del todo— aprender de ese vuelo específico para que el siguiente sea mejor.
El mapa de las 8 lecciones de este módulo
Lección Capa del lanzamiento Módulo(s) que integra
──────── ───────────────────────────────────────────── ──────────────────────
L1 (esta) el metodo completo, de punta a punta M1-M7
L2 el flag encendido y la rampa disenada M2 + M3
L3 vigilar la rampa en vivo -- el HALT en 10% M4
L4 decidir -- revertir en minutos, no en horas M5
L5 el postmortem, sin culpar a nadie M6
L6 iterar -- migrar el modelo con shadow mode M7
L7 re-lanzar, y verificar que el lift aguanta M3 + M6 (noveltyCheck)
L8 Proyecto: el plan de lanzamiento completo M1-M7, de punta a punta
Cada una de las lecciones 2 a 7 toma una o dos piezas ya construidas —sin cambiarles una sola línea— y las corre sobre el mismo lanzamiento de recommendations, en el orden en que un equipo real las ejecutaría. La lección 2 enciende el flag y diseña la rampa completa, antes de exponer a nadie más allá del canary. La lección 3 vigila esa rampa en vivo con los cuatro guardrails de la guía de métricas, y confirma el HALT en la etapa de 10%. La lección 4 toma esa confirmación y decide, con números, revertir — y mide qué tan rápido respondió el equipo. La lección 5 investiga la causa raíz sin culpar a nadie, y deja acordado qué se arregla. La lección 6 valida, en shadow mode, el modelo nuevo que resuelve la causa raíz, antes de tocar producción. La lección 7 re-lanza con el fix ya validado, y confirma —varias semanas después— que la ganancia no fue un espejismo de novedad. La lección 8, el proyecto final de la guía completa, junta las siete piezas en un solo plan de lanzamiento y una sola corrida de Node, y cierra tanto esta guía como el ecosistema completo de Product Engineering.
La frontera: qué NO entra en este módulo
- Diseñar mecanismos nuevos. Este módulo no inventa ningún modelo de decisión nuevo más allá de los que ya construyeron M1-M7 (y las dos piezas de integración —
buildPostmortem()ynoveltyCheck()— que completan lo que M6 dejó descrito). Si buscas cómo se construyerolloutPlan()desde cero, ese es el módulo 3, no este. - El pipeline de deploy de infraestructura. El flag de
recommendationsya está deployado —el código vive en producción, apagado— desde antes de que este módulo empiece. Este módulo controla la exposición de ese código ya deployado, no el proceso que lo llevó a los servidores. Eso esfullstack-performance-and-deployment-guide, el ecosistema Fullstack. - Re-calcular la significancia del experimento. El
+18.75%conp=0.0114es un dato que llega ya resuelto deproduct-metrics-and-experimentation-guide. Este módulo lo usa como insumo delrollbackDecision(), nunca lo vuelve a calcular.
Errores comunes
Tratar las siete piezas como ejercicios aislados, en vez de una cadena donde la salida de una alimenta la entrada de la siguiente. Qué pasa: alguien corre guardrailWatch() de la lección 3, ve el HALT, y después corre rollbackDecision() de la lección 4 con datos inventados desde cero, en vez de usar exactamente el guardrail que guardrailWatch() acaba de confirmar roto. Por qué pasa: cada pieza se aprendió en un módulo separado, con sus propios ejemplos, y es natural seguir pensándolas por separado incluso cuando el objetivo explícito de este módulo es conectarlas. Cómo detectarlo: si el p95Latency que usas en la lección 4 no es exactamente el 910ms que confirmó la lección 3, la cadena se rompió en algún punto. Cómo corregirlo: en cada lección de este módulo, la salida de la lección anterior es literalmente el dato de entrada de la siguiente — la disciplina de este módulo es no perder ese hilo ni una sola vez.
Saltar directo al código de la lección 8, sin pasar por las lecciones 2 a 7. Qué pasa: alguien, ansioso por ver "el resultado final", va directo al proyecto de la lección 8 y corre el script completo sin haber entendido, capa por capa, qué hace cada pieza y por qué está en ese orden. Por qué pasa: el proyecto final tiene el código más impresionante y completo de todo el módulo, y es tentador tratarlo como el verdadero contenido, con las lecciones 2 a 7 como relleno. Cómo detectarlo: si no puedes explicar, sin mirar el código, por qué guardrailWatch() corre antes que rollbackDecision() y no al revés, todavía no procesaste las lecciones intermedias. Cómo corregirlo: las lecciones 2 a 7 no son preámbulo — son donde se entiende por qué cada pieza está donde está en la cadena. El proyecto de la lección 8 es la demostración de que entendiste eso, no un atajo para evitarlo.
Asumir que, porque el desenlace de este módulo es positivo (re-lanzamiento exitoso), el guardrail roto de la mitad del módulo "no fue tan grave". Qué pasa: al llegar a la lección 7 y ver que recommendations se re-lanza limpio hasta el 100%, alguien concluye retroactivamente que el HALT de la lección 3 fue un trámite menor, casi innecesario. Por qué pasa: un final feliz tiende a suavizar, en la memoria, la seriedad de lo que pasó en el camino. Cómo detectarlo: si tu resumen de este módulo es "todo salió bien al final", sin mencionar el HALT, el rollback, ni el postmortem, perdiste la lección central. Cómo corregirlo: el desenlace positivo de este módulo es consecuencia directa de haber tratado el HALT con toda la seriedad del proceso completo —frenar, revertir, investigar, arreglar, validar— no a pesar de eso. Sin ese proceso, la latencia rota habría llegado al 100% de la base antes de que nadie se diera cuenta.
Ejercicios
Ejercicio 1 — Nombra el eslabón que falta. Sin ver el código de nuevo, escribe de memoria las siete piezas de la cadena (M1 a M7) en el orden correcto, junto con la pregunta que cada una contesta. Compara tu lista contra la tabla de "el método completo" de esta lección. ¿Cuál fue la más difícil de recordar, y por qué crees que es esa?
Ver solución
La lista correcta, en orden: M1 blastRadius() — cuánta gente exponer primero. M2 isEnabled() — quién ve la feature, de forma estable y reversible. M3 rolloutPlan() — la rampa completa. M4 guardrailWatch() — vigilar en vivo. M5 rollbackDecision() + mttr() — revertir, medido. M6 buildPostmortem() — aprender sin culpar. M7 shadowCompare() — migrar el modelo sin adivinar. No hay una respuesta única para "cuál es la más difícil" — pero si te costó recordar el orden exacto entre M4 y M5, vale la pena notar que es, precisamente, la transición donde más equipos reales se equivocan: confundir "confirmar que algo está roto" (M4) con "decidir qué hacer con eso" (M5) es el error central que la lección 1 del módulo 5 nombró explícitamente.
Ejercicio 2 — Ubica dónde estaría cada situación real. Para cada una, di a qué lección de este módulo (2 a 7) correspondería si ocurriera hoy en el equipo de Mercado:
- (a) "El dashboard acaba de confirmar que
checkoutLatencyP95Mssigue por encima de 800ms en la etapa de 10%." - (b) "Escribimos, sin nombrar a ninguna persona, por qué la latencia se rompió y qué vamos a cambiar."
- (c) "Corrimos el modelo nuevo en paralelo durante una semana, sin que ningún comprador lo viera, y comparamos sus recomendaciones contra las del modelo viejo."
- (d) "Cuatro semanas después de re-lanzar, seguimos viendo el mismo lift, no solo en la primera semana."
Ver solución
(a) Lección 3 — vigilar la rampa en vivo, guardrailWatch(). (b) Lección 5 — el postmortem blameless, buildPostmortem(). (c) Lección 6 — iterar y migrar el modelo, shadowCompare(). (d) Lección 7 — re-lanzar y verificar, noveltyCheck(). Fíjate en que cada situación tiene una palabra o frase que la ancla a una pieza específica: "en vivo" apunta a monitoreo, "sin nombrar a ninguna persona" apunta a blameless, "sin que ningún comprador lo viera" apunta a shadow mode, y "cuatro semanas después" apunta a novedad versus durabilidad.
Ejercicio 3 — Predicción sobre el desenlace. Basándote solo en el mapa de las 8 lecciones de esta introducción, y sin haber leído todavía ninguna lección posterior, ¿qué crees que tiene que ser cierto en la lección 6 (shadowCompare()) para que la lección 7 pueda re-lanzar recommendations con confianza? Escribe tu predicción en 2-3 frases.
Ver solución
Para que la lección 7 pueda re-lanzar con confianza, la lección 6 probablemente necesita demostrar que el modelo nuevo (v2) da resultados suficientemente parecidos a los del modelo viejo (v1) — no idénticos, pero por encima de algún umbral de acuerdo que el equipo defina de antemano, igual que el maxAcceptableExposure del módulo 1 o el ceiling de latencia de los módulos 3-4. Sin ese umbral cruzado, re-lanzar sería repetir el mismo error que esta guía entera existe para prevenir: cambiar algo en producción sin haber verificado, con datos, que el cambio es seguro.
Resumen y siguiente paso
En esta lección viste el mapa completo de este módulo: siete piezas ya probadas por separado en M1-M7, que este módulo corre juntas, en orden, sobre el mismo lanzamiento de recommendations — el "primer vuelo real" después de siete pruebas en tierra. Confirmaste el punto de partida exacto: un resultado significativo (+18.75%, p=0.0114) que convive con un guardrail roto (p95Latency de 650ms a 910ms, techo 800ms), la misma tensión sin resolver que abrió la guía completa en el módulo 1.
Antes de avanzar deberías poder: nombrar las siete piezas en orden, con la función que las representa y la pregunta que cada una contesta; y explicar, en tus propias palabras, por qué un desenlace positivo al final de este módulo es consecuencia del proceso completo, no una señal de que el proceso no hacía falta.
La lección 2 empieza donde el módulo 1 dejó la decisión: con el canary elegido, enciende el flag de verdad y diseña la rampa completa antes de subir un solo punto porcentual más allá del canario inicial.
Recursos
- Google SRE Workbook, Capítulo 16, "Canarying Releases" — sre.google/workbook/canarying-releases. La referencia formal de la práctica que este módulo entero ejecuta de punta a punta: exponer un cambio gradualmente, vigilarlo, y tener un plan claro para cuando algo sale mal. En inglés.
- Google SRE Book, Capítulo 14, "Managing Incidents" — sre.google/sre-book/managing-incidents. El capítulo que conecta monitoreo, decisión de rollback y cierre medido como una sola disciplina continua — el espíritu completo de las lecciones 3 a 5 de este módulo. En inglés.
- LaunchDarkly, "What Is Progressive Delivery All About?" — launchdarkly.com/blog/what-is-progressive-delivery-all-about. El resumen de la industria sobre por qué flags, rollout gradual y monitoreo son, juntos, un solo sistema — no piezas independientes. En inglés.