Módulo 1: What A Design System Is

Anatomía del sistema de diseño de Mercado

Descripción

Ya tienes las piezas del rompecabezas: sabes qué problema resuelve un sistema (el drift, L1-L2), cuáles son sus cuatro capas (L3), y los tres resultados que entrega —consistencia, mantenibilidad, accesibilidad (L4-L6)—. Esta lección los junta en una sola imagen: la anatomía completa del sistema de diseño de Mercado. Es el plano terminado —todas las capas pobladas con sus piezas reales— que el proyecto de la lección 8 te pondrá a inventariar tú mismo, y que los módulos siguientes construirán pieza por pieza.

Aquí no aparece ningún concepto nuevo; aparece todo junto, con nombres concretos. Vas a ver los tokens de Mercado organizados por categoría (color, espaciado, tipografía, radios), sus componentes con las variantes que cada uno ofrece, y sus patrones. Y vas a ver algo que hasta ahora estaba implícito: cuántas configuraciones distintas produce un componente con variantes —cómo un solo Button cubre nueve botones distintos sin escribir nueve botones—. Esa es la economía del sistema hecha visible: pocas piezas, muchas configuraciones.

Conexión con el módulo. Esta es la lección-síntesis. La 3 dio las cuatro capas en abstracto; aquí las llenamos con el sistema real de Mercado, con los identificadores exactos (en inglés) que verás en toda la guía. Es el mapa que el resto de los módulos desarrolla: el módulo 2 construye los tokens que aquí solo listamos, el 3 las utilidades, el 5 los componentes con variantes, y los patrones llegan en el capstone. Tener la anatomía completa a la vista te deja ubicar cada módulo futuro en su lugar. La lección 8 te pide reproducir este inventario y detectar su drift.

Una analogía: el plano del arquitecto contra la casa terminada

Un arquitecto no empieza poniendo ladrillos; empieza con un plano que muestra la casa entera antes de construirla —los cimientos, los muros maestros, las habitaciones, la distribución—. El plano no es la casa, pero es la casa entendida de un vistazo: dónde va cada cosa, cómo se relacionan, qué se apoya en qué. Con el plano en la mano, cualquiera —el albañil, el plomero, el dueño— sabe hacia dónde va la obra.

Esta lección es el plano del sistema de Mercado. Las lecciones anteriores te enseñaron a leer planos (qué es un token, qué es una capa); esta te muestra el plano completo de una casa concreta. Y como todo buen plano, tiene una propiedad valiosa: te deja ver la economía de la construcción. En el plano ves que con tres tipos de muro y dos de ventana se arma toda la casa —no hay cien muros distintos, hay tres reutilizados—. Igual en el sistema: con pocos tokens y pocos componentes bien diseñados se cubre todo el storefront. El plano revela que la riqueza de la UI no viene de muchas piezas, sino de pocas piezas bien combinadas. Ese es el gran ahorro que un sistema hace visible, y que vamos a contar.

De cerca: el sistema de Mercado, capa por capa

Aquí está el plano completo. Vale la pena tenerlo delante mientras lees; es el mapa de referencia de toda la guía:

  ┌──────────────────────────────────────────────────────────────────┐
  │ PATTERNS    site-header · product-grid · checkout-form            │
  ├──────────────────────────────────────────────────────────────────┤
  │ COMPONENTS  Button       variant: primary|secondary|ghost         │
  │             (con           size:    sm|md|lg                       │
  │             variantes)   ProductCard variant: default|compact      │
  │                          SearchBar   size:    md|lg                │
  │                          Badge       variant: neutral|sale         │
  ├──────────────────────────────────────────────────────────────────┤
  │ UTILITIES   bg-primary · text-text · p-4 · gap-4 · flex ·          │
  │             rounded-md · text-lg   (cada una aplica UN token)      │
  ├──────────────────────────────────────────────────────────────────┤
  │ TOKENS      color:  primary · surface · text · muted · danger      │
  │             space:  space-2 · space-4 · space-6 · space-8          │
  │             type:   text-sm · text-base · text-lg · text-xl        │
  │             radius: radius-sm · radius-md                          │
  └──────────────────────────────────────────────────────────────────┘

Los tokens de Mercado, organizados por categoría. Los de color son semánticos —nombrados por rol, no por valor (L1)—: color.primary (el azul de marca, las acciones principales), color.surface (el fondo de tarjetas y superficies), color.text (el texto principal), color.muted (el texto secundario, menos importante), color.danger (errores, eliminar). Los de espaciado salen de una escala (space-2, space-4, space-6, space-8 — el módulo 4 explica la escala base 4/8px). Los de tipografía son una escala de tamaños (text-sm, text-base, text-lg, text-xl). Los de radio dan las esquinas (radius-sm, radius-md). Cada uno es una decisión tomada una vez; todo lo de arriba los referencia.

Las utilidades aplican un token cada una (bg-primary pinta con color.primary, p-4 da padding de space-4, etc.). Son la capa que el módulo 3 (Tailwind) desarrolla; aquí basta ver que median entre los tokens y los componentes.

Los componentes con sus variantes. Aquí está lo interesante. El Button no es un botón; es una familia de botones parametrizada por dos ejes: variant (primary, secondary, ghost) y size (sm, md, lg). El ProductCard tiene variant (default, compact). El SearchBar tiene size (md, lg). El Badge tiene variant (neutral, sale). Cada eje es una dimensión de variación intencional (recuerda L4: variantes buenas, drift malo).

Los patrones componen esos componentes en arreglos recurrentes: site-header (logo + SearchBar + nav), product-grid (una cuadrícula de ProductCard), checkout-form (campos + Button).

La pregunta que hace visible la economía del sistema: ¿cuántos botones distintos puede producir ese único Button? Con variant (3 opciones) y size (3 opciones), cada combinación es un botón: 3 × 3 = 9 botones distintos, y todos salen de un componente. No escribiste nueve botones; escribiste uno, con dos ejes de variación. Esa multiplicación —pocas piezas, muchas configuraciones— es lo que vamos a contar ejecutando.

Ejemplo trabajado: el inventario completo, con las combinaciones

Vamos a modelar el sistema de Mercado como un objeto con las cuatro capas, y a escribir un inventario que recorra los tokens (contándolos por categoría), los componentes (mostrando sus variantes y cuántas combinaciones produce cada uno), y los patrones. La clave es el cálculo de combinaciones: para un componente, se multiplican las opciones de sus ejes (un Button con variant=3 y size=3 da 3 × 3 = 9):

// L7 — anatomia completa del sistema de Mercado: las 4 capas, con las piezas
// reales y las variantes de cada componente.
const mercado = {
  tokens: {
    color:   ['color.primary', 'color.surface', 'color.text', 'color.muted', 'color.danger'],
    space:   ['space-2', 'space-4', 'space-6', 'space-8'],
    type:    ['text-sm', 'text-base', 'text-lg', 'text-xl'],
    radius:  ['radius-sm', 'radius-md'],
  },
  utilities:  ['bg-primary', 'text-text', 'p-4', 'gap-4', 'flex', 'rounded-md', 'text-lg'],
  components: {
    Button:      { variant: ['primary', 'secondary', 'ghost'], size: ['sm', 'md', 'lg'] },
    ProductCard: { variant: ['default', 'compact'] },
    SearchBar:   { size: ['md', 'lg'] },
    Badge:       { variant: ['neutral', 'sale'] },
  },
  patterns: ['site-header', 'product-grid', 'checkout-form'],
};

function count(obj) { return Object.values(obj).reduce((n, arr) => n + arr.length, 0); }

console.log('=== Anatomia del sistema de diseno de Mercado ===\n');
console.log('1. tokens     : ' + count(mercado.tokens) + ' (color, space, type, radius)');
console.log('2. utilities  : ' + mercado.utilities.length);
console.log('3. components : ' + Object.keys(mercado.components).length);
for (const [name, axes] of Object.entries(mercado.components)) {
  const combos = Object.values(axes).reduce((n, opts) => n * opts.length, 1);
  const axesStr = Object.entries(axes).map(([k, v]) => k + '=' + v.length).join(', ');
  console.log('     - ' + name.padEnd(12) + axesStr + '  -> ' + combos + ' combinaciones');
}
console.log('4. patterns   : ' + mercado.patterns.length + ' (' + mercado.patterns.join(', ') + ')');

Qué esperar. Al correr el archivo, la salida es exactamente esta:

=== Anatomia del sistema de diseno de Mercado ===

1. tokens     : 15 (color, space, type, radius)
2. utilities  : 7
3. components : 4
     - Button      variant=3, size=3  -> 9 combinaciones
     - ProductCard variant=2  -> 2 combinaciones
     - SearchBar   size=2  -> 2 combinaciones
     - Badge       variant=2  -> 2 combinaciones
4. patterns   : 3 (site-header, product-grid, checkout-form)

Léela como el plano terminado de Mercado, y fíjate en dos cosas que cuentan la historia entera del sistema.

Lo primero: la pirámide, otra vez, con números reales. 15 tokens en la base, 7 utilidades, 4 componentes, 3 patrones. Base ancha, punta angosta (L3). Todo el storefront —cada pantalla, cada botón, cada tarjeta— se construye con estas 15 + 7 + 4 + 3 piezas. No hay cientos de decisiones sueltas; hay unas pocas decenas, organizadas en capas, cada una apoyándose en la de abajo. Esa es la compresión que un sistema logra: una UI entera cabe en un plano que lees de un vistazo.

Lo segundo, y es la joya: la línea del Button. variant=3, size=3 -> 9 combinaciones. De un componente salen nueve botones distintos (primary-sm, primary-md, primary-lg, secondary-sm… hasta ghost-lg). No escribiste nueve botones ni nueve CSS; escribiste un Button con dos ejes, y el sistema multiplica. Sumando los cuatro componentes, hay 9 + 2 + 2 + 2 = 15 configuraciones de UI a partir de 4 piezas. Esa es la economía del sistema hecha número: las variantes multiplican la cobertura sin multiplicar el código. Y todas esas 15 configuraciones heredan la consistencia (salen de los mismos tokens), la mantenibilidad (cambias el Button y las 9 cambian) y la accesibilidad (el Button trae el foco y el contraste) que armaste en L4-L6. El plano no solo muestra las piezas; muestra por qué pocas piezas bastan.

Una pregunta para el proyecto: si Mercado agregara un tercer eje al Button —digamos state con default y disabled—, ¿cuántas combinaciones tendría entonces? (Se multiplica: variant=3 × size=3 × state=2 = 18. Un eje más duplica la cobertura. Así crece el poder de un componente con variantes, y por eso el módulo 5 le dedica una lección entera a manejarlo sin caos.)

Un matiz: el plano no es la construcción

Importante para no confundirte con lo que sigue en la guía: este inventario es el plano, no la casa construida. Aquí listamos que Mercado tiene un token color.primary, pero no lo hemos definido (qué valor tiene en claro, qué valor en oscuro, cómo se escribe en CSS) —eso es el módulo 2—. Listamos que el Button tiene variant y size, pero no lo hemos construido (el JSX, las clases de Tailwind, el patrón cva que resuelve las clases según las props) —eso es el módulo 5—.

Es la diferencia entre saber qué piezas necesita la casa y saber cómo fabricar cada una. Este módulo 1 —y esta lección en particular— te da el qué: el plano completo, las piezas nombradas, las capas ordenadas, la economía entendida. Los módulos siguientes te dan el cómo: la fabricación de cada pieza. Tener el plano primero no es un rodeo; es lo que hace que, cuando construyas el token en el módulo 2, sepas exactamente dónde encaja en el todo. Se construye mejor con el plano a la vista.

Errores comunes

Confundir el inventario (el plano) con el sistema construido. Qué pasa: alguien hace la lista de tokens y componentes y cree que "ya tiene un design system". Por qué pasa: el inventario se siente como un entregable completo. Cómo detectarlo: tienes una hermosa lista de nombres (color.primary, Button, variant: primary|secondary) pero ningún token definido ni ningún componente construido —el plano sin la obra—. Cómo corregirlo: el inventario es el primer paso, no el sistema. Es imprescindible (construir sin plano produce el caos ad-hoc), pero es un mapa, no un territorio. Los módulos 2 al 5 convierten cada línea del inventario en una pieza real. Ten el plano, sí; pero recuerda que falta levantar la casa.

Inflar el inventario "por si acaso". Qué pasa: en el afán de "cubrir todo", se agregan tokens y variantes que nadie usará —doce tonos de gris, un Button con seis variantes y cinco tamaños "por si algún día"—. Por qué pasa: se confunde "sistema completo" con "sistema grande". Cómo detectarlo: tu inventario tiene piezas que ninguna pantalla usa, y Button produce 30 combinaciones de las que se usan 4. Cómo corregirlo: el sistema debe cubrir lo que la UI necesita, no todo lo imaginable. Cada token y cada variante es algo que hay que definir, mantener, testear y hacer accesible; los que no se usan son puro costo sin beneficio. Un buen inventario es ajustado: las piezas justas para el storefront real. Empieza mínimo y crece con la necesidad —justo lo contrario de adivinar el futuro.

Meter drift dentro del propio inventario. Qué pasa: al listar las piezas, se cuelan dos tokens que son "casi" lo mismo (color.primary y color.brand, ambos el azul de marca) o dos componentes que se solapan (Button y CTAButton). Por qué pasa: el inventario se arma por partes y nadie revisa el conjunto. Cómo detectarlo: tienes dos nombres para un mismo rol —el drift de la L4, ahora en la capa de definición del sistema—. Cómo corregirlo: el inventario debe tener un token por rol y un componente por pieza, igual que la UI debe tener un valor por rol. Dos tokens para el mismo color es la enfermedad que el sistema venía a curar, colada en la cura misma. Al hacer el inventario (y lo harás en L8), pregúntate por cada par de piezas: "¿estas dos son de verdad roles distintos, o es el mismo rol dos veces?".

Ejercicios

Ejercicio 1 — Cuenta las combinaciones. Para cada componente, calcula cuántas configuraciones distintas produce (multiplicando las opciones de sus ejes):

  • (a) Button con variant (primary, secondary, ghost) y size (sm, md, lg).
  • (b) Badge con variant (neutral, sale).
  • (c) Un hipotético Alert con variant (info, success, warning, danger) y size (sm, lg).
  • (d) Un hipotético Input con size (sm, md, lg), state (default, error) e icon (none, left, right).
Ver solución
  • (a) Button: 3 × 3 = 9. Nueve botones distintos de un componente.
  • (b) Badge: 2 = 2. Un solo eje con dos opciones → dos configuraciones.
  • (c) Alert: 4 × 2 = 8. Cuatro variantes por dos tamaños.
  • (d) Input: 3 × 3 × 2 = 18. Tres ejes se multiplican entre sí: size (3) × icon (3) × state (2) = 18. Nota cómo cada eje nuevo multiplica —por eso tres ejes modestos ya dan 18 configuraciones de una sola pieza—.

La regla: las combinaciones de un componente son el producto de las opciones de sus ejes. Es la economía del sistema: agregar un eje multiplica la cobertura sin multiplicar el código. (Y el reverso, que el módulo 5 cuida: demasiados ejes producen una explosión de combinaciones difícil de mantener y testear; hay que elegir los ejes con criterio.)

Ejercicio 2 — Ubica la pieza en su capa. Para cada elemento del sistema de Mercado, di en qué capa vive y, si aplica, de qué capa de abajo depende:

  • (a) color.danger
  • (b) product-grid
  • (c) bg-primary
  • (d) SearchBar con size: md|lg
Ver solución
  • (a) color.danger: token (capa 1). Un valor atómico nombrado por rol (el color de error/peligro). No depende de nada debajo; es la base.
  • (b) product-grid: patrón (capa 4). Un arreglo recurrente de componentes. Depende de la capa 3: usa el componente ProductCard (que a su vez usa utilidades y tokens).
  • (c) bg-primary: utilidad (capa 2). Aplica un token a un elemento; depende de la capa 1: lee el token color.primary.
  • (d) SearchBar: componente (capa 3). Una pieza reutilizable con un eje de variante (size). Depende de la capa 2 (utilidades) y por ella de la capa 1 (tokens); por ejemplo, su tamaño sale de tokens de espaciado y tipografía.

El patrón de siempre: cada pieza vive en una capa y solo depende de las de abajo (L3). Token → nada; utilidad → tokens; componente → utilidades → tokens; patrón → componentes → …

Ejercicio 3 — Detecta el drift en el inventario. Un compañero propone este inventario de tokens de color para Mercado. Encuentra el problema y corrígelo:

const colorTokens = [
  'color.primary',   // el azul de marca
  'color.brand',     // el azul de marca (el del logo)
  'color.surface',
  'color.text',
  'blue600',         // #2563eb
  'color.danger',
];
Ver solución

Hay dos problemas, ambos vistos en el módulo:

  1. Drift dentro del inventario: color.primary y color.brand son el mismo rol (el azul de marca) con dos nombres. Es el drift de la L4 colado en la definición del sistema: dos verdades para una idea. Corrección: dejar uno solo (color.primary) y usarlo en todo, incluido el logo. Un rol, un token.

  2. Token nombrado por su valor: blue600 (con valor #2563eb) viola la regla de la L1 —los tokens se nombran por su rol, no por su valor—. Además, #2563eb es justamente el valor del azul de marca, así que blue600 es una tercera forma del mismo rol. Corrección: eliminarlo; ese rol ya es color.primary.

El inventario corregido, sin drift y con nombres por rol:

const colorTokens = [
  'color.primary',   // el azul de marca (logo, acciones principales)
  'color.surface',
  'color.text',
  'color.danger',
];

La moraleja: el sistema cura el drift, pero solo si el propio inventario está limpio. Un token por rol, nombrado por rol. Si en el inventario hay dos nombres para un color, la UI tendrá dos azules —la enfermedad, colada en la cura—.

Resumen y siguiente paso

En esta lección viste el plano completo del sistema de diseño de Mercado: las cuatro capas pobladas con sus piezas reales —15 tokens (color, space, type, radius), 7 utilidades, 4 componentes con sus variantes, 3 patrones—, todos con los identificadores exactos que usarás en la guía. Con el plano del arquitecto entendiste que su valor es dejarte ver la economía del sistema: ejecutaste el inventario y viste que de un Button con dos ejes salen 9 combinaciones, y que 4 componentes cubren 15 configuraciones —pocas piezas, muchas configuraciones—. Y separaste el plano del cómo: aquí listamos las piezas; los módulos 2 al 5 las fabrican. Reforzaste, además, que el inventario mismo debe estar libre de drift: un token por rol, nombrado por rol.

Antes de avanzar deberías poder: dibujar de memoria las cuatro capas de Mercado con ejemplos de piezas; calcular las combinaciones de un componente por el producto de sus ejes; ubicar cualquier pieza en su capa y sus dependencias; y detectar drift o nombres-por-valor en un inventario.

La lección 8 cierra el módulo poniéndote a hacer el trabajo: el proyecto —el inventario del sistema de Mercado—. Vas a listar los tokens que el storefront necesita, los componentes con sus variantes, y —lo más importante— a detectar el drift de una versión ad-hoc, comprobándolo con el modelo en Node. Es la síntesis práctica de las siete lecciones: no ya leer el plano, sino trazarlo tú, y demostrar con un número que distingues un sistema coherente de un montón de estilos sueltos. Con eso quedas listo para el módulo 2, donde se define el primer token de verdad.

Recursos

  • Material Design 3 — m3.material.io. Un sistema completo y público (tokens, componentes, patrones) para comparar con la anatomía de Mercado; útil para ver un plano "de verdad" a gran escala. En inglés.
  • shadcn/ui, "Components" — ui.shadcn.com/docs/components. Componentes reales con variantes (Button, Badge, Input) construidos sobre tokens; el catálogo que verás en el módulo 7. En inglés.
  • cva (class-variance-authority) — cva.style/docs. La herramienta que da estructura a las variantes de un componente (variant, size) y que multiplica configuraciones sin caos; el corazón del módulo 5. En inglés.
  • Tailwind CSS, "Theme" — tailwindcss.com/docs/theme. Cómo se declaran los tokens (color, space, type, radius) que aquí solo inventariamos; la definición real llega en los módulos 2 y 3. En inglés.