wandres.dev
RENDIMIENTO EN CI · Evitar la regresión

Qué medir en cada commit y qué medir cada noche

La pirámide de comprobaciones con su presupuesto de tiempo, qué va en cada nivel y por qué, la ejecución nocturna con dispositivos reales, y el bucle que cierra el campo con el laboratorio.

⏱ 18 min

La tentación es ejecutarlo todo siempre, y produce un sistema que tarda veinticinco minutos por petición de cambios, que la gente aprende a saltarse y que acaba desactivado por lento antes de que llegue a desactivarse por ruidoso. El reparto correcto no lo decide la exhaustividad sino dos restricciones duras: cuánto tiempo puede tardar una comprobación sin que la gente la esquive, y cuánto ruido puede tener sin perder credibilidad. Con esas dos restricciones, el reparto se deduce casi solo.

🎯 Al terminar esta lección sabrás
  • Repartir las comprobaciones en los cuatro niveles de la pirámide según tiempo y ruido.
  • Configurar la ejecución nocturna con dispositivos reales y sesiones largas.
  • Conectar las alertas de campo con las comprobaciones de laboratorio.
  • Definir qué se hace cuando cada nivel detecta algo.

La pirámide

Cuatro niveles. La regla que los ordena: cuanto más frecuente, más rápido y más determinista.

Nivel Cuándo Presupuesto de tiempo Qué se mide Al fallar
1 Cada commit menos de 2 min Bytes, número de fragmentos, dependencias, importaciones prohibidas Rompe el trabajo
2 Cada petición de cambios menos de 8 min Auditoría entrelazada contra la base, 5 pasadas, rutas clave Comenta, no rompe
3 Cada noche 30 a 90 min Todas las rutas, dispositivos reales, sesiones largas, memoria Alerta a un canal
4 Continuo Datos de campo reales por segmento Alerta si hay tendencia

Los presupuestos de tiempo no son orientativos. Una comprobación que tarda más de dos minutos en cada commit hace que la gente deje de esperar y empiece a integrar sin mirar; una que tarda más de diez en una petición de cambios se salta con una etiqueta de urgencia que enseguida se convierte en costumbre. El límite lo pone la paciencia humana y no negocia.

Nivel 1, cada commit. Todo determinista y calculado sobre los artefactos de la compilación, sin arrancar ningún navegador. Bytes por fragmento con presupuesto, número de fragmentos, dependencias nuevas, y comprobaciones estáticas del tipo “esta biblioteca no se puede importar desde el paquete de entrada”. Esto último se hace muy bien con una regla de análisis estático y es de lo más eficaz que existe:

{
  "rules": {
    "no-restricted-imports": ["error", {
      "paths": [
        {
          "name": "libreria-de-graficas",
          "message": "Solo con import dinamico dentro de la ruta de informes."
        },
        {
          "name": "libreria-de-fechas",
          "message": "Usa Intl.DateTimeFormat. Ver docs/rendimiento/fechas.md."
        }
      ],
      "patterns": [
        {
          "group": ["libreria-de-iconos"],
          "message": "Importa el icono concreto, no el paquete entero."
        }
      ]
    }]
  }
}

Estas reglas son extraordinariamente eficaces porque fallan en el editor, antes de compilar, con un mensaje que dice exactamente qué hacer. No hay comprobación de rendimiento más barata ni más rápida que una que se ejecuta mientras la persona escribe.

Nivel 2, cada petición de cambios. Aquí va la auditoría entrelazada con la rama base, cinco pasadas de cada, sobre las tres o cuatro rutas más importantes. El resultado es un comentario con la diferencia y su intervalo, y no rompe el trabajo, por lo visto sobre falsos positivos. Su función es informar a quien revisa, no bloquear.

Nivel 3, cada noche. Aquí cabe todo lo que es demasiado lento o demasiado ruidoso para las peticiones de cambios. Es el nivel donde se ejecutan las cosas que de verdad se parecen a la realidad, y merece detalle.

Nivel 4, continuo. Los datos reales. Es el único nivel que mide lo que de verdad pasa, y por eso es el que manda cuando los cuatro se contradicen.

La ejecución nocturna

Sin presión de tiempo, la ejecución nocturna puede hacer lo que las otras no. Cinco cosas que merecen estar ahí:

Todas las rutas, no una muestra. Una plantilla que casi nadie mira puede tener una regresión durante meses sin que ninguna comprobación de nivel 2 la vea.

Dispositivos reales en redes reales. Un servicio de pruebas con teléfonos físicos en varias localizaciones. Es la única medida del conjunto que se parece a un usuario, y su valor no está en el número absoluto sino en la serie temporal.

Sesiones largas. Un recorrido guiado de diez minutos con navegación entre rutas, midiendo el INP a lo largo del tiempo y la memoria al final. Es donde aparecen la degradación térmica, las fugas y el crecimiento del DOM, que ninguna carga de treinta segundos detecta. Con lo visto sobre medir memoria en producción, la comprobación concreta es sencilla: repetir un ciclo de uso completo N veces y ver si la memoria vuelve a su punto de partida.

// Comprobacion nocturna de fuga. Se ejecuta con un navegador dirigido.
async function comprobarFuga(pagina, ciclos = 12) {
  const medir = async () => {
    await pagina.evaluate(() => new Promise((r) => setTimeout(r, 1500)));
    const m = await pagina.evaluate(() =>
      performance.measureUserAgentSpecificMemory
        ? performance.measureUserAgentSpecificMemory().then((x) => x.bytes)
        : null
    );
    return m;
  };

  await recorridoCompleto(pagina);        // calentar y estabilizar
  const inicial = await medir();

  for (let i = 0; i < ciclos; i++) await recorridoCompleto(pagina);
  const final = await medir();

  const crecimientoPorCiclo = (final - inicial) / ciclos;
  return {
    inicial, final,
    crecimientoPorCiclo: Math.round(crecimientoPorCiclo),
    // Menos de 200 KB por ciclo es ruido; mas es una fuga.
    sospechoso: crecimientoPorCiclo > 200 * 1024,
  };
}

Muchas más pasadas. Con treinta pasadas por ruta, el suelo de detección baja lo bastante como para ver regresiones que en la petición de cambios eran indistinguibles del ruido.

Comparación con la competencia. Los datos públicos de experiencia de usuario permiten seguir la evolución de sitios que no son tuyos. Es el único número de todo este nivel que interesa fuera de ingeniería, y tenerlo en la serie sale gratis.

Y una regla sobre qué hacer cuando la nocturna encuentra algo: abre una incidencia con el rango de commits, no despiertes a nadie. La ejecución nocturna detecta derivas y regresiones de días; su latencia de respuesta correcta es de horas, no de minutos.

Cerrar el bucle con el campo

Los tres primeros niveles son laboratorio y el cuarto es realidad. La pregunta interesante es qué se hace cuando no coinciden, y las cuatro combinaciones tienen respuestas distintas:

Laboratorio Campo Diagnóstico Acción
Bien Bien Coherente Nada
Mal Bien El laboratorio mide algo que no afecta a los usuarios Revisar el escenario de laboratorio, quizá relajar el umbral
Bien Mal Al laboratorio le falta una dimensión: dispositivo, geografía, red, terceros, contenido real Ampliar el escenario hasta reproducirlo
Mal Mal Regresión real Arreglar

La tercera fila es la más frecuente y la más instructiva. Casi siempre significa que el escenario de laboratorio está limpio de algo que en producción sí está: los terceros, un contenido más grande, un dispositivo más lento, una latencia mayor, una tasa de aciertos de caché real. Cada vez que ocurre, la reacción correcta no es descartar el campo sino ampliar el escenario de laboratorio hasta que reproduzca el problema, y ese escenario ampliado se queda para siempre. Es el mecanismo por el que un montaje de pruebas se vuelve bueno con el tiempo: cada regresión que se escapó añade el caso que la habría detectado.

Y una alerta de campo que conviene tener, porque es la única que detecta la clase de regresión que ninguna comprobación de laboratorio puede ver: una alerta sobre la tasa de aciertos de caché y sobre el peso de los terceros, medidos en producción. Esas dos cosas cambian sin que tú despliegues nada, y por tanto son invisibles para cualquier comparación entre commits.

Un sistema de comprobaciones de rendimiento se evalúa por cuánto tiempo lleva vivo, no por cuánto cubre, y todas las decisiones de diseño se derivan de ahí

Cuando montes esto vas a tener que elegir muchas veces entre dos opciones, y hay un criterio que resuelve casi todas: entre una comprobación más completa y una que la gente vaya a tolerar durante dos años, elige siempre la segunda. No es pragmatismo resignado; es que la métrica de éxito de un sistema de este tipo es el tiempo integrado durante el que ha estado activo, y una comprobación exhaustiva que se desactiva a los dos meses tiene un valor total menor que una modesta que lleva tres años en pie. El motivo es que las regresiones no llegan en un momento concreto que puedas anticipar: llegan continuamente, en pequeñas dosis, en peticiones de cambios de gente que no está pensando en rendimiento, y lo que las detiene no es la profundidad de la comprobación sino su presencia. Con ese criterio, las decisiones de este nivel dejan de ser cuestión de gusto. Los presupuestos de tiempo son duros porque una comprobación lenta se esquiva. Las puertas duras van solo sobre lo determinista porque un falso positivo consume crédito y el crédito no se repone. Los mensajes de error tienen que traer el diagnóstico porque un mensaje incomprensible convierte cada fallo en una hora de trabajo que alguien acabará evitando. El procedimiento de excepción existe porque una puerta sin llave se derriba. La ejecución nocturna no despierta a nadie porque una alerta que despierta sin motivo se silencia y ya nunca vuelve a sonar. Todo son variaciones del mismo principio. Y hay una implicación que va más allá de la herramienta y que conviene ver, porque es la que conecta este nivel con el siguiente: el cuello de botella del rendimiento en un equipo maduro no es técnico, es de sostenibilidad social del mecanismo. Sabemos desde hace años qué hay que medir y cómo medirlo; lo que se rompe es la voluntad colectiva de seguir mirándolo cuando hay una fecha de entrega encima. Diseñar para esa realidad —comprobaciones que valen su fricción, mensajes que enseñan en vez de regañar, excepciones que se conceden en dos minutos y caducan solas, alertas en las que se puede confiar— es tan parte del trabajo de ingeniería de rendimiento como saber por qué un layout forzado cuesta lo que cuesta. La diferencia es que lo segundo se enseña en todas partes y lo primero casi en ninguna, y es lo primero lo que decide si tu producto sigue siendo rápido dentro de dos años.

⚔️ Reparte tus comprobaciones
  1. Coloca cada comprobación que tengas hoy en uno de los cuatro niveles y mide cuánto tarda cada nivel completo.
  2. Mueve al nivel 1 todo lo determinista y saca de ahí todo lo que arranque un navegador.
  3. Añade las reglas de importación prohibida para tus tres bibliotecas más pesadas, con mensajes que digan la alternativa.
  4. Monta la ejecución nocturna con la comprobación de fuga por ciclos y un recorrido largo con INP a lo largo del tiempo.
  5. Coge la última regresión que llegó a producción y añade al laboratorio el escenario que la habría detectado.