Tag: Programación

  • Cómo SDD y TDD optimizan el desarrollo con Claude Code

    Cómo SDD y TDD optimizan el desarrollo con Claude Code

    SDD + TDD: el combo que convierte a Claude Code en un dev senior

    Tiempo estimado de lectura: 4 min

    • SDD reduce las decisiones del agente; TDD valida de forma determinista.
    • Especificación primero, tests después: contratos claros y criterios ejecutables.
    • Aplica cuando hay lógica crítica, APIs públicas y repositorios tipados.

    Introducción

    SDD + TDD: el combo que convierte a Claude Code en un dev senior. Poca gente lo practica en equipos que prueban agentes, y sin embargo es la diferencia entre recibir código usable o un cajón de sorpresas que rompe en producción.

    Claude Code (motor basado en Claude 3.7 Sonnet) puede leer tu repo, ejecutar comandos y escribir código. Genial. También puede inventar abstracciones, tocar capas que no debe y aplicar convenciones que no son las tuyas. La solución no es pedir menos; es pedir mejor: especificación primero, tests después.

    Resumen rápido (lectores con prisa)

    SDD = especificaciones codificadas (tipos, interfaces, reglas). TDD = tests que hacen las especificaciones ejecutables. Juntos reducen la improvisación del agente y transforman código generado en artefactos verificables y mantenibles.

    Por qué SDD + TDD: el combo que convierte a Claude Code en un dev senior

    Un modelo de lenguaje es, por naturaleza, probabilístico. Sin restricciones explícitas, el agente construirá “la versión más probable” de tu feature, no la versión correcta para tu sistema. SDD (Specification-Driven Development) fuerza el contrato: tipos, firmas, reglas y límites. TDD (Test-Driven Development) convierte esos contratos en criterios ejecutables: rojo, verde, refactor.

    Juntos funcionan así:

    • SDD reduce el espacio de decisiones del agente.
    • TDD da un criterio determinista para validar el trabajo.
    • Claude Code deja de improvisar y se limita a cumplir pruebas que tú definiste.

    Referencias útiles: Anthropic (Claude) docs, TDD (Martin Fowler).

    Qué debe incluir una SDD práctica para agentes

    No es un brief largo: es el mínimo necesario para quitar decisiones al modelo.

    • Tipos e interfaces visibles en código
      TypeScript: exporta types / interfaces antes de pedir implementación. (TypeScript: docs)
      Python: define modelos Pydantic para entradas/salidas. (Pydantic)
    • Reglas explícitas de efectos secundarios
      “Función pura — sin DB, sin llamadas HTTP” o “Permitido: escribir en tabla payments; Prohibido: llamar a servicios externos”.
    • Manejo de errores y contratos de retorno
      `Result<T, E>` vs excepciones. Si decides una convención, documenta y hazla código.
    • Casos límite documentados
      Inputs inválidos, límites numéricos, retries, timeouts, políticas de deduplicación.

    Escribe esto en archivos que el agente pueda leer (por ejemplo *.types.ts, *.schema.py, .md con reglas) y no lo dejes solo en un prompt.

    El ciclo TDD que hace verificable al agente

    Con la spec lista, el flujo TDD para Claude Code es práctico y repetible:

    • Fase Roja — Generar tests.
      Prompt: claude “Lee payment.types.ts y las reglas en comments. Genera tests en Vitest que cubran todos los casos límite. Ejecuta los tests y reporta fallos.”
      Resultado esperado: tests fallando (porque no hay implementación).
    • Fase Verde — Implementación mínima.
      Prompt: claude “Implementa payment.ts respetando los tipos. Ejecuta los tests y corrige hasta que pasen en verde. No cambies firmas ni añadas dependencias externas.”
    • Refactor — Mejorar con seguridad.
      Prompt: claude “Refactoriza para reducir la complejidad ciclomática, manteniendo todos los tests en verde.”

    Herramientas recomendadas para el ciclo: Vitest o Jest, integradas en la terminal que usa Claude Code.

    Ejemplo práctico (resumen)

    En vez de: “Crea validación de email”, escribe:

    • types.ts:
      interface CreateUser { email: string; name?: string }
      type Result = { ok: true; value: T } | { ok: false; error: string }
    • Comentario en createUser.ts:
      // Función pura. Rechaza dominios genéricos (gmail.com, hotmail.com). Retorna Result. No lanza excepciones.
    • Prompts:
      • Genera tests → ejecuta → confirma fallo.
      • Implementa hasta pasar tests → refactor.

    La diferencia es mínima en tiempo de setup y enorme en predictibilidad.

    Cuándo aplicar este enfoque (y cuándo no)

    Aplica SDD + TDD cuando:

    • Construyes lógica de negocio crítica o APIs públicas.
    • Trabajas en repositorios compartidos y tipados.
    • Necesitas trazabilidad y responsabilidad en cambios.

    No lo apliques para:

    • Scripts one-off o hacks exploratorios.
    • Prototipos que requieren máxima velocidad de experimentación.

    Lo que cambian estas prácticas en tu equipo

    La escritura de código se convierte en commodity; el verdadero valor pasa a:

    • Diseñar contratos claros.
    • Anticipar edge cases.
    • Traducir decisiones de producto a reglas verificables.

    Claude Code seguirá escribiendo código — pero ahora ese código será verificable y, lo que es más importante, mantenible. Si defines la partitura (SDD) y pones el metrónomo (TDD), el agente tocará afinado.

    Fuentes y lectura recomendada

    FAQ

    ¿Qué es SDD y en qué se diferencia de un brief tradicional?

    SDD (Specification-Driven Development) codifica las decisiones clave —tipos, interfaces, reglas de efectos secundarios— en artefactos que el agente puede leer. Un brief tradicional suele ser texto libre; SDD es código y contrato.

    ¿Por qué es necesario TDD cuando uso un agente capaz de ejecutar tests?

    TDD transforma la especificación en criterios ejecutables (tests). Sin tests, el agente puede producir la solución más probable; con tests, debe producir la solución que pasa los criterios que definiste (rojo → verde → refactor).

    ¿Qué archivos debo incluir en la SDD para que el agente los use?

    Archivos legibles por el agente: *.types.ts, *.schema.py, y .md con reglas y comentarios. Define tipos, modelos y reglas de efectos secundarios en esos archivos.

    ¿Puedo usar este flujo con agentes distintos a Claude Code?

    Sí. El patrón SDD + TDD es aplicable a agentes que puedan leer repositorios y ejecutar comandos. Se basa en contratos verificables y tests automatizados, no en peculiaridades de un motor concreto.

    ¿Qué herramientas recomiendan para ejecutar el ciclo TDD?

    Herramientas recomendadas: Vitest o Jest. Integradas en la terminal del agente para ejecutar fases Roja/Verde/Refactor.

    ¿Cómo manejo cambios de contrato sin romper downstream?

    Versiona tipos y contratos, introduce migraciones y añade tests de compatibilidad. Documenta cambios en la SDD y agrega pruebas que verifiquen compatibilidad hacia atrás cuando sea necesario.

    ¿Cuándo NO debo aplicar SDD + TDD?

    No lo apliques para scripts one-off, hacks exploratorios o prototipos donde la prioridad es iterar rápido sin garantías fuertes.

  • Implementación de Managed Agents en la Plataforma de Anthropic

    Implementación de Managed Agents en la Plataforma de Anthropic

    Anthropic lanzó Managed Agents — agentes de largo plazo en la plataforma

    Tiempo estimado de lectura: 4 min

    • Managed Agents mueve la responsabilidad de ejecutar agentes de largo plazo desde tu infraestructura hacia la plataforma de Anthropic.
    • Proporciona primitivas críticas: sesiones estables, sandboxes con estado duradero, harnesses de ejecución y gestión segura de herramientas/credenciales.
    • La Rate Limits API permite orquestar y escalar controlando capacidad disponible antes de lanzar trabajos.
    • Patrón práctico: usar un orquestador (ej. n8n) para desacoplar el lanzamiento y la finalización de las sesiones agénticas.
    • Riesgos: vendor lock-in, observabilidad limitada, fuga de datos temporales y límites de tasa; requieren políticas y controles explícitos.

    Introducción

    Anthropic lanzó Managed Agents — agentes de largo plazo en la plataforma el 25 de abril de 2026. Esta funcionalidad en Claude Platform no es una mejora menor: cambia la responsabilidad operativa de ejecutar agentes agénticos prolongados desde tu infraestructura hacia la plataforma de Anthropic. Fuente: Anthropic Platform Docs

    Resumen rápido (lectores con prisa)

    Managed Agents ofrece sesiones estables, sandboxes con estado duradero, harnesses y gestión de herramientas/credenciales en la plataforma. Reduce engineering necesario para ejecutar agentes asíncronos largos y añade una Rate Limits API para orquestación segura. Útil cuando priorizas velocidad de entrega; no es apropiado si necesitas control forense total sobre ejecución y datos.

    Qué significa que Anthropic lanzó Managed Agents — agentes de largo plazo en la plataforma

    La noticia clave es de infraestructura, no de modelo. Managed Agents provee primitivas que antes tenías que inventar: sesiones estables, sandboxes con estado duradero, harnesses de ejecución y acceso seguro a herramientas. Eso corrige tres cuellos de botella clásicos de agentes autónomos en producción:

    • Persistencia de estado entre pasos (que evita reinyectar historial en cada request).
    • Aislamiento y ejecución segura de código (sandboxes duraderos).
    • Gestión segura de credenciales y herramientas (Secure Tool Use).

    Estos elementos transforman agentes episódicos y frágiles en procesos asíncronos confiables que pueden correr horas sin reinyectar contexto manualmente.

    Componentes técnicos y por qué importan

    Interfaces estables para sesiones

    Managed Agents expone IDs de sesión y APIs para consultar su estado. Eso permite diseños desacoplados: lanzas un agente, recibes un session_id y vuelves más tarde por el resultado. En prácticas reales esto reduce el acoplamiento entre orquestador (n8n, cron, Lambda) y ejecución agéntica.

    Harnesses y sandboxes con estado duradero

    El harness controla la inyección de prompts y la ejecución de herramientas; el sandbox es el runtime persistente donde sobreviven variables, artefactos y dependencias entre pasos. Esto elimina el cold-start continuo y permite construcciones incrementales (tests encadenados, scraping por lotes, refactors multi-archivo) sin retransmitir todo el contexto en cada llamada.

    Acceso seguro a herramientas

    Anthropic gestiona credenciales y permisos en la plataforma. El agente consume interfaces a servicios externos sin exponer secrets dentro del texto del prompt o logs de razonamiento. Es un requisito mínimo para producción: evita fugas accidentales de credenciales y facilita auditoría centralizada.

    Startup optimizado

    Reducir la latencia de arranque entre pasos cambia el coste operativo de tareas largas. Si tu agente ejecuta cientos de scripts por sesión, el ahorro acumulado en tiempo y coste es real y medible.

    Rate Limits API: control programático del escalado

    El 25 de abril Anthropic también lanzó la Rate Limits API, que permite consultar programáticamente los límites de tokens y uso de la organización. Si vas a orquestar docenas de agentes concurrentes, necesitas este dato antes de lanzar trabajos. Patrón operativo recomendado:

    • Consulta la Rate Limits API antes de encolar un agente.
    • Si la capacidad disponible es < 20% (umbral configurable), encola la tarea y reintenta más tarde.
    • Prioriza trabajos críticos y aplica un backoff exponencial en la cola.

    Ejemplo (pseudocurl): curl -H “Authorization: Bearer $ANTHROPIC_KEY” Rate Limits API

    Integración práctica con n8n (patrón de arquitectura)

    n8n es el orquestador natural para este enfoque. Patrón de integración:

    1. n8n recibe trigger (webhook, cron, evento).
    2. Llama a Rate Limits API; decide lanzamiento o encolado.
    3. Si hay cuota, invoca Managed Agent con contexto y guarda session_id.
    4. n8n cierra la ejecución; recibe webhook de finalización o consulta el estado con polling.
    5. Procesa y distribuye resultado (commit a Git, notificación Slack, inserción en DB).

    Este patrón desacopla totalmente el tiempo real de ejecución del agente del flujo orquestador, permitiendo escalado horizontal sin mantener hilos abiertos.

    Riesgos, límites y controles que debes imponer

    1. Vendor lock-in y compliance: durante la ejecución, código e inputs residirán en la plataforma de Anthropic. Para entornos regulados (SOC 2, HIPAA) exige SLA/Docs de retención y capacidad de auditoría antes de producción.
    2. Observabilidad y debugging: cuando una sesión falla dentro del sandbox, las herramientas forenses pueden ser menos ricas que en tu propio Kubernetes. Diseña checkpoints y exporta artefactos intermedios a tu almacenamiento controlado (S3 cifrado) con permisos limitados.
    3. Fugas de datos temporales: define políticas de redacción y minimización de datos en prompts; sanea PII antes de enviar a la plataforma.
    4. Rate limits y resiliencia: no asumas disponibilidad ilimitada. Implementa encolado, prioridad y backoff; monitoriza 429 y métricas de latencia.

    Cuándo delegar y cuándo no

    Delegar a Managed Agents tiene sentido cuando ahorrarás semanas de ingeniería en infra (sandboxes, orquestación, secretos) y necesitas fiabilidad en tareas asíncronas prolongadas. No lo uses si tu negocio requiere retención forense total o control absoluto sobre ejecución (por ejemplo, datos regulados que no pueden salir de tu red). En esos casos, preferir un cluster interno con un harness local y un modelo autohospedado —aunque más coste inicial— puede ser la opción correcta.

    Conclusión operativa

    Anthropic lanzó Managed Agents para abstraer la parte más aburrida y frágil de la ejecución agéntica: estado, aislamiento y herramientas. La plataforma acelera adopción, pero no elimina la responsabilidad del equipo: gobernanza, observabilidad y políticas de datos siguen siendo necesarias. Integra la Rate Limits API, usa un orquestador (n8n) para desacoplar, y define reglas rígidas de handoff, checkpoints y retención para evitar que un avance operativo se convierta en una deuda técnica costosa.

    Si quieres explorar patrones de integración y pruebas alrededor de orquestación y agentes, consulta Dominicode Labs para recursos y ejemplos prácticos que complementan este enfoque.

    FAQ

    Respuesta:

    Managed Agents son agentes de largo plazo gestionados por la plataforma de Anthropic; la funcionalidad fue lanzada el 25 de abril de 2026.

    Respuesta:

    Resuelven persistencia de estado entre pasos, aislamiento y ejecución segura (sandboxes), harnesses para ejecutar herramientas y gestión segura de credenciales, reduciendo la necesidad de infraestructura propia para agentes asíncronos largos.

    Respuesta:

    La Rate Limits API permite consultar los límites de tokens y uso organizacional de forma programática, lo que te deja decidir antes de encolar o lanzar agentes y aplicar encolado/prioridad/backoff cuando la capacidad es limitada.

    Respuesta:

    n8n sirve como orquestador desacoplado: recibe triggers, consulta Rate Limits API, lanza Managed Agents guardando session_id y luego procesa resultados con webhooks o polling, evitando mantener hilos abiertos y facilitando escalado horizontal.

    Respuesta:

    Riesgos clave: vendor lock-in y requisitos de compliance, menor observabilidad forense dentro del sandbox, posible fuga de datos temporales y dependencia en límites de tasa; se requieren políticas, checkpoints y exportación controlada de artefactos.

    Respuesta:

    No delegues si tu negocio exige retención forense total o control absoluto sobre la ejecución y datos (por ejemplo, datos regulados que no pueden salir de tu red). En esos casos, considera un cluster interno con harness local y modelo autohospedado.

  • Cómo usar Map.getOrInsert() en JavaScript para mejorar tu código

    Cómo usar Map.getOrInsert() en JavaScript para mejorar tu código

    Map.getOrInsert(): el método que siempre quisiste en JavaScript

    Tiempo estimado de lectura: 4 min

    • Menos código, más intención: getOrInsert/getOrInsertComputed expresan “devuelve o crea” en una llamada atómica.
    • Mejor tipado en TypeScript 6.0: el retorno es T, no T | undefined, reduciendo aserciones peligrosas.
    • Uso práctico: útil en cachés, agrupaciones, contadores y construcción de grafos; evita inicializaciones innecesarias.

    Resumen rápido (lectores con prisa)

    Map.getOrInsert y Map.getOrInsertComputed permiten obtener un valor existente o insertar uno nuevo en una sola operación. En TypeScript 6.0, con target: "esnext" y lib: ["esnext"], estos métodos están tipados para devolver T en vez de T | undefined. Use getOrInsert cuando quiera expresar “devuelve o crea” de forma atómica; use la variante computada para evitar inicializaciones costosas salvo que sean necesarias.

    Map.getOrInsert(): el método que siempre quisiste en JavaScript (qué es y cómo funciona)

    Map.getOrInsert(): el método que siempre quisiste en JavaScript aparece en la primera línea porque no es una mejora menor: es la forma de expresar, de manera atómica y tipada, la intención que antes requería tres operaciones verbosas. TypeScript 6.0 ya expone los tipos vía esnext y la propuesta ECMAScript que la introduce ha alcanzado Stage 4. Aquí te explico qué hace, por qué importa y cómo integrarlo con criterio en código de producción.

    Qué hace y cómo funciona

    El patrón clásico —buscar, insertar si no existe, y luego usar— se repite en cachés, agrupaciones, contadores y grafos. Tradicionalmente escribíamos:

    if (!map.has(key)) map.set(key, compute());
    const v = map.get(key)!;

    Tres operaciones, doble lookup y una aserción no nula que silencia al compilador. getOrInsert y su variante perezosa getOrInsertComputed resuelven eso en una sola llamada:

    • map.getOrInsert(key, defaultValue): devuelve el valor si existe, si no inserta y devuelve el defaultValue.
    • map.getOrInsertComputed(key, () => value): ejecuta la función sólo si la clave no existía, evitando inicializaciones innecesarias y efectos secundarios.

    En TypeScript 6.0, usando target: "esnext" y lib: ["esnext"], el compilador tipa estos métodos de forma que el retorno es T (no T | undefined). El contrato refleja la intención: si llamas, obtienes un valor seguro.

    Por qué esto no es solo “azúcar sintáctico”

    Tres razones prácticas:

    1. Menos errores de tipo

    Con el patrón manual el compilador ve get() como T | undefined. Con getOrInsert obtienes T. Menos comprobaciones defensivas, menos ! peligrosos.

    2. Menos overhead y operaciones atomizadas

    Evitas doble lookup (has + get). Aunque la mejora de rendimiento es pequeña en muchos casos, en bucles grandes o inicializaciones masivas suma.

    3. Menos ruido cognitivo

    La intención queda expresada: “devuelve o crea”. El lector del código no necesita reconstruir el propósito tras tres líneas.

    Casos reales donde cambia la vida

    – Cachés con inicialización costosa: evita ejecutar la función de cálculo salvo que sea estrictamente necesario.

    – Agrupaciones: Map<string, T[]> ya no requiere crear arrays temporales.

    – Contadores y histogramas: inicializar un contador a 0 en una sola línea es más legible.

    – Construcción de grafos (listas de adyacencia): evita boilerplate en algoritmos BFS/DFS.

    Ejemplo típico

    const groups = new Map<string, User[]>();
    
    function addUser(role: string, user: User) {
      groups.getOrInsertComputed(role, () => []).push(user);
    }

    Sencillo, explícito y sin crear arrays inútiles.

    Integración práctica en repositorios TypeScript

    1. Habilita esnext en tsconfig:
      {
        "compilerOptions": {
          "target": "esnext",
          "lib": ["esnext"],
          "strict": true
        }
      }
    2. Revisa compatibilidad runtime:

      TypeScript te da la comprobación estática. La API como tal puede requerir polyfill o verificar la versión de Node/Bun/deno si no está implementada nativamente en tu motor.

    3. Refactor incremental:

      Busca utilidades internas con nombres como getOrCreate, getOrInit o computeIfAbsent. Reemplaza utilidades por el método nativo en PRs pequeños. Añade pruebas unitarias para casos bordes (excepciones en la función de cálculo, concurrencia en entornos compartidos).

    4. No abuses de getOrInsertComputed con side effects:

      La función de cálculo se invoca solo cuando hace falta, pero debe ser determinista y preferiblemente sin efectos secundarios que el mapa pueda registrar de forma incompleta si ocurre una excepción.

    Consideraciones de diseño y criterio Dominicode

    Estándar sobre conveniencia: si ya tienes utilidades internas, migrar a getOrInsert reduce mantenimiento y mejora la expresividad.

    No sustituyas estructuras lógicas: usar Map con getOrInsert no es excusa para diseños pobres. Sigue definiendo responsabilidades y límites de módulo.

    Audita y documenta: añade esta patrón a las guías internas y revisiones de código para homogenizar su uso.

    Fuentes y lectura adicional

    Adoptar Map.getOrInsert() hoy es reducir ruido, reforzar tipos y expresar intención. No es una moda: es una higiene mínima que facilita mantener bases de código grandes sin perder claridad. Si eres Tech Lead, estandariza su uso; si eres desarrollador, empieza a buscar esos utils/mapGetOrCreate.ts y reemplázalos por la API del lenguaje.

    FAQ

    Respuesta — ¿Qué devuelve getOrInsert si la clave existe?

    Devuelve el valor existente asociado a la clave. El contrato asegura que el retorno es T, no T | undefined.

    Respuesta — ¿En qué se diferencia getOrInsert de getOrInsertComputed?

    getOrInsert recibe un valor por defecto ya construido; getOrInsertComputed recibe una función que se ejecuta solo si la clave no existe, evitando costes de inicialización cuando no son necesarios.

    Respuesta — ¿Necesito un polyfill para usarlo en producción?

    Depende del runtime. TypeScript ofrece comprobación estática cuando apuntas a esnext, pero la API puede no estar presente en versiones antiguas de Node/Bun/deno; en esos casos se requiere polyfill o verificación de la versión del motor.

    Respuesta — ¿Cómo mejora el tipado en TypeScript 6.0?

    Con target: "esnext" y lib: ["esnext"], los tipos para estos métodos hacen que el retorno sea T, evitando la necesidad de aserciones (!) y reduciendo comprobaciones manuales de undefined.

    Respuesta — ¿Es seguro usarlo en entornos concurrentes?

    El método evita doble lookup, pero la seguridad en entornos concurrentes depende del runtime y del modelo de concurrencia. Añade pruebas y, si corresponde, mecanismos de sincronización en entornos compartidos.

    Respuesta — ¿Debo reemplazar todas mis utilidades internas?

    No necesariamente. Migra en PRs pequeños y cuando aporte claridad o reduzca mantenimiento. Prioriza casos donde el beneficio sea evidente (cachés, agrupaciones, contadores).

    Respuesta — ¿Qué precauciones al usar funciones con efectos secundarios?

    La función de cálculo en getOrInsertComputed debe ser determinista y preferiblemente sin efectos secundarios. Si lanza una excepción, el mapa podría quedar en un estado intermedio; maneja errores y añade pruebas para esos casos.

  • Cómo crear una librería npm tipada en TypeScript para desarrolladores

    Cómo crear una librería npm tipada en TypeScript para desarrolladores

    Cómo hacer una librería npm tipada con TypeScript

    Tiempo estimado de lectura: 5 min

    • Entrega dual: código ejecutable + declaraciones de tipo (.d.ts) para buena DX.
    • Configuración esencial: tsconfig con declaration: true y salida limpia en dist/.
    • Empaquetado: mapear main/module/types en package.json y validar con npm pack y tsc en proyecto consumidor.
    • Exportaciones claras: centralizar API en src/index.ts y usar export type para tipos.
    • Validación: pruebas de tipos en CI con tsd y tests locales antes de publish.

    Introducción

    Saber cómo hacer una librería npm tipada con TypeScript significa entregar dos cosas a la vez: código que la máquina ejecuta y tipos que el desarrollador consume. Desde el primer archivo hasta el .d.ts final, la meta es que quien instale tu paquete tenga autocompletado y verificaciones de tipo sin tocar su configuración. Esta guía va directo al flujo de producción: configuración, estructura, packaging y validación local.

    Resumen rápido (lectores con prisa)

    Una librería npm tipada combina JavaScript/TypeScript compilado y declaraciones de tipo (.d.ts). Usa tsc con declaration: true para generar tipos; centraliza la API en src/index.ts; apunta types en package.json al .d.ts maestro; valida con npm pack y ejecuta tsc --noEmit en un proyecto consumidor.

    Cómo hacer una librería npm tipada con TypeScript — pasos y criterios

    1. Estructura mínima

    • src/ — código TypeScript.
    • dist/ — artefactos compilados (generado).
    • package.json, tsconfig.json, README.md.

    2. Instala y prepara TypeScript

    npm init -y
    npm install typescript --save-dev
    npx tsc --init

    3. tsconfig.json recomendable (base)

    {
      "compilerOptions": {
        "target": "ES2020",
        "module": "CommonJS",
        "moduleResolution": "node",
        "declaration": true,
        "declarationMap": true,
        "outDir": "./dist",
        "rootDir": "./src",
        "strict": true,
        "esModuleInterop": true,
        "skipLibCheck": true,
        "forceConsistentCasingInFileNames": true
      },
      "include": ["src/**/*"],
      "exclude": ["node_modules", "**/*.test.ts"]
    }
    • declaration: true es obligatorio: genera .d.ts.
    • declarationMap: true mejora la experiencia “Go to definition” en IDEs.
    • outDir y rootDir mantienen el árbol limpio.

    Documentación oficial TypeScript: TypeScript declaration files publishing

    4. Código: exportaciones claras y barrel file

    Centraliza la API pública en src/index.ts. Exporta valores y tipos explícitamente:

    // src/types.ts
    export interface LibraryConfig { timeout: number; }
    
    // src/core.ts
    import type { LibraryConfig } from './types';
    export function init(cfg: LibraryConfig) { /* ... */ }
    
    // src/index.ts
    export { init } from './core';
    export type { LibraryConfig } from './types';
    

    Usa export type para separar contratos estáticos (no existen en runtime). Evita filtrar internals por accidente.

    5. package.json: el contrato que vincula .js y .d.ts

    {
      "name": "mi-libreria-tipada",
      "version": "1.0.0",
      "main": "dist/cjs/index.js",
      "module": "dist/esm/index.js",
      "types": "dist/index.d.ts",
      "files": ["dist"],
      "scripts": {
        "build": "npm run build:cjs && npm run build:esm",
        "build:cjs": "tsc --outDir dist/cjs --module commonjs",
        "build:esm": "tsc --outDir dist/esm --module ESNext",
        "prepublishOnly": "npm run build"
      },
      "exports": {
        ".": {
          "types": "./dist/index.d.ts",
          "require": "./dist/cjs/index.js",
          "import": "./dist/esm/index.js"
        }
      }
    }
    • types debe apuntar al .d.ts maestro.
    • files actúa como whitelist; evita subir src o configs.
    • exports (condicional) habilita resolución moderna y puede mapear CJS/ESM. Coloca types junto a la condición raíz para que TypeScript lo resuelva bien.

    Si publicas scoped package (p. ej. @scope/name), recuerda npm publish --access public para paquetes públicos.

    6. ¿Generar .d.ts con tsc o con bundler?

    • Para proyectos simples o librerías de funciones: usa tsc con declaration: true. Es robusto y sencillo.
    • Para bundles complejos (single-file output), usa un plugin para generar tipos como rollup-plugin-dts o la opción tsup --dts. Si eliges esta vía, verifica que el .d.ts final coincida con la estructura exportada.

    Herramientas útiles:

    7. Validación local antes de publicar

    1. npm pack — crea un .tgz. Ábrelo y verifica contenido: dist/, package.json, README.md.

      Docs: npm pack docs

    2. Instalación local en proyecto cliente:
      cd ../project-test
      npm install /ruta/a/mi-libreria-tipada-1.0.0.tgz

      Importa y ejecuta tsc --noEmit en el proyecto consumidor: si types está mal, fallará aquí.

    3. Tests de tipos automáticos: integra tsd en tu CI para asegurar que la API expuesta no cambia rompeints:

      tsd

    8. Dependencias y peerDependencies

    • Declara en peerDependencies librerías que el consumidor debe proveer (React, por ejemplo) para evitar duplicados.
    • Pon utilidades que la librería necesita en dependencies.

    9. Checklist rápido antes de publish

    • [ ] npm run build genera dist con .js y .d.ts.
    • [ ] package.json apunta a main, module (si aplica) y types.
    • [ ] files incluye solo dist, README.md, LICENSE.
    • [ ] npm pack inspeccionado.
    • [ ] Prueba de instalación local y tsc --noEmit en proyecto consumidor.
    • [ ] Tests de tipos (tsd) pasados en CI.

    10. Comandos finales para publicar

    npm login
    npm publish --access public

    (Usa --access public para paquetes scope públicos.)

    Conclusión

    Construir una librería tipada no es mágico: es disciplina. Configura tsc para emitir declaraciones, expone solo lo necesario y valida el paquete en un entorno consumidor antes de pulsar publish. El tiempo que inviertes en estos pasos se recupera con menos issues en integraciones y una mejor experiencia para quienes usan tu paquete.

    FAQ

    ¿Por qué es obligatorio generar .d.ts?

    Las declaraciones (.d.ts) proporcionan tipos a los consumidores de tu librería sin necesidad de que compilen tu código TypeScript. Sin ellas, los usuarios perderían autocompletado y las comprobaciones de tipo.

    ¿Puedo usar un bundler para generar tipos?

    Sí. Para bundles single-file es común usar plugins como rollup-plugin-dts o herramientas como tsup --dts. Verifica que el resultado refleje la API exportada.

    ¿Qué debe apuntar el campo types en package.json?

    types debe apuntar al .d.ts maestro que describe la API pública, por ejemplo dist/index.d.ts.

    ¿Cómo pruebo la experiencia del consumidor antes de publicar?

    Usa npm pack para generar un .tgz, instálalo en un proyecto de prueba con npm install /ruta/mi-libreria.tgz y ejecuta tsc --noEmit en el proyecto consumidor.

    ¿Debo usar peerDependencies para React?

    Sí. Declara frameworks como React en peerDependencies para evitar múltiples copias y problemas de compatibilidad en el proyecto consumidor.

    ¿Qué herramientas recomiendo para pruebas de tipos en CI?

    Integra tsd en tu CI para pruebas automáticas de tipos. Revisa tsd para más detalles.

    ¿Qué archivos incluir en el paquete publicado?

    Usa files en package.json para incluir solo dist, README.md y LICENSE. Evita subir src o configuraciones internas.

  • Cómo utilizar OpenSpec para documentar APIs de forma efectiva

    Cómo utilizar OpenSpec para documentar APIs de forma efectiva

    Qué es OpenSpec y como empezar a usarlo?

    Tiempo estimado de lectura: 4 min

    Ideas clave:

    • OpenSpec (típicamente OpenAPI) es un contrato interoperable para describir APIs RESTful en YAML o JSON.
    • Buenas especificaciones reducen errores, permiten generación de SDKs y mejoran el comportamiento de agentes IA.
    • Empieza con un openapi.yaml válido, centraliza esquemas en components/schemas y valida con linters en CI/CD.
    • Decide una única fuente de la verdad: la spec o el código; sincronízalos para evitar drift.
    • Usa herramientas como Spectral, openapi-generator, Orval y n8n para integrar la spec en tu stack.

    Tabla de contenidos

    ¿Quieres que tus APIs hablen claro con humanos, herramientas y agentes de IA? Entender qué es OpenSpec y como empezar a usarlo es el primer paso para dejar de parchear integraciones y empezar a diseñar sistemas que realmente escalan.

    Resumen rápido (lectores con prisa)

    OpenSpec (normalmente OpenAPI) es un contrato en YAML/JSON que describe endpoints, parámetros y respuestas. Usarlo permite generación de clientes, validación automática y que agentes IA descubran y llamen funciones. Empieza con un openapi.yaml, centraliza esquemas en components/schemas y valida con Spectral en CI/CD.

    Qué es OpenSpec (breve y sin rodeos)

    OpenSpec = OpenAPI (típicamente). Repositorio oficial: OpenAPI Spec repo.

    Es un estándar agnóstico al lenguaje para describir APIs RESTful en YAML o JSON. No es solo “documentación bonita”: es un artefacto interoperable que potencia generación de clientes, validación en CI/CD y, hoy en día, el comportamiento de agentes IA que realizan tool-calling.

    Si lo haces bien, reduces preguntas, errores y tiempo de debugging. Si lo haces mal, tus integraciones sufrirán en silencio.

    Por qué importa ahora (sí, de verdad)

    • Los modelos de lenguaje consumen especificaciones para descubrir capacidades y ejecutar llamadas: mejores especificaciones = agentes más útiles.

    • Herramientas como n8n pueden mapear rutas desde una OpenSpec y reducir el trabajo manual en flujos.

    • Generadores como openapi-generator o Orval crean SDKs y hooks tipados: menos errores y builds que fallan temprano.

    • Linters como Spectral te permiten bloquear cambios que rompan contratos en CI/CD.

    Si tu arquitectura usa automatizaciones, agentes o consumidores externos, OpenSpec deja de ser “opcional” y pasa a ser infraestructura.

    Cómo empezar a usar OpenSpec en 5 pasos prácticos

    1) Elige formato: YAML por defecto

    YAML es más legible en PRs, permite comentarios y evita ruido. JSON es válido, pero menos humano.

    2) Crea el archivo base openapi.yaml con metadatos

    Ejemplo mínimo:

    openapi: 3.1.0
    info:
      title: API de Gestión de Usuarios
      version: 1.0.0
    servers:
      - url: https://api.midominio.com/v1

    3) Modela endpoints y componentes reutilizables

    Centraliza esquemas en components/schemas. Usa operationId en cada operación: es la referencia estable que usan generadores y agentes.

    Ejemplo:

    paths:
      /usuarios:
        get:
          operationId: getUsuarios
          summary: Lista usuarios activos
          responses:
            '200':
              description: OK
              content:
                application/json:
                  schema:
                    type: array
                    items:
                      $ref: '#/components/schemas/Usuario'
    
    components:
      schemas:
        Usuario:
          type: object
          required: [id, nombre]
          properties:
            id:
              type: string
              format: uuid
            nombre:
              type: string

    4) Valida y lintea en CI/CD

    Instala Spectral y córrelo en tus pipelines:

    npm install -g @stoplight/spectral-cli
    spectral lint openapi.yaml

    Configura reglas propias para estilo y seguridad. Esto evita que la IA actúe sobre un contrato erróneo.

    5) Conecta la especificación a tu stack

    • n8n: importa la spec para mapear rutas en nodos HTTP.

    • Frontend: usa Orval para generar hooks React/Next o servicios Angular.

    • Backend: genera SDKs con openapi-generator.

    • Agentes IA: pasa el YAML como “capability file” al sistema prompt o úsalo con LangChain para que los agentes sepan qué funciones pueden invocar.

    Decisiones prácticas: cuándo autogenerar y cuándo escribir

    • Si tu API cambia rápido o es grande: genera la OpenSpec desde código fuente o desde un DSL (ej. TypeSpec de Microsoft TypeSpec). Mantener un YAML manual de miles de líneas es fuego lento.

    • Si tu API es estable y pequeña: editar manualmente puede ser más rápido y explícito.

    • Regla simple: la fuente de la verdad debe ser única. O el código genera la spec, o la spec manda al código. No ambos sin sincronización.

    Riesgos y límites a considerar

    • Verbosidad: OpenAPI 3.x puede crecer mucho. Divide specs por dominios si hace falta.

    • Ambigüedad semántica: un buen schema evita que agentes “adivinen” parámetros. Sé explícito con required, tipos y ejemplos.

    • Seguridad: nunca publiques specs con credenciales ni ejemplos sensibles.

    Herramientas clave (rápido)

    Si tu trabajo incluye automatización, agentes o workflows, puede interesarte explorar recursos adicionales en Dominicode Labs como una continuación práctica para integrar especificaciones en pipelines y agentes. La mención apunta a material y experimentos que complementan las prácticas aquí descritas.

    FAQ

    ¿Qué diferencia hay entre OpenSpec y OpenAPI?

    OpenSpec, en el uso común, suele referirse a la OpenAPI Specification (OAS). Es el estándar para describir APIs RESTful en YAML o JSON.

    ¿Debo usar YAML o JSON?

    YAML es preferible para edición humana y PRs por su legibilidad y soporte de comentarios. JSON es igualmente válido pero menos práctico para revisión manual.

    ¿Cómo integro Spectral en CI/CD?

    Instala la CLI (npm install -g @stoplight/spectral-cli) y añade un paso en tu pipeline que ejecute spectral lint openapi.yaml. Configura reglas para estilo y seguridad para bloquear merges que rompan contratos.

    ¿Cuándo genero la spec desde código?

    Cuando el API cambia rápido o es grande: generar la spec desde el código o desde un DSL evita drift y reduce la carga de mantenimiento manual.

    ¿Puedo usar la spec con agentes IA?

    Sí. Puedes pasar el YAML como “capability file” en prompts o usar frameworks como LangChain para que los agentes conozcan las funciones disponibles.

    ¿Qué evitar al publicar una spec?

    No publiques credenciales ni ejemplos con datos sensibles. Evita ambigüedades en tipos y required; sé explícito para que consumidores y agentes no adivinen.

  • Implementación de Agent Skills para proyectos Angular

    Implementación de Agent Skills para proyectos Angular

    Hacer post sobre los Agent Skills de angular: guía práctica para arquitectos y equipos

    Tiempo estimado de lectura: 3 min

    • Agent Skills son capacidades automatizadas para leer, analizar y proponer cambios en código Angular respetando arquitectura y límites.
    • Prioridad ahora: Standalone Components, Signals, inject() y Zoneless requieren que la IA entienda contexto antes de tocar código.
    • Flujo operativo: discovery read‑only → auditorías estáticas → propuestas mecánicas en rama con PR y revisión humana.
    • Governance: integrar skills en CI, playbooks y dashboards para trazabilidad y control de riesgos.

    Hacer post sobre los Agent Skills de angular no es levantar hype ni repetir buzzwords; es ordenar una pieza crítica del puzzle: cómo convertimos agentes de IA en revisores técnicos y refactorizadores seguros para proyectos Angular. Si tu equipo opera con monorepos, Signals y rutas lazy, necesitas que la IA entienda topología, prácticas y riesgo antes de tocar una línea de código.

    Resumen rápido (lectores con prisa)

    Agent Skills son capacidades programáticas para que un agente automatizado lea, analice y proponga cambios en un repo Angular respetando arquitectura. Úsalos para discovery read‑only, auditorías estáticas y para generar propuestas en ramas con revisión humana. Integrar skills en CI y playbooks es clave para trazabilidad y control de riesgo.

    Qué son los Agent Skills de Angular (y por qué importan)

    Los Agent Skills son capacidades programáticas que permiten a un agente automatizado leer, analizar y —con límites— transformar código Angular respetando la arquitectura del proyecto. No hablamos de completados contextuales: hablamos de habilidades concretas para mapear workspaces, auditar patrones reactivos, detectar fugas de memoria y proponer refactorizaciones alineadas con la versión del framework.

    Por qué ahora

    Angular cambió. Standalone Components, Signals, inject() y la tendencia Zoneless hacen que un snippet bien formado pueda ser, en contexto, una regresión. El objetivo de los Agent Skills es cerrar la brecha entre lo que el modelo “sabe” y lo que el repo “es”.

    Categorías de Agent Skills (práctico y accionable)

    1) Descubrimiento y topología (Read‑Only)

    Mapeo de workspace

    Mapeo de workspace: lee angular.json / project.json y detecta apps, librerías y fronteras de dominio. Referencia: Nx.

    Árbol de dependencias

    Árbol de dependencias: construye el grafo de importaciones para detectar fronteras violadas o riesgos de dependencia circular.

    Regla de oro: siempre en modo solo lectura. Ejecutar antes de cualquier propuesta.

    2) Auditoría y análisis estático (reportes)

    Detección de fugas

    Detección de fugas: localizar suscripciones sin cleanup (ngOnDestroy, takeUntilDestroyed()), event listeners no removidos o timers persistentes.

    Change detection check

    Change detection check: validar OnPush vs mutaciones por referencia que rompen el rendering.

    Compatibilidad Zoneless

    Compatibilidad Zoneless: identificar patrones que dependen de la detección implícita de zone.js. Referencia: zone.js.

    Resultado: un informe accionable con líneas de riesgo, prioridad y referencia documental.

    3) Modernización y refactorización (propuestas con revisión humana)

    Migración a Standalone

    Migración a Standalone: extraer un componente de un NgModule, aplicar standalone: true y actualizar rutas lazy.

    Refactor inject()

    Refactor inject(): reemplazar inyección por constructor cuando el patrón lo permita.

    RxJS → Signals

    RxJS → Signals: transformar estados locales sincronizados (BehaviorSubject) a signal()/computed() cuando no haya flujos asíncronos complejos.

    Nota: estas operaciones deben proponerse en PRs, nunca aplicarse directamente en main sin revisión.

    Ejemplo de flujo mínimo (adoptable hoy)

    1. PR abierto → webhook dispara workflow.
    2. Ejecutar skills Read‑Only: mapea workspace + análisis de dependencias.
    3. Ejecutar auditorías: fugas, OnPush, Zoneless. Adjuntar report con URLs de documentación (angular.dev).
    4. Si todo OK, ejecutar propuestas mecánicas (migración Standalone o inject()) en una rama de trabajo y abrir PR automático con checklist y pruebas.

    Este flujo es orquestable con n8n o runners CI que disparen agentes y persistan resultados para trazabilidad.

    Criterio técnico (lo que no debes automatizar sin control)

    • No otorgues permisos de escritura globales hasta que el agente haya corrido los skills de descubrimiento y get_best_practices.
    • Tratar la migración Zoneless como diagnóstico, no como parche automático: los efectos secundarios en tiempo de ejecución y librerías externas pueden romper producción.
    • No convertir RxJS → Signals de forma indiscriminada; define reglas: solo estado local sincronizable y sin operadores complejos.
    • Exige trazabilidad: cada recomendación viene con fragmento de doc y URL a la sección relevante de angular.dev.

    Integración con gobernanza y equipos

    Los Agent Skills dejan de ser experimentales cuando se integran en:

    • Pipelines de CI que registran outputs de los inspectores junto al PR.
    • Playbooks de revisión que establecen qué skills pueden autocorregir en ramas de feature y cuáles requieren aprobación de un Senior.
    • Dashboards de deuda técnica que priorizan hallazgos del agente (fugas, violaciones de fronteras, patrones Zoneless).

    Qué ganas — y cuánto riesgo evitas

    Implementar Agent Skills bien definidos reduce regresiones arquitectónicas, acelera migraciones repetitivas y convierte a la IA en un revisor que aporta contexto (no solo snippets). El retorno real es tiempo de arquitecto liberado para decisiones complejas y menos deuda introducida por cambios automáticos mal contextualizados.

    Cierre práctico

    1. Añadir un skill de mapeo de workspace en tu pipeline.
    2. Automatizar la auditoría de fugas por cada PR.
    3. Pilotar migraciones Standalone en ramas feature con revisión humana.

    Con eso pones la IA a trabajar para tu arquitectura, no contra ella.

    Si quieres integrar estos workflows en tus pipelines y experimentos, considera explorar recursos y experiments en Dominicode Labs. Es una continuación natural para llevar skills de inspección y orquestación a pipelines con trazabilidad y playbooks.

    FAQ

    ¿Qué son exactamente los Agent Skills en Angular?

    Son capacidades programáticas que permiten a un agente automatizado leer, analizar y, con límites, transformar código Angular respetando la arquitectura del proyecto. Incluyen discovery, auditoría estática y generación de propuestas para revisión humana.

    ¿Cuándo debo ejecutar los skills en un PR?

    El flujo recomendado es: al abrir un PR, disparar skills Read‑Only (mapeo de workspace y análisis de dependencias) y luego las auditorías (fugas, OnPush, Zoneless). Solo después de pasar estos pasos se generan propuestas mecánicas en una rama separada.

    ¿Puede el agente aplicar cambios directamente en main?

    No. Las operaciones de modificación deben proponerse en PRs y revisarse. No otorgues permisos de escritura globales hasta validar discovery y mejores prácticas. Las transformaciones automatizadas requieren trazabilidad y aprobación.

    ¿Cómo integro los reports en CI?

    Orquesta el flujo con webhooks o runners CI: al abrir PR disparas agentes que persisten los resultados junto al PR. Puedes usar herramientas como n8n para orquestación y almacenar informes para dashboards de deuda técnica.

    ¿Qué precauciones con Zoneless?

    Trata la migración Zoneless como diagnóstico, no como parche automático. Identifica patrones que dependen de zone.js y evalúa efectos secundarios en tiempo de ejecución y librerías externas antes de proponer cambios.

    ¿Cómo asegurar trazabilidad de recomendaciones?

    Cada recomendación debe incluir fragmentos de doc y un enlace a la sección relevante de angular.dev, junto con el contexto del repo (archivo, línea, grafo de dependencias) y el historial del agente que generó la sugerencia.

  • Cómo orquestar subagentes de IA para un desarrollo eficaz

    Cómo orquestar subagentes de IA para un desarrollo eficaz

    Subagentes como equipo de desarrollo: orquestación con Claude Code

    Tiempo estimado de lectura: 4 min

    Ideas clave

    • Plan, delega, commit, valida: estructura que convierte a un asistente en un equipo con coordinador y subagentes.
    • Riesgos mitigados: degradación de contexto, decisiones implícitas y falta de trazabilidad.
    • Regla de commit inquebrantable: cada subagente debe hacer un commit atómico antes de avanzar.
    • DAG y paralelismo: lanzar en paralelo solo nodos sin dependencias y revisar diffs antes de desbloquear dependientes.
    • Requisitos para producción: CLAUDE.md, pipelines rápidos, política de revisión y auditoría de commits.

    Introducción

    Subagentes como equipo de desarrollo: orquestación con Claude Code es el patrón que convierte a un asistente de IA en un equipo real: un coordinador que descompone trabajo y subagentes que ejecutan tareas atómicas, hacen commits y devuelven resultados auditables. Si vas a automatizar entregas complejas, empieza por esta estructura: plan, delega, commit, valida.

    Resumen rápido (lectores con prisa)

    Patrón que transforma un asistente en un equipo con un coordinador que define la spec y un conjunto de subagentes que implementan tareas atómicas. Útil cuando puedes separar trabajo por interfaces claras y hay necesidad de trazabilidad y rollback atómico. Requiere commits por subagente, pipelines rápidos y un CLAUDE.md como referencia.

    Subagentes como equipo de desarrollo: por qué importa y cómo cambia el riesgo

    La diferencia entre generar código rápido y entregar cambios sostenibles no está en la velocidad de la IA, sino en cómo gestionas el contexto y las decisiones. Un agente que trabaja solo acumula contexto y toma decisiones implícitas; eso produce deuda técnica que emerge en integración. Orquestar subagentes reduce tres riesgos claves:

    • Degradación de contexto: cada subagente opera con una ventana limitada y relevante.
    • Propagación de decisiones implícitas: el coordinador valida outputs antes de avanzar.
    • Falta de trazabilidad: cada subagente hace un commit atómico, facilitando revertir y revisar.

    Documentación útil: Claude Code overview y Claude (Anthropic)

    Cómo funciona el flujo: roles, primitives y regla del commit

    1. Agente principal (coordinador)

    – Define la spec global y el DAG de dependencias.
    – Descompone el trabajo en tareas atómicas.
    – Lanza subagentes con la primitiva task.

    2. Subagentes (desarrolladores)

    – Reciben una tarea acotada: archivos relevantes, firmas esperadas, criterios de aceptación.
    – Implementan cambios, añaden tests y hacen un commit.
    – Devuelven al coordinador el diff, logs de test y un resumen de riesgos pendientes.

    3. Regla inquebrantable: cada subagente hace un commit antes de que el coordinador asigne la siguiente tarea dependiente

    Beneficios: aislamiento de errores, validación incremental, trazabilidad en Git.

    Ejemplo de secuencia para migración

    • Task 1: migrar modelo de pagos → commit “payments: migrate model v2”
    • Task 2: actualizar servicio de facturación (depende de Task 1) → commit “billing: use payments v2”
    • Task 3: actualizar tests e2e (paralelo) → commit “tests: update e2e for payments v2”

    Reglas operativas: cómo escribir tareas para subagentes

    Una mala especificación produce malos resultados, aunque el subagente sea capaz. Sigue estas reglas:

    • Objetivo claro en 1–2 líneas.
    • Alcance: archivos y módulos permitidos.
    • Contratos: firmas, DTOs, errores esperados.
    • Criterios de aceptación automatizables (tests unitarios o comandos de CI).
    • Comando de commit esperado y mensaje sugerido.
    • Limitar tiempo/recursos si procede.

    Plantilla mínima para una tarea

    • Título: actualizar UserService para usar AuthV2
    • Archivos permitidos: src/services/userService.ts, src/types/auth.ts
    • Contrato: getUser(id): UserDto
    • Tests: añadir unit tests para getUser con mocks de AuthV2
    • Commit: “user: migrate to AuthV2 — tests added”

    Integración, paralelismo y control de dependencias

    – Construye un DAG (grafo acíclico) de tareas. Lanza en paralelo solo nodos sin dependencias entre sí.
    – Siempre inspecciona el diff tras cada commit. El coordinador puede ejecutar hooks o pipelines ligeros antes de desbloquear tareas dependientes.
    – Si una tarea paralela falla, su rollback es local: revertir su commit o patch específico, sin tocar el trabajo válido previo.

    Requisitos previos para producción

    • CLAUDE.md actualizado en la raíz: stack, patrones prohibidos, comandos CI. Los subagentes la leerán al iniciar. (Ver ejemplo de uso de CLAUDE.md en prácticas de equipo).
    • Pipelines de CI rápidos: que verifiquen commits intermedios (lint, tests unitarios).
    • Política de revisión: define qué commits requieren revisión humana inmediata (p. ej., cambios en auth, DB).
    • Mecanismo de auditoría: etiquetas de commit que identifiquen subagente y tarea.

    Cuándo aplicar este patrón (y cuándo no)

    Úsalo cuando

    • Puedes descomponer trabajo en módulos con interfaces claras.
    • Hay paralelismo real entre módulos.
    • Necesitas trazabilidad y rollback atómico.

    No lo uses cuando

    • La tarea es totalmente secuencial o indivisible.
    • Las interfaces son ambiguas o el proyecto carece de convenciones documentadas.
    • El overhead de coordinación supera el beneficio (scripts pequeños, fixes triviales).

    Métricas que importan para medir éxito

    • Tiempo medio desde task creada hasta merge sin rework.
    • Número de reverts por milestone.
    • % de tasks que pasan CI en primer commit.
    • Latencia de integración (tiempo entre commit de dependencia y comienzo de tareas dependientes).

    Un aumento en la proporción de merges sin rework y una caída en los reverts indican que la orquestación está funcionando.

    Limitaciones honestas

    El patrón amplifica capacidad, no sustituye criterio. Si el coordinador delega mal —tareas vagas, contratos inconsistentes— obtendrás implementaciones rápidas y equivocadas. La diferencia está en quién escribe las specs: la IA ejecuta, el humano decide.

    Dominicode Labs

    Para seguir explorando patrones de orquestación y automatización aplicados a equipos mixtos humano+IA, consulta Dominicode Labs. Es una continuación lógica para pruebas de concepto y plantillas de CLAUDE.md en equipos de ingeniería.

    FAQ

    Es una estructura donde un coordinador descompone trabajo en tareas atómicas y subagentes ejecutan esas tareas, hacen commits atómicos y devuelven diffs, logs y riesgos pendientes.

    Cuando puedes descomponer trabajo en módulos con interfaces claras, hay paralelismo real y necesitas trazabilidad y capacidad de rollback atómico.

    Objetivo en 1–2 líneas, alcance (archivos permitidos), contratos (firmas/DTOs), criterios de aceptación automatizables, comando de commit esperado y límites de tiempo/recursos si procede.

    Se recomiendan pipelines rápidos que verifiquen commits intermedios con lint y tests unitarios. No se prescribe una herramienta específica en este texto.

    El rollback es local: revertir el commit o aplicar un patch específico de la tarea fallida, sin tocar el trabajo válido previo.

    Debe incluir stack, patrones prohibidos y comandos CI. Los subagentes la leerán al iniciar y sirve como referencia de equipo.

    Aumentos en merges sin rework, caída en reverts, tiempo medio hasta merge menor, alto % de tasks que pasan CI en primer commit y baja latencia de integración.

  • Cómo usar Claude Code para mejorar la productividad en desarrollo

    Cómo usar Claude Code para mejorar la productividad en desarrollo

    Como usar Claude Code como un pro

    Tiempo estimado de lectura: 4 min

    • Sesiones enfocadas: abre Claude Code en la carpeta del módulo, no en la raíz del monorepo.
    • Delega ciclos completos: pide flujos (tests → ejecutar → corregir → commit), no snippets aislados.
    • Controla contexto: evita indexar logs, binarios y secretos; limpia filtros antes de iniciar.
    • Autonomía con control: mantén confirmaciones para comandos destructivos y usa entornos efímeros para ejecuciones automáticas.

    Si quieres transformar la terminal en un entorno de ingeniería productiva, necesitas saber como usar Claude Code como un pro desde el primer comando. Claude Code no es un complemento de autocompletado: es un agente que puede leer tu repositorio, ejecutar comandos, iterar sobre fallos y aplicar cambios. Usarlo bien implica diseño de prompts, control del contexto y reglas claras de seguridad.

    Resumen rápido (lectores con prisa)

    Qué es: Un agente que puede leer repositorios, ejecutar comandos y aplicar cambios.

    Cuándo usarlo: Para flujos completos como refactorizaciones, tests y generación de PRs en entornos controlados.

    Por qué importa: Acelera tareas completas y reduce iteraciones manuales cuando se usa con límites y control de contexto.

    Cómo funciona: Indexa el directorio de sesión, ejecuta comandos permitidos y puede iterar según la salida real del sistema.

    como usar Claude Code como un pro: principios prácticos

    1) Trabaja en sesiones enfocadas (aprovecha el prompt caching)

    Claude Code indexa el directorio en el que abres la sesión. Esa indexación se cachea para reducir latencia y coste. La regla: una sesión = un microservicio o un módulo. Cambiar de contexto dentro de la misma sesión invalida la caché y dispara costes y latencia.

    Práctica: abre la CLI dentro de services/payments/, resuelve la tarea y cierra la sesión. No abras Claude Code en la raíz de un monorepo a menos que realmente necesites ver todo.

    2) Delega ciclos completos, no micro-tareas

    Un uso amateur pide snippets. Un uso profesional delega un flujo entero:

    Prompt tipo pro:
    “Refactoriza src/billing para eliminar dependencias a legacy-lib.
    Crea tests Jest que cubran el 80% de las rutas críticas.
    Ejecuta npm run test y corrige fallos hasta que la suite pase.
    Genera un changelog corto y crea un commit.”

    Resultado: código probado, commit y artefactos (tests + changelog). No más “escribe la función X”.

    3) Controla el contexto y el ruido (asegura tu entrada)

    Si la sesión indexa logs, bases SQLite locales o binarios, el modelo desperdicia tokens. Dos acciones imprescindibles:

    • Ejecuta Claude Code desde la carpeta del módulo que interesa.
    • Mantén .gitignore y filtros locales limpios; mueve o excluye archivos pesados antes de indexar.

    No inventes exclusiones mágicas: la higiene del repositorio reduce errores y mejora precisión.

    4) Define expectativas y contratos en el prompt

    Un prompt efectivo contiene: objetivo, criterios de éxito, límites y comandos permitidos. Ejemplo breve:

    • Objetivo: “Internacionalizar mensajes de error en src/errors.”
    • Criterio de éxito: “Tests de integración deben pasar y la clave i18n existir en cada error.”
    • Límite: “No modificar build/ ni archivos en vendor/.”
    • Comandos permitidos: “npm test, git add, git commit.”

    Esto evita cambios sorpresivos y deja claro qué auditar.

    Integración segura: autonomía con control

    La gran pregunta es siempre autonomía vs control. Claude Code pide confirmación antes de comandos destructivos; esa barrera debe mantenerse por defecto. Habilitar ejecución totalmente autónoma solo tiene sentido en entornos efímeros: contenedores Docker desechables o runners de CI con permisos mínimos.

    Patrón recomendado:

    • Local: Human-in-the-loop. Aprobar cambios críticos manualmente.
    • CI/CD: Sesiones automáticas dentro de contenedores con snapshot y rollback.
    • Producción: Nunca sin procesos de revisión y herramientas de observabilidad.

    Ejemplo de entorno efímero:

    docker run --rm -v $(pwd):/work -w /work node:18 bash -c "claude-code session --authed"
    (Ejecutar la CLI dentro de un contenedor permite pruebas reproducibles y segura reversión).

    Casos de uso donde Claude Code rinde como un pro

    Ejemplos claros donde aporta valor:

    • Onboarding técnico: “Lee src/ y genera un diagrama Mermaid de la arquitectura.” Resultado: documentación inicial y mapa de dependencias.
    • Refactorización transversal: “Sustituye libX por libY y ejecuta linter + tests.” Resultado: cambios aplicados + report.
    • Auditoría rápida: “Revisa el módulo de auth contra OWASP Top 10 y documenta hallazgos.” Resultado: lista priorizada de riesgos.
    • PR autopiloto: “Analiza esta rama, aplica fixes mínimos, y crea PR con descripción técnica y checklist de QA.”

    Métricas para demostrar ROI

    No es magia; mide impacto con indicadores concretos:

    • Tiempo medio para cerrar una tarea compleja (antes / después).
    • % de PRs que pasan CI en primera corrida.
    • Tiempo de onboarding de nuevos devs (documentación generada).
    • Reducción de errores por regresiones introducidas manualmente.

    Riesgos y cómo mitigarlos

    • Fugado de secretos: asegúrate de que la CLI no indexe .env con credenciales; usar vaults y secrets managers.
    • Cambios no revisados: habilita hooks que obliguen revisión humana en cambios críticos.
    • Sobredependencia: Claude Code acelera, no sustituye juicio. Mantén reglas de propiedad de código.

    Resumen rápido y acción inmediata

    Para empezar ya: instala la CLI, abre una sesión en un módulo pequeño, prueba un prompt de TDD completo (escribir tests → ejecutar → corregir) y ejecuta todo dentro de un contenedor temporal. Documenta los resultados y ajusta prompts.

    Si aprendes como usar Claude Code como un pro tendrás menos código parcheado y más flujos reproducibles. La terminal deja de ser un editor y se convierte en un orquestador: potente, pero bajo tu criterio.

    Dominicode Labs

    Si trabajas con agentes, automatización o workflows, considera continuar explorando patrones y experimentos en Dominicode Labs. Está diseñado como una continuación práctica para pruebas controladas y prototipos de integración.

    FAQ

    Respuesta: ¿Qué es Claude Code y para qué sirve?

    Claude Code es un agente que puede leer tu repositorio, ejecutar comandos, iterar sobre fallos y aplicar cambios, usado para acelerar flujos completos como refactorizaciones, tests y creación de PRs.

    Respuesta: ¿Cuándo debo abrir una sesión en la carpeta del módulo versus en la raíz?

    Abre la sesión en la carpeta del módulo cuando trabajes en una unidad cohesionada (microservicio o paquete). Evita la raíz en monorepos grandes para no invalidar caché y aumentar coste y latencia.

    Respuesta: ¿Qué debe incluir un prompt profesional?

    Debe contener objetivo, criterios de éxito, límites y comandos permitidos. Ejemplo: objetivo claro, tests necesarios, carpetas prohibidas y lista de comandos autorizados.

    Respuesta: ¿Cómo mitigo el riesgo de fugado de secretos?

    No indexes .env ni archivos con credenciales; usa vaults y secrets managers; filtra o mueve archivos sensibles antes de iniciar la sesión.

    Respuesta: ¿Es seguro habilitar ejecución autónoma en producción?

    No. Habilita ejecución autónoma solo en entornos efímeros y controlados. En producción exige revisiones humanas y observabilidad.

    Respuesta: ¿Qué métricas son útiles para medir ROI?

    Tiempo medio para cerrar tareas complejas, porcentaje de PRs que pasan CI en la primera corrida, tiempo de onboarding y reducción de errores por regresiones manuales.

    Claude Code (documentación oficial: documentación oficial) se comporta como un colaborador técnico: puede generar código, ejecutar tests y corregir errores basándose en la salida real del sistema.

  • Fundamentos del Spec-First Development para desarrolladores

    Fundamentos del Spec-First Development para desarrolladores

    Deja de vibe-codear: Fundamentos del Spec-First Development

    Tiempo estimado de lectura: 6 min

    • Spec-First invierte minutos en especificar para evitar horas de corrección posterior.
    • Sin una spec, los agentes (p. ej. Claude Code) completan huecos con suposiciones que rompen invariantes.
    • Una spec efectiva contiene contexto, contrato, restricciones y casos de uso.
    • Usa vibe coding para prototipos; usa Spec-First para producción y sistemas compartidos.

    Deja de vibe-codear: Fundamentos del Spec-First Development. Deja de vibe-codear: Fundamentos del Spec-First Development. Si confías en prompting improvisado para todo, acabarás con un sistema que “funciona” y nadie entiende. Spec-First Development no es paperwork; es el antídoto práctico contra las suposiciones que los agentes —incluido Claude Code— introducen cuando no hay una especificación clara.

    Resumen rápido (lectores con prisa)

    Spec-First Development: escribir la especificación mínima (contexto, contrato, restricciones, ejemplos) antes de implementar. Útil para producción y sistemas compartidos. Evita suposiciones de agentes y pérdida de consistencia arquitectónica. Usa vibe coding solo para prototipos.

    Fundamentos del Spec-First Development: por qué importa antes de abrir Claude Code

    Vibe coding acelera prototipos. Funciona hasta que el prototipo debe vivir en producción. Los agentes como Claude Code operan dentro de ventanas de contexto finitas; cuando esa ventana se cierra, el agente no recuerda decisiones previas y completa lagunas con suposiciones. Resultado: fragmentos correctos en aislamiento que, juntos, rompen invariantes del sistema.

    Spec-First Development cambia el orden: primero especificas el sistema mínimo necesario (contexto, contrato, restricciones, ejemplos), y luego pides al agente que implemente. Así conviertes a Claude en un ejecutor alineado, no en un improvisador.

    Fuentes útiles:

    Qué falla con el vibe coding en sistemas reales

    • Pérdida de memoria arquitectónica: cada sesión es una pizarra limpia; las decisiones previas no viajan implícitas.
    • Suposiciones silenciosas: el agente rellena huecos según heurísticas, no según tus invariantes.
    • Deuda de coherencia: el conjunto pasa tests unitarios pero falla en invariantes transversales; refactorizarlo es costoso.

    No es que los agentes sean malos. Es que sin especificaciones les pides que inventen el contexto del proyecto en cada interacción.

    Qué debe contener una spec efectiva (los 4 pilares)

    1. Contexto del sistema

    – Stack, rutas, estructura modular, patrones de estado y librerías permitidas.

    – Ejemplo: “Next.js (App Router), Zustand para estado cliente, servicios de microservicios en /services, convención kebab-case para nombres de archivo.”

    2. Contrato de la interfaz

    – Inputs (tipos), outputs (tipos), efectos secundarios permitidos, invariantes.

    – Ejemplo: “Función getUser(id: string): Promise. No realizar llamadas externas salvo a auth-service; no mutar objetos globales.”

    3. Restricciones y criterios de aceptación

    – Requisitos no funcionales: latencia, límites de dependencias, compatibilidad con versiones, criterios de seguridad.

    – Ejemplo: “Respuesta en <200ms p95; no usar librerías con licencia X; cobertura mínima 80% en pruebas unitarias.”

    4. Casos de uso y ejemplos de I/O

    – Un caso nominal, al menos un caso borde y comportamiento ante error.

    – Ejemplo: entrada JSON, salida esperada, salida esperada cuando falta un campo.

    Estos cuatro pilares evitan que el agente “sea creativo” donde no debe.

    Cómo integrar specs en tu flujo con Claude Code (pasos prácticos)

    1. Escribe la spec antes de abrir la sesión del agente

    – No la guardes en Google Docs. Ponla en el repo: SPEC.md junto al test file o como comentario estructurado en tests.

    2. Incluye la spec textual como primer contexto en el prompt

    – No resumas: copia y pega. El agente necesita reglas explícitas, no interpretaciones.

    3. Pide la implementación y las pruebas asociadas

    – Solicita código + tests unitarios que verifiquen los criterios de aceptación.

    4. Valida resultado contra la spec antes de mergear

    – Verde en CI no equivale a alineación arquitectónica. Comprueba invariantes, latencias, dependencias y contratos.

    5. Versiona la spec junto al código

    – Si cambian los requisitos, actualiza SPEC.md; la spec es parte del contrato del repo.

    Ejemplo mínimo de SPEC.md (esquema)

    • – Contexto: [stack, rutas, convenciones]
    • – Contrato: [firma, tipos, efectos secundarios permitidos]
    • – Restricciones: [latencia, dependencias, seguridad]
    • – Casos: [input nominal → output; caso borde; error esperado]
    • – Criterios de aceptación: [tests, performance, compatibilidad]

    Guardarlo en el repo reduce el ciclo “pregunta-respuesta” y elimina ambigüedades en prompts posteriores.

    Cuándo usar vibe coding y cuándo spec-first

    Vibe coding: validación rápida de concepto, experimentación aislada, exploración de bibliotecas.

    Spec-First: producción, microservicios compartidos, sistemas con múltiples mantenedores, integraciones críticas.

    No es blanco o negro: usa vibe para idear, spec-first para construir. Esa transición mental es la diferencia entre velocidad aparente y velocidad sostenible.

    Cierre: el coste real de no especificar

    Un agente sin spec es un colaborador talentoso sin briefing: produce soluciones plausibles que resuelven problemas distintos al que tienes. Escribir specs no es burocracia; es invertir minutos que ahorran horas de corrección y semanas de deuda técnica. Antes de abrir Claude Code, escribe la spec. Tu base de código te lo agradecerá.

    Para equipos que trabajan con automatización, agentes y workflows, una práctica complementaria es centralizar plantillas y ejemplos en un laboratorio interno. Más recursos y experimentos aplicados están disponibles en Dominicode Labs.

    FAQ

    Respuesta:

    Spec-First Development es la práctica de definir la especificación mínima necesaria (contexto, contrato, restricciones, ejemplos) antes de implementar el sistema o función.

    Respuesta:

    Antes de comenzar una tarea que vaya a producción, que implique integración entre equipos o que afecte invariantes transversales. Para prototipos rápidos puedes saltarla.

    Respuesta:

    La spec es un contrato operativo y minimalista pensado para ejecución y validación (tests, CI), no un documento extenso de diseño. Está orientada a la implementabilidad.

    Respuesta:

    Sí. Los agentes consumen la spec como contexto explícito y la usan para reducir suposiciones. Es crucial pegar la spec textual en el prompt o ponerla en el repo accesible.

    Respuesta:

    Contexto del sistema, contrato de la interfaz, restricciones y criterios de aceptación, y casos de uso con ejemplos de I/O.

    Respuesta:

    Se pierde trazabilidad entre versiones del código y sus requisitos; provoca divergencias, errores en integración y mayor deuda técnica. Versionar la spec junto al código evita ambigüedades.

  • Cómo usar httpResource() en Angular para manejar peticiones HTTP

    Cómo usar httpResource() en Angular para manejar peticiones HTTP

    httpResource() — Resource API para HTTP: Peticiones Reactivas con Signals

    ¿Te imaginas definir una petición HTTP como si fuera una variable y olvidarte de orquestar cancelaciones, estados y subscriptions? Eso es lo que propone httpResource() — Resource API para HTTP: defines los parámetros como señales y el recurso se actualiza solo cuando cambian las señales dependientes.

    Tiempo estimado de lectura: 3 min

    • Convierte llamadas de red en estado reactivo accesible desde Signals.
    • Automatiza cancelaciones y recargas cuando las señales dependientes cambian.
    • Reduce boilerplate respecto al patrón Observable + suscripción para patrones “estado → petición”.
    • No reemplaza a RxJS para orquestaciones temporales o streams continuos.

    Introducción

    httpResource() convierte llamadas de red en estado reactivo. Si trabajas con Angular y Signals, esto no es una mejora cosmética: es una forma distinta de pensar la carga de datos. En lugar de construir Observables, suscribirte y gestionar cancelaciones manuales, consumes estado.

    Resumen rápido (lectores con prisa)

    Definición: httpResource() expone peticiones HTTP como señales reactivas que actualizan automáticamente su estado al cambiar dependencias.

    Cuándo usarlo: Para cargas impulsadas por estado (filtros, rutas, paginación).

    Por qué importa: Simplifica cancelaciones automáticas, estados y recargas sin boilerplate.

    Limitación clave: No sustituye a RxJS para orquestación temporal o streams continuos.

    httpResource() — Resource API para HTTP: qué es y por qué importa

    La Resource API expone operaciones asíncronas como señales. httpResource() es la implementación para peticiones HTTP: envuelve la llamada y te devuelve señales listas para consumir (value, loading, error, status y un método reload).

    Angular documenta el enfoque reactividad en su guía oficial (ver Reactive primitives). El HttpClient sigue siendo el motor de la petición; httpResource() es la interfaz que lo conecta con Signals.

    Actualmente la API está en Developer Preview en las versiones recientes, por lo que conviene probar con criterio en proyectos que puedan tolerar cambios en la firma antes de que se estabilice.

    Cómo funciona, sin demasiada magia

    Piensa en httpResource() como un computed() que hace fetch. Definís una función que lee señales. Angular registra dependencias. Cuando cualquiera cambia:

    • la petición anterior se aborta si aún está en curso,
    • se lanza una nueva petición con los parámetros actualizados,
    • las señales (value, isLoading, error, status) reflejan el ciclo de vida automáticamente.

    Ejemplo mínimo

    readonly userId = signal(1);
    
    readonly userResource = httpResource(() => ({
      url: `/api/users/${this.userId()}`,
      method: 'GET'
    }));

    Cambia userId() y el recurso hace el resto. No hay switchMap, no hay takeUntil, no hay memoria de suscripciones.

    Qué recibes “de serie” y por qué eso importa

    Al usar httpResource() obtienes señales listas para consumir en la plantilla o en lógica reactiva:

    • .value() — datos resueltos.
    • .isLoading() — booleano para spinners/skeletons.
    • .error() — información del fallo.
    • .status()idle | loading | resolved | error.
    • .reload() — fuerza una re-ejecución.

    Esto elimina mucho boilerplate: ya no necesitas declarar isLoading, data, error y actualizar cada uno en handlers separados.

    Race conditions: ya no es una preocupación recurrente

    Las condiciones de carrera eran el talón de Aquiles cuando el usuario cambiaba filtros rápido y una respuesta tardía pisaba datos nuevos. Con httpResource() la cancelación es automática: si la señal que define la petición cambia, las peticiones intermedias se abortan. Resultado: datos consistentes y menos código defensivo.

    Eso no significa que el problema desaparezca en todos los contextos, pero sí que desaparece en el patrón más común: “estado cambia → cargar datos para la vista”.

    Cuándo usarlo — y cuándo no

    Usos recomendados

    • La obtención de datos está impulsada por estado (filtros, ruta, paginación).
    • Quieres minimizar boilerplate y unificar el modelo mental del equipo en Signals.
    • Buscas evitar errores por manejo manual de cancelaciones.

    Cuándo no usarlo

    • Necesitas orquestación compleja de eventos (WebSockets, SSE, streams continuos).
    • Requieres transformaciones temporales avanzadas (debounceTime, windowing, combinaciones complejas).
    • Estás construyendo pipelines de datos que dependen del tiempo y eventos más que del estado.

    RxJS sigue siendo la herramienta correcta para flujos de eventos; httpResource() es la herramienta correcta para “estado → petición” limpio y declarativo.

    Impacto arquitectónico real

    El cambio más importante no es técnico: es mental. Cuando el equipo compra la narrativa Signals-first, los componentes y su testing se vuelven más simples. Menos suscripciones olvidadas. Menos efectos colaterales. Mejor onboarding para quien llega nuevo al repo.

    No es magia: es coherencia. httpResource() reduce superficie para errores y acelera decisiones arquitectónicas sobre dónde debe vivir la lógica de carga de datos.

    Recursos y siguientes pasos

    Angular Reactivity Guide

    HttpClient (persistencia del motor)

    Si estás en Angular 19+ y ya trabajas con Signals, empieza por prototipar una pantalla con httpResource() y compara la legibilidad, tests y bugs con la versión RxJS/HttpClient. No lo adoptes por moda: mídelo. Y si en el prototipo funciona, lo siguiente es reescribir un flujo real y ver cuántas líneas de código desaparecen.

    Esto no acaba aquí: hay decisiones de testing, caching y error handling que merecen otra pieza. Si querés, escribo la segunda parte con patrones de testing y estrategias de cache para httpResource().

    FAQ

    ¿Qué es exactamente httpResource()?

    Es una implementación de la Resource API para peticiones HTTP que expone el resultado y el estado de la petición como señales reactivas. Envuelve el mecanismo del HttpClient y ofrece .value(), .isLoading(), .error(), .status() y .reload().

    ¿Cómo se integra con HttpClient?

    El HttpClient sigue siendo el motor que efectúa las peticiones. httpResource() actúa como la interfaz declarativa que lee señales y delega la ejecución y cancelación al HttpClient.

    ¿Qué señales ofrece por defecto?

    Provee .value() (datos), .isLoading() (booleano), .error() (detalle del fallo), .status() (idle | loading | resolved | error) y .reload().

    ¿El API cancela peticiones automáticamente?

    Sí. Si la señal que define la petición cambia mientras una petición está en curso, la petición anterior se aborta automáticamente para evitar condiciones de carrera comunes.

    ¿Cuándo debo seguir usando RxJS?

    Cuando necesitas orquestación compleja de eventos, streams continuos (WebSockets, SSE) o transformaciones temporales avanzadas (debounceTime, windowing, combinaciones complejas), RxJS sigue siendo la herramienta adecuada.

    ¿Es estable la API en producción?

    La API estaba en Developer Preview en versiones recientes; conviene probar con criterio en proyectos que puedan tolerar cambios en la firma antes de adoptarla ampliamente en producción.