Lección 11

¿Por qué el código funciona y aun así ya no se puede cambiar?

El rendimiento se arregla con infraestructura. Esto otro no: cuando el equipo crece, lo que se rompe es la coherencia. La pregunta deja de ser si la página carga y pasa a ser cuánto cuesta tocarla.

01Escalar usuarios y escalar gente

En una cocina con un solo cocinero, la sal puede estar en cualquier estante: él sabe dónde. Con quince, la sal tiene un lugar, una etiqueta y una regla: no sale de la cocina. Nadie cocina mejor por eso; cambió lo que hay que acordar para que el turno funcione.

Escalar usuarios es que más gente use lo mismo: se arregla con caché, con servidores, con índices. Escalar gente es que más manos toquen lo mismo: no se arregla con infraestructura, porque lo que se rompe no es el rendimiento, es la coherencia. Dos personas implementan dos formas de formatear una fecha, tres equipos tienen tres copias del mismo botón, y un cambio de precio toca siete archivos que nadie sabía que estaban conectados.

El criterio que ordena todo lo demás: el costo de cambiar algo debe ser proporcional a lo que cambia. Cambiar el color de un botón debería tocar un token y, como mucho, una revisión. Cambiar cómo se calcula un impuesto debería tocar el dominio y sus pruebas, no la vista. Cuando un cambio pequeño exige abrir doce archivos y pedir permiso a tres equipos, el problema no es el código: es el dibujo de las fronteras.

Los números ayudan a verlo: con 4 personas el acuerdo cabe en la cabeza; con 12, ya no. Un equipo de 12 suele tener tres o cuatro ritmos de cambio distintos, y cada uno merece una frontera propia.

02Fronteras, contratos y guardarraíles

Una frontera de módulo es una línea que dice qué puede saber una parte del código de la otra. Lo que las hace útiles es la dirección: las dependencias apuntan hacia dentro. La interfaz, lo que se ve, puede depender de la aplicación, los casos de uso; la aplicación puede depender del dominio, las reglas del negocio; el dominio no sabe que existe una pantalla. Si el dominio importa la vista, ya no puedes probarlo sin navegador, ni reusarlo en otro cliente, ni cambiar la vista sin miedo.

Los contratos tipados compartidos son esa frontera aplicada a los datos: una sola fuente de tipos entre la API (la puerta por la que la web pide datos) y la web, generada del esquema. Si el esquema es la verdad, el tipo se genera; si el tipo se escribe a mano, hay dos verdades y una se queda vieja. El error deja de aparecer en producción y aparece al compilar.

El monorepo, un solo repositorio con varios paquetes, no sirve por tener todo junto: sirve porque las reglas entre paquetes se verifican en el mismo build (la compilación). En repos separados también se puede, pero cada frontera cuesta una integración.

Un guardarraíl es una regla que el sistema hace cumplir. Una regla en un documento se olvida; una regla en CI, la integración continua que corre las comprobaciones en cada cambio, falla el build y no se puede fusionar. La diferencia no es la redacción: es la consecuencia. Una regla que no falla un build es una sugerencia. La etiqueta de la sal no cocina; solo evita que quince personas discutan dónde está.

El design system es un contrato, no una biblioteca de componentes. Tokens en vez de valores: decisiones con nombre, color, espacio, tipografía, para que el tema se cambie en un lugar. Props semánticas (la intención que recibe un componente) en vez de valores: variant="peligro" y no color="#9c3a2e", porque la intención se puede auditar y el valor se copia. Versionado y codemods, transformaciones automáticas que actualizan el código de los consumidores cuando la API cambia. Y adopción medida: porcentaje de pantallas que usan el componente, no número de descargas.

Los micro-frontends son varias aplicaciones pequeñas que se despliegan por separado y se componen en una página. Tienen sentido cuando hay equipos independientes que no pueden coordinar un despliegue común, con ritmos distintos y fronteras de negocio claras. Casi nunca son la primera respuesta porque multiplican lo que ya era difícil: duplican dependencias, obligan a versionar contratos entre equipos, reparten el estado y hacen que el rendimiento de la página dependa del peor fragmento. Si no puedes desplegar tu parte sin pedir permiso, ganas algo; si solo quieres ordenar carpetas, no.

Las dependencias apuntan hacia el dominio interfaz aplicación dominio reglas cada flecha dice “depende de” la interfaz depende de la aplicación la aplicación depende del dominio el dominio no depende de nada una flecha que sale del centro es la señal de alarma
La capa de afuera puede mirar hacia adentro; la de adentro no mira hacia afuera. Cuando aparece una flecha que sale del centro, el dominio dejó de poder probarse sin navegador y el cambio más pequeño empieza a arrastrar la interfaz.
El mismo cambio en un archivo o en doce un cambio de token 1 archivo 1 revisión el mismo cambio 12 archivos 12 revisiones, 3 equipos
El mismo cambio, dos formas de pagarlo. La diferencia no está en el esfuerzo de escribir el cambio, sino en las revisiones, las esperas y las probabilidades de romper algo que no tiene que ver.
Una regla con consecuencia se cumple; una sugerencia se olvida la misma regla no importar la base wiki y junta se recuerda 9 imports en 3 meses CI build falla no fusiona el olvido se ve una regla sin consecuencia es una sugerencia
La frase es idéntica; cambia quién la hace cumplir. En la wiki depende de la memoria y del apuro; en CI el olvido se convierte en un error antes de fusionar.

03Cómo se ataca

Primero se dibuja el mapa de cambios: qué se modifica junto y con qué frecuencia. La frontera va donde cambia el ritmo, no donde queda bonito. Lo que cambia cada semana se separa de lo que cambia cada trimestre, aunque hoy vivan en la misma carpeta.

Después se eligen las reglas que se pueden verificar: prohibir imports, limitar dependencias entre paquetes, congelar el tamaño del bundle (el paquete de código que se descarga). Cada regla necesita un mensaje que diga qué hacer en su lugar, no solo que está prohibido. Y se mide el costo real: cuántos archivos toca un cambio típico y cuántas revisiones necesita.

// eslint.config.js — la regla vive en el repositorio y corre en CI.
export default [
  {
    files: ['apps/web/**/*.{ts,tsx}'],
    rules: {
      'no-restricted-imports': ['error', {
        patterns: [{
          group: ['@acme/db', '@acme/db/*', '**/lib/db'],
          message:
            'La web no puede hablar con la base de datos: ' +
            'pasa por @acme/api. Si falta un dato, se añade al ' +
            'contrato compartido, no al import.',
        }],
      }],
    },
  },
];

// Lo que ve quien lo intenta, en la terminal y en la revisión:
// error  La web no puede hablar con la base de datos:
//        pasa por @acme/api.
//        apps/web/src/precios.ts:3:1

El mensaje es la mitad de la regla. “Prohibido” enseña a rodear el límite; “pasa por el contrato” enseña la salida correcta. Con doce personas, la regla se lee muchas más veces de las que se discute.

04Cómo diagnosticarlo

Los síntomas de una arquitectura que ya no aguanta son medibles y casi nunca aparecen en un panel de rendimiento.

HerramientaQué se miraCómo se ve el síntoma
Tiempo hasta el primer PR Cuánto tarda alguien nuevo en fusionar un cambio pequeño (un pull request), contando entorno y revisión. Más de una semana apunta a un problema de arranque y de fronteras, no de talento.
Pull requests que rompen otra área Cambios que revierten o que exigen arreglos fuera de su carpeta. Es la medida directa del acoplamiento: si es frecuente, las fronteras son decorativas.
Duplicación medida Cuántas copias del mismo componente o utilidad existen, buscando por nombre y por forma. Tres botones con tres comportamientos distintos significan que el contrato no existe o no se adopta.
Acoplamiento Cuántos imports entran y salen de cada paquete. Un paquete con cuarenta entradas es un centro de gravedad: moverlo obliga a mover medio repo.
Reglas que fallan un build Cuántas reglas de arquitectura existen y cuántas se ejecutan en CI. Diez reglas escritas y dos automatizadas es una arquitectura de opiniones, no de hechos.
La prueba de una frontera

Intenta borrar el paquete de la interfaz y compilar el dominio. Si no compila, la frontera está invertida; si compila y pasa sus pruebas, la frontera es real.

Para decirlo en la entrevista

“If the domain imports the view, you cannot test the rules without a browser.”

“A rule that does not fail the build is a suggestion.”

“Micro-frontends buy independent deploys and charge you in coordination.”

Comprueba que lo tienes

Cuatro preguntas. Al comprobar se marca la lección como completada.

El módulo de precios importa el componente de tabla “para reutilizar el formato”. ¿Qué se rompió?

La wiki dice “la web no debe importar la base de datos”. Tres meses después hay nueve imports. ¿Qué faltó?

Un componente recibe color="#9c3a2e" en vez de variant="peligro". ¿Por qué importa?

Dos equipos despliegan cada semana por separado y hoy comparten un único despliegue que se bloquea mutuamente. ¿Es buen caso para micro-frontends?