TechLead
Volver a Sistemas de Diseño
Tema 8 de 8

Arquitectura y Escalado

Mono-repos, versionado, distribución y escalado de sistemas de diseño entre equipos

Escalando Sistemas de Diseño

A medida que tu sistema de diseño crece más allá de un solo equipo, necesitas arquitectura sólida para versionado, distribución y colaboración multi-equipo. Un sistema bien arquitecturado puede servir a cientos de desarrolladores en docenas de proyectos.

🏗️ Decisiones de Arquitectura

Monorepo

Todos los paquetes en un repositorio (Turborepo, Nx)

Multi-repo

Repositorios separados por paquete

Paquete Único

Todo empaquetado junto

Federado

Propiedad distribuida entre equipos

Configuración de Monorepo con Turborepo

# Crear un nuevo Turborepo
npx create-turbo@latest my-design-system

# Estructura de carpetas
my-design-system/
├── apps/
│   ├── docs/              # Storybook o sitio de documentación
│   └── playground/        # Aplicación de prueba/demostración
├── packages/
│   ├── tokens/           # Tokens de diseño
│   ├── ui/               # Componentes React
│   ├── utils/            # Utilidades compartidas
│   └── config/           # Configuraciones compartidas (ESLint, TypeScript)
├── turbo.json
├── package.json
└── pnpm-workspace.yaml

# turbo.json
{
  "$schema": "https://turbo.build/schema.json",
  "globalDependencies": ["**/.env.*local"],
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    },
    "lint": {},
    "test": {
      "dependsOn": ["build"]
    }
  }
}

# pnpm-workspace.yaml
packages:
  - 'apps/*'
  - 'packages/*'

# Ejecutar todas las compilaciones
pnpm turbo run build

# Ejecutar solo paquetes cambiados
pnpm turbo run build --filter=...[HEAD~1]

📖 Documentación de Turborepo →

Estructura de Paquete

// packages/ui/package.json
{
  "name": "@acme/ui",
  "version": "1.0.0",
  "main": "./dist/index.js",
  "module": "./dist/index.mjs",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.js",
      "types": "./dist/index.d.ts"
    },
    "./button": {
      "import": "./dist/button.mjs",
      "require": "./dist/button.js",
      "types": "./dist/button.d.ts"
    }
  },
  "sideEffects": ["**/*.css"],
  "peerDependencies": {
    "react": "^18.0.0",
    "react-dom": "^18.0.0"
  },
  "devDependencies": {
    "@acme/tokens": "workspace:*",
    "tsup": "^7.0.0",
    "typescript": "^5.0.0"
  },
  "scripts": {
    "build": "tsup src/index.ts --format cjs,esm --dts",
    "dev": "tsup src/index.ts --format cjs,esm --dts --watch"
  }
}

// packages/ui/src/index.ts
export * from './Button';
export * from './Card';
export * from './Input';
// ...

// packages/ui/tsup.config.ts
import { defineConfig } from 'tsup';

export default defineConfig({
  entry: ['src/index.ts', 'src/button.ts'],
  format: ['cjs', 'esm'],
  dts: true,
  splitting: true,
  clean: true,
  treeshake: true,
  external: ['react', 'react-dom'],
});

Versionado con Changesets

# Instalar changesets
pnpm add -Dw @changesets/cli

# Inicializar
pnpm changeset init

# Cuando hagas un cambio, agrega un changeset
pnpm changeset
# Esto pregunta: ¿Qué paquetes cambiaron? ¿Mayor/menor/parche? ¿Descripción?

# Crea un archivo como:
# .changeset/brave-eagles-dance.md
---
"@acme/ui": minor
"@acme/tokens": patch
---

Se agregó nuevo componente Avatar con soporte de imagen de respaldo.

# Flujo de trabajo de versionado
pnpm changeset version   # Aumenta versiones, actualiza CHANGELOG
pnpm changeset publish   # Publica a npm

# En CI (GitHub Actions)
- name: Crear PR de Release o Publicar
  uses: changesets/action@v1
  with:
    publish: pnpm changeset publish
  env:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

📖 Documentación de Changesets →

Publicación a npm

# .npmrc para registros privados
@acme:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}

# O usa el registro público de npm
# Asegúrate de que package.json tenga:
{
  "name": "@acme/ui",
  "publishConfig": {
    "access": "public"
  }
}

# Script de compilación y publicación
# package.json (raíz)
{
  "scripts": {
    "release": "pnpm build && pnpm changeset publish"
  }
}

# Flujo de trabajo de GitHub Actions
name: Release

on:
  push:
    branches: [main]

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: pnpm/action-setup@v2
      - uses: actions/setup-node@v3
        with:
          node-version: 18
          cache: 'pnpm'
          registry-url: 'https://registry.npmjs.org'
      
      - run: pnpm install
      - run: pnpm build
      
      - name: Publicar
        uses: changesets/action@v1
        with:
          publish: pnpm changeset publish
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

Contribución Multi-Equipo

// Archivo CODEOWNERS para GitHub
# .github/CODEOWNERS

# El equipo central posee todo por defecto
* @acme/design-system-core

# Propiedad de componente específico
/packages/ui/src/data-table/ @acme/data-team
/packages/ui/src/charts/ @acme/analytics-team
/packages/tokens/ @acme/design-team

# Directrices de Contribución (CONTRIBUTING.md)
## Agregar un Nuevo Componente

1. Crea un issue de propuesta usando la plantilla
2. Obtén aprobación del equipo design-system-core
3. Crea componente siguiendo patrones en /packages/ui/src/Button
4. Agrega historias de Storybook
5. Agrega pruebas unitarias
6. Agrega changeset
7. Abre PR y solicita revisión

## Lista de Verificación de Componente
- [ ] Tipos TypeScript exportados
- [ ] Historia de Storybook con todas las variantes
- [ ] Pruebas unitarias con >80% de cobertura
- [ ] Accesibilidad probada (teclado + lector de pantalla)
- [ ] Documentación en MDX de Storybook
- [ ] Changeset agregado

Consumiendo Sistemas de Diseño

# Instalando el sistema de diseño
npm install @acme/ui @acme/tokens

# En tu aplicación
import { Button, Card } from '@acme/ui';
import '@acme/ui/styles.css'; // O importar tokens

// Tree-shaking: solo importa lo que usas
import { Button } from '@acme/ui/button';

// Estrategias de fijación de versión

// package.json
{
  "dependencies": {
    // Versión exacta (más segura, pero actualizaciones manuales)
    "@acme/ui": "2.1.0",
    
    // Caret: permite actualizaciones menores (recomendado)
    "@acme/ui": "^2.1.0",
    
    // Tilde: permite solo actualizaciones de parche
    "@acme/ui": "~2.1.0"
  }
}

// Configuración de Renovate para auto-actualizaciones
// renovate.json
{
  "extends": ["config:base"],
  "packageRules": [
    {
      "matchPackagePatterns": ["@acme/*"],
      "automerge": true,
      "automergeType": "branch"
    }
  ]
}

Herramientas de Sistema de Diseño

Turborepo

Sistema de compilación de monorepo de alto rendimiento

Nx

Kit de herramientas de monorepo con todas las características y generadores

tsup

Empaquetador TypeScript sin configuración impulsado por esbuild

Changesets

Gestión de versionado y changelog para monorepos

Chromatic

Pruebas visuales y revisión para componentes de interfaz

💡 Consejos de Escalado

  • • Comienza pequeño: no sobre-ingenierices temprano
  • • Establece propiedad clara con CODEOWNERS
  • • Usa versionado semántico estrictamente
  • • Documenta cambios que rompen compatibilidad a fondo
  • • Proporciona guías de migración para versiones mayores
  • • Configura pruebas de regresión visual automatizadas
  • • Crea directrices de contribución temprano
  • • Usa banderas de características para despliegues graduales