Author: Dominicode

  • Implementa Spec-First y TDD para asegurar código con Claude Code

    Implementa Spec-First y TDD para asegurar código con Claude Code

    Spec-First + TDD: el combo que hace que Claude Code no rompa nada

    Tiempo estimado de lectura: 4 min

    • Spec-First transforma requisitos en contratos ejecutables que eliminan ambigüedades.
    • TDD convierte esos contratos en tests que fallan primero (Red) y obligan a implementar hasta pasar (Green).
    • El flujo reduce suposiciones del agente, evita happy-paths y deuda técnica silenciosa.
    • Requiere versionar specs y tests junto a la implementación para trazabilidad y control.

    Spec-First + TDD: el combo que hace que Claude Code no rompa nada. Díselo a cualquier equipo que delega implementaciones críticas a un agente y observarás tres problemas: suposiciones, happy-paths y deuda técnica que aparece en silencio. Este patrón invierte el orden habitual: especificación primero, tests que fallan después, implementación solo para pasar tests. Resultado: la IA implementa contra contratos ejecutables, no contra intuiciones.

    Resumen rápido (lectores con prisa)

    Spec-First convierte requisitos en contratos ejecutables. TDD transforma esos contratos en tests rojos que deben pasar. El agente implementa únicamente para lograr que pnpm test devuelva exit code 0. Menos ambigüedad, más trazabilidad, menos regresiones.

    Spec-First + TDD: qué es y por qué lo necesitas con Claude Code

    Claude Code y otros agentes son excelentes generadores de código, pero su entrenamiento los empuja a soluciones “plausibles”, no necesariamente correctas para tu dominio. La solución no es prompts más largos; es cambiar el flujo de trabajo.

    Spec-First + TDD combina:

    • Spec-First: transformar requisitos en un contrato preciso y ejecutable (feature-spec.md).
    • TDD: traducir ese contrato a tests que inicialmente fallan (Red).
    • Implementación: conceder al agente la tarea de alcanzar el verde (Green) ejecutando y corrigiendo hasta que pnpm test devuelva exit code 0.

    Links útiles: Claude Code docs y Vitest para ejemplos de runners.

    Flujo operativo paso a paso

    1) Escribir la especificación (Spec)

    La especificación no es un texto largo: es un contrato. Define funciones, inputs, outputs, errores y reglas inmutables.

    Ejemplo (feature-spec.md):

    Feature: applyDiscount(order, coupon)
    
    Función: applyDiscount(order, coupon)
    Inputs:
    - order: { id, subtotal, userId, items[] }
    - coupon: { code, type: 'percentage'|'fixed', value, minOrder, expiresAt }
    
    Reglas:
    - Si coupon.expiresAt < now -> DiscountExpiredError
    - Si order.subtotal < coupon.minOrder -> OrderBelowMinimumError
    - total = max(0, subtotal - discount)
    

    Si necesitas respuesta HTTP o formatos JSON exactos, escríbelos. Nada queda implícito.

    2) Generar esqueletos de tests que fallen (Red)

    Pide a Claude que genere solo los tests: archivos Vitest/Jest que describan las aserciones exactas. Estos tests deben fallar inicialmente porque la implementación aún no existe.

    Ejemplo breve (applyDiscount.test.ts):

    import { applyDiscount } from './applyDiscount'
    import { DiscountExpiredError } from './errors'
    
    it('lanza DiscountExpiredError si el cupón expiró', () => {
      expect(() => applyDiscount(orderExpired, couponExpired)).toThrow(DiscountExpiredError)
    })
    

    Ejecuta pnpm test localmente o desde el agente. Verás rojo: eso es correcto. Tienes un contrato ejecutable.

    3) Implementación: el agente repara hasta verde

    Autoriza a Claude a escribir el código con una instrucción clara:

    “Implementa applyDiscount() conforme a feature-spec.md. Ejecuta pnpm test y corrige hasta que todos los tests pasen. No modifiques los tests.”

    El agente iterará: escribir, ejecutar, leer errores, corregir. Termina cuando el runner devuelve 0. Esa condición objetiva sustituye la “autovalidación” del modelo.

    Beneficios reales y medibles

    • Trazabilidad: cada cambio está ligado a un test derivado de una especificación humana.
    • Determinismo: el criterio de finalización es el estado del test runner, no el juicio subjetivo del agente.
    • Menos regresiones: CI bloqueará commits que rompan contratos; el agente ya trabaja para pasar esa barrera.
    • Refactor seguro: optimizar sin romper es posible porque la suite revisa invariantes.

    Métricas a monitorear: porcentaje de PRs que pasan en la primera ejecución de CI, número de reverts por errores de negocio, tiempo medio para retomar trabajo en sesiones de agente.

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

    Aplica Spec-First + TDD cuando:

    • La lógica tiene invariantes críticas: facturación, pagos, permisos.
    • La feature afecta múltiples consumidores del API.
    • Vas a delegar implementación a sesiones autónomas del agente.

    No lo uses para:

    • Prototipos visuales donde la iteración UX prima.
    • Scripts puntuales o migraciones one-off.
    • Cambios triviales donde crear tests cuesta más que la implementación.

    Buenas prácticas y guardrails

    • Versiona feature-spec.md junto con la PR que implementa la feature.
    • No permitas que el agente modifique tests sin revisión humana.
    • Mantén artefactos pequeños: especificaciones por feature, no documentos gigantes.
    • Incluye en CLAUDE.md la referencia a specs y al contrato de proyecto para que Claude cargue el contexto inicial: esto reduce fricción y errores de interpretación (ver docs).

    Spec-First + TDD no es un ritual: es control. Si quieres que Claude Code deje de ser creativo y empiece a ser fiable, escribe contratos ejecutables primero, exige tests rojos y permite que la IA solo implemente para pasar tests. El resultado no es menos velocidad: es menos correcciones, menos deuda y más confianza en el código que llega a producción.

    Dominicode Labs

    Para equipos que automatizan con agentes y workflows, un laboratorio de pruebas y plantillas de specs acelera la adopción. Consulta Dominicode Labs como continuación lógica para crear artefactos y plantillas reutilizables.

    FAQ

    Respuesta: Spec-First es un contrato ejecutable que define funciones, inputs, outputs y errores de forma precisa. La documentación normal puede ser descriptiva; la spec exige reglas inmutables y formatos exactos que pueden traducirse a tests automatizados.

    Respuesta: Forzar tests rojos crea un criterio objetivo: la implementación debe satisfacer el contrato verificable. Evita que el agente implemente “por intuición” y asegura que el código cumpla casos límites y errores definidos.

    Respuesta: Usa runners como Vitest o Jest para ejecutar tests. Ejecuta pnpm test en CI y localmente para validar que el agente alcanzó exit code 0.

    Respuesta: Políticas de revisión de PR que bloqueen merges si los tests cambian sin aprobación humana y reglas de CI que rechacen cambios en archivos de tests son medidas efectivas. Además, incluye en el proceso de aceptación la verificación de artefactos versionados.

    Respuesta: Hay una inversión inicial: escribir specs y tests. Esa sobrecarga se compensa con menos rework, menos regresiones y mayor velocidad a largo plazo cuando los agentes trabajan contra contratos claros.

    Respuesta: Métricas recomendadas: porcentaje de PRs que pasan en la primera ejecución de CI, número de reverts por errores de negocio y tiempo medio para retomar trabajo en sesiones de agente.

  • Implementación de Steering Documents para Claude Code

    Implementación de Steering Documents para Claude Code

    Steering documents: enseña a Claude tu arquitectura de una vez

    Tiempo estimado de lectura: 5 min

    • Convierte la memoria del agente en infra versionada: usa product.md, tech.md y structure.md.
    • Son contratos operativos: Claude Code los carga al arrancar y los respeta como reglas.
    • Manténlos concisos y gobernados: actualízalos como parte de la PR y asigna propietarios.

    Steering documents: enseña a Claude tu arquitectura de una vez —esa es la diferencia entre repetir contexto cada sesión y tener un agente que ya entiende tu producto, tu stack y tus límites. Si usas Claude Code en proyectos reales, necesitas tres documentos permanentes en el repo: product.md, tech.md y structure.md. Con ellos conviertes la memoria del agente en infra versionada, no en promesas inútiles de prompt.

    Resumen rápido (lectores con prisa)

    Steering documents son archivos Markdown versionados que Claude Code carga al iniciar. Son contratos operativos: product.md define dominio y reglas inmutables; tech.md define stack y prohibiciones; structure.md define mapa y reglas de dependencia. Actualízalos con la PR que cambia el dominio o stack.

    Steering documents: qué son y cómo los usa Claude Code

    Un steering document es un Markdown versionado que Claude Code lee al arrancar una sesión. No es mera documentación: es el contrato operativo que la IA debe respetar. La doc raíz CLAUDE.md debe referenciarlos para que Claude los cargue automáticamente (ver docs de Claude Code y Claude (Anthropic)).

    ¿Por qué preocuparnos? Sin estos archivos el agente:

    • Asume patrones genéricos y propone librerías no deseadas.
    • Introduce convenciones inconsistentes (nombres, capas).
    • Toma decisiones de negocio que rompen reglas críticas.

    Con steering documents, el agente aplica las mismas restricciones y expectativas que un ingeniero senior al entrar al repositorio.

    Los tres steering documents esenciales

    A continuación, la estructura práctica y mínima para cada archivo. Copia, adapta y versiona.

    product.md — contexto de negocio (qué y para quién)

    Debe explicar el dominio y las reglas que NUNCA se rompen.

    Ejemplo mínimo:

    ## Propósito
    Sistema B2B para facturación y gestión de suscripciones.
    
    ## Usuarios
    Admin (gestiona planes), Cliente (visualiza facturas), Billing Ops.
    
    ## Conceptos de dominio
    - Factura: documento inmutable que refleja obligación de pago.
    - Suscripción: contrato con ciclo y estado (active, trial, cancelled).
    
    ## Reglas inmutables
    - Una factura con estado "paid" no puede mutarse.
    - Cambios de plan aplican solo desde el próximo ciclo de facturación.

    Product.md evita que Claude implemente validaciones técnicamente correctas pero comercialmente inválidas.

    tech.md — contrato técnico (qué usar y qué evitar)

    Enumera stack, patrones aprobados, patrones prohibidos y comandos de validación.

    Ejemplo mínimo:

    ## Stack aprobado
    - Frontend: Next.js 14 (App Router), TypeScript
    - Backend: Node + Fastify
    - DB: PostgreSQL + Drizzle
    
    ## Patrones aprobados
    - Feature-based folders
    - Estado: Zustand
    - Validaciones: Zod
    
    ## Prohibiciones
    - No usar `any` en TS
    - No añadir dependencias sin RFC y PR

    Incluye comandos que Claude puede ejecutar para validar cambios: pnpm test, pnpm lint, pnpm build.

    structure.md — mapa del repositorio y reglas de dependencia

    Describe la topología y las reglas de importación.

    Ejemplo mínimo:

    ## Árbol principal
    src/
    ├─ app/
    ├─ features/
    ├─ shared/
    └─ lib/
    
    ## Reglas de dependencia
    - features -> shared|lib
    - shared !-> features
    - lib !-> features|shared

    Structure.md previene importaciones cruzadas, acoples y mal colocación de código.

    Cómo integrarlos en CLAUDE.md y en el flujo de trabajo

    Incluye estas líneas al inicio de CLAUDE.md:

    Lee antes de cualquier tarea:
    - @product.md
    - @tech.md
    - @structure.md

    Eso obliga a Claude Code a tratarlos como memoria base. Además, convierte a estos archivos en el primer artefacto que se consulta en cada sesión, reduciendo la necesidad de prompts largos.

    Reglas operativas prácticas:

    • Actualiza steering docs como parte de la PR que introduce el cambio (no después).
    • Cada PR que modifica stack o dominio debe incluir cambios en tech.md o product.md.
    • Los commits deben referenciar el documento afectado: e.g., tech: add pgvector to approved libs.

    Mantenimiento y gobernanza

    Los steering documents son infra; trátalos como tal:

    • Mantén un owner (Staff/Tech Lead) responsable de aprobar cambios.
    • Usa PR con plantilla: “¿Este cambio requiere actualizar product/tech/structure?”.
    • Revisión obligatoria para cambios que rompan reglas prohibidas.

    Medir impacto:

    • % de PRs que violan tech.md (debe bajar).
    • Tiempo medio para onboarding de IA (leer docs vs. explicar manualmente).
    • Reverts causados por decisiones del agente (debe descender).

    Límite y advertencia práctica

    No conviertas estos archivos en una lista viva de todo el código. Son contratos, no specs línea por línea. Manténlos concisos, explícitos y estables. Si permites que entren cambios experimentales sin governance, el agente aplicará reglas obsoletas y causará más fricción que ahorro.

    Implementar steering documents: enseña a Claude tu arquitectura de una vez

    Implementar steering documents: enseña a Claude tu arquitectura de una vez. Es trabajo de equipo al principio; ahorro de tiempo y coherencia técnica permanente después. Si quieres que la IA actúe como ingeniero efectivo, no le des hints: dale el contrato.

    Para equipos que automatizan workflows, integran agentes o aplican IA en procesos de ingeniería, también puede ser útil revisar recursos prácticos y experimentales en Dominicode Labs. Esa referencia complementa estrategias de gobernanza y pruebas para agentes en repositorios reales.

    FAQ

    ¿Qué es un steering document?

    Un steering document es un archivo Markdown versionado que Claude Code lee al arrancar. Funciona como un contrato operativo que la IA debe respetar.

    ¿Por qué necesito product.md, tech.md y structure.md?

    Porque juntos convierten la memoria del agente en infra versionada: product.md define el dominio y reglas inmutables; tech.md define stack y prohibiciones; structure.md define topología y reglas de dependencia.

    ¿Cómo se cargan estos archivos en Claude Code?

    La doc raíz CLAUDE.md debe referenciarlos para que Claude los cargue automáticamente al arrancar una sesión. Incluye al inicio: Lee antes de cualquier tarea: – @product.md – @tech.md – @structure.md.

    ¿Qué poner en tech.md?

    Enumera stack aprobado, patrones aprobados, prohibiciones y comandos de validación (por ejemplo: pnpm test, pnpm lint, pnpm build).

    ¿Cómo gestiono cambios en estos documentos?

    Actualízalos como parte de la PR que introduce el cambio y asigna un owner responsable de aprobar actualizaciones. Usa plantillas de PR que pregunten si los steering docs requieren cambios.

    ¿Pueden ser demasiado detallados?

    No. Deben ser concisos y estables. Evita convertirlos en una lista viva de todo el código; son contratos, no especificaciones línea por línea.

    ¿Qué pasa si el agente viola una regla?

    Si el agente toma decisiones que violan las reglas, revisa y refuerza los steering docs y la gobernanza: owner, PRs obligatorias y métricas de impacto (PRs que violan tech.md, reverts, tiempo de onboarding).

  • Cómo utilizar tipos condicionales en TypeScript para mejorar la robustez

    Cómo utilizar tipos condicionales en TypeScript para mejorar la robustez

    ¿Quieres que tus tipos de TypeScript hagan el trabajo sucio por ti —y de verdad— en vez de darte una falsa sensación de seguridad?

    Tiempo estimado de lectura: 4 min

    • Los tipos condicionales (T extends U ? X : Y) se evalúan en tiempo de compilación y permiten metaprogramación robusta.
    • infer captura partes de tipos para extraer retornos, parámetros y elementos internos sin runtime.
    • Patrones clave: Unwrap para Promises, evitar distribución con tuplas, manipular tuples con Head/Tail, y extraer retornos async.
    • Precauciones: complejidad excesiva, deuda técnica y necesidad de validación runtime para datos externos.

    Bien. Aquí tienes una guía práctica que no promete magia, pero sí te salva de la gimnasia de tipos inútil y de bugs que aparecen a las 2AM.

    Resumen rápido (lectores con prisa)

    Los condicionales de tipos son ternarios que TypeScript evalúa en tiempo de compilación. infer permite extraer partes de un tipo coincidente. Úsalos para utilidades tipo-level (Unwrap, AsyncReturn, Head/Tail) y evita su abuso: documenta, limita y combina con validación runtime cuando el input viene de la red.

    Introducción

    Primero, lo obvio: el condicional de tipos es un ternario que vive en el compilador. Sintaxis: T extends U ? X : Y. Se evalúa en tiempo de compilación. No en runtime. Eso lo convierte en una espada afilada: poderosa, pero cortante.

    Condicionales de tipos

    Sintaxis

    Sintaxis: T extends U ? X : Y. Se evalúa en tiempo de compilación.

    Ejemplo mínimo

    type IsString<T> = T extends string ? true : false;
    type A = IsString<'hola'>; // true
    type B = IsString<42>;     // false
    

    Sencillo. Útil para construir utilidades.

    infer

    Qué es

    infer captura piezas del tipo que estás inspeccionando. Es la manera de decirle a TS: “si esto encaja, arráncame esto otro”.

    Ejemplo clásico — extraer el tipo de retorno

    type MyReturn<T> = T extends (...args: any[]) => infer R ? R : never;
    type Fn = () => { id: number };
    type R = MyReturn<Fn>; // { id: number }
    

    Útil. Limpio. Poderoso.

    Patrones

    Patrón 1 — Unwrap de Promises (recursivo)

    Cuando trabajas con APIs, las promesas anidadas son una plaga. Esto te limpia el resultado:

    type Unwrap<T> = T extends Promise<infer U> ? Unwrap<U> : T;
    type X = Unwrap<Promise<Promise<{ ok: true }>>>; // { ok: true }
    

    Patrón 2 — Tipos distributivos y el problema que nadie lee

    Si T es una unión, el condicional se aplica a cada miembro (distribuye). A veces quieres eso. A veces no.

    Distribución:

    type ExcludeFunc<T> = T extends Function ? never : T;
    type U = ExcludeFunc<string | (() => void)>; // string
    

    Evitar distribución

    Envuélvelo en una tupla.

    type NoDist<T> = [T] extends [Function] ? never : T;
    

    Memorízalo. Te salvará de errores raros.

    Patrón 3 — Extraer elementos de tuples/arrays

    infer también domina tuplas. Necesitas sacar head/tail o el último elemento:

    type Head<T extends any[]> = T extends [infer H, ...any[]] ? H : never;
    type Tail<T extends any[]> = T extends [any, ...infer R] ? R : never;
    

    Esto abre puertas para manipulaciones tipo-level sin hacer trampas.

    Patrón 4 — AsyncReturnType para funciones async

    type AsyncReturn<T> = T extends (...args: any[]) => Promise<infer R> ? R : never;
    

    Ideal para tipos de efectos y sagas.

    Casos reales donde esto brilla

    • Clientes HTTP tipados por endpoint (súper seguro, sin as adivinatorio).
    • Librerías que exponen utilidades genéricas robustas.
    • Metaprogramación de APIs internas (mapea rutas a tipos de response).
    • Sistemas de validación y mapeo que dependen de signatures de funciones.

    Ejemplo rápido: tipos por endpoint

    interface Endpoints {
      '/users': { id: string, name: string }[];
      '/status': { ok: boolean };
    }
    
    function fetchApi<T extends keyof Endpoints>(url: T): Promise<Endpoints[T]> {
      return fetch(url).then(r => r.json());
    }
    

    No más any. No más guessing.

    Pitfalls — Lo que te rompe la vida si no tienes cuidado

    • Complexity blowup: tipos gigantes ralentizan el compilador. TS puede confundirse y tirar errores crípticos.
    • Abuso: si tu equipo no entiende, se convierte en deuda técnica invisible.
    • Debug hard: errores en tipos a veces son opacos; documenta y divide tipos largos.
    • Runtime vs compile-time: los tipos no validan data externa. Para eso, runtime schemas (Zod) son tus amigos.

    Buenas prácticas — rápido y aplicable

    • Usa tipos condicionales en librerías y núcleos infra. No en cada componente.
    • Nombra aliases: type AsyncReturn<T> = ... — no pongas 10 ternarios directos.
    • Comenta. Sí, los tipos necesitan comentarios.
    • Mantén límites: si un tipo tiene más de 30–40 líneas, replantea.
    • Combina con validación runtime donde el input viene de la red.
    • Testea tipos con tsd o expect-type para evitar regresiones.

    Trucos avanzados en dos líneas

    • Forzar no-distribución: [T] extends [U] ? X : Y.
    • Obtener parámetros de una función: type Params<T> = T extends (...a: infer A) => any ? A : never;
    • Extraer propiedades no-función: usa mapped types con condicionales para filtrar claves.

    Metáfora rápida para que no lo olvides

    Los tipos condicionales son el sistema inmunitario del código. Te protegen si los pones en el lugar correcto. Si los usas por todos lados sin control, te provocan una reacción autoinmune: complejidad que te derriba.

    ¿Quieres algo práctico que puedas pegar ya?

    Puedo mandarte:

    • Un cheat-sheet con 25 utilidades (Unwrap, AsyncReturn, Head, Tail, PickByValue, etc.).
    • Un pequeño repo con ejemplos y tests de tsd.
    • Un snippet para un cliente HTTP tipado por endpoints + validación Zod integrada.

    Responde “Envíame el cheat-sheet” y te lo paso listo para copiar. No es teoría. Es la diferencia entre escribir tipos y dejar que los tipos te salven. Esto no acaba aquí.

    FAQ

    ¿Qué es un condicional de tipos en TypeScript?

    Es una expresión tipo-level con la forma T extends U ? X : Y que el compilador evalúa en tiempo de compilación para producir un tipo según la condición.

    ¿Qué hace infer?

    infer permite capturar una parte del tipo que coincide en un condicional, por ejemplo para extraer el tipo de retorno de una función o el inner type de una Promise.

    ¿Cómo evito que un condicional distribuya sobre una unión?

    Envuelve el tipo en una tupla: [T] extends [U] ? X : Y. Eso evita la distribución sobre cada miembro de la unión.

    ¿Los tipos garantizan que los datos externos sean válidos?

    No. Los tipos existen en tiempo de compilación. Para datos externos debes usar validación runtime (por ejemplo Zod) y combinarla con tipos TypeScript.

    ¿Cuándo debo usar estos patrones vs validación runtime?

    Usa tipos condicionales y infer para modeling y seguridad interna del código. Añade validación runtime cuando aceptas datos de la red o de usuarios.

    ¿Qué herramientas recomiendas para testear tipos?

    Testea tipos con frameworks como tsd o utilidades como expect-type para evitar regresiones en tipos complejos.

  • Soluciones efectivas para props drilling en React

    Soluciones efectivas para props drilling en React

    ¿Qué es el props drilling en React? Guía de arquitectura y soluciones

    Tiempo estimado de lectura: 4 min

    • Props drilling es pasar props a través de varios niveles que no las usan.
    • Opciones: composición, Context API o stores externos según alcance y frecuencia de cambio.
    • Decisión técnica: privilegia composición; Context para valores estables; store para coordinación entre subsistemas.

    Resumen rápido (lectores con prisa)

    Props drilling: pasar datos por componentes intermedios que no los usan. Si atraviesa pocos niveles (<3) suele estar bien; si escala, considerar composición, Context o un store externo. Elige según alcance, frecuencia de cambio y acoplamiento.

    ¿Qué es el props drilling en React?

    El props drilling en React es cuando pasas propiedades a través de múltiples niveles de componentes que no las usan, solo las retransmiten hasta el componente que sí las necesita.

    Ejemplo visual:

    App (tiene user)
    └─ Layout
    └─ Sidebar
    └─ Menu
    └─ UserProfile (usa user)

    Código mínimo:

    function App() {
      const user = { name: "Ana", avatar: "/ana.jpg" };
      return <Layout user={user} />;
    }
    
    function Layout({ user }) { return <Sidebar user={user} />; }
    function Sidebar({ user }) { return <UserProfile user={user} />; }
    function UserProfile({ user }) { return <img src={user.avatar} alt={user.name} />; }

    Layout y Sidebar no necesitan user. Solo lo llevan. Eso genera acoplamiento y ruido en el código.

    ¿Cuándo es un problema real?

    No todo props que viaja es pecado. Pasar props uno o dos niveles es totalmente aceptable. El problema aparece cuando:

    • La propiedad atraviesa tres o más niveles.
    • Múltiples props no relacionadas llenan la firma de componentes intermedios.
    • Mover un componente exige recablear docenas de firmas.
    • Los re-renders se disparan y el rendimiento cae.

    Consecuencias prácticas: acoplamiento innecesario, refactors costosos, más tests y mayor probabilidad de bugs al cambiar la forma del dato.

    Soluciones (con criterio técnico)

    No hay varita mágica. Hay herramientas y criterios para escoger la correcta.

    1) Composición de componentes (cuando aplica)

    Primera regla: intenta composición antes que librerías. Si el componente final vive en un subárbol que puedes construir desde el padre que tiene el dato, inyecta el subárbol.

    function App() {
      const user = { name: "Ana", avatar: "/ana.jpg" };
      return (
        <Layout sidebar=&{``} />
      );
    }

    Ventaja: cero dependencias, cero props intermedios. Referencia: docs de React sobre composición

    Cuándo usar: datos locales a una sección, poco compartidos fuera del subárbol.

    2) Context API (cuando el dato es global y estable)

    Context te permite proveer un valor desde arriba y consumirlo en cualquier punto del árbol, sin pasar props intermedios.

    const UserContext = React.createContext(null);
    
    function App() {
      const user = { name: "Ana" };
      return <UserContext.Provider value={user}><Layout /></UserContext.Provider>;
    }
    
    function UserProfile() {
      const user = useContext(UserContext);
      return <span>{user.name}</span>;
    }

    Docs oficiales: React Context

    Advertencia: Context es ideal para valores que cambian poco (tema, idioma, sesión). Si el valor cambia con alta frecuencia, todos los consumidores se re-renderizan y el rendimiento puede sufrir.

    3) Estado global / stores (cuando la app escala)

    Cuando múltiples partes desconectadas del árbol necesitan leer y escribir el mismo estado, un store fuera del árbol es la opción práctica.

    Opciones razonables hoy:

    • Zustand: simple, sin boilerplate, buen rendimiento.
    • Redux Toolkit: trazabilidad y patterns para apps enterprise.
    • Jotai/Recoil: atom-based state para control fino de re-renders.

    No uses un store global por moda. Úsalo cuando la composición y Context se queden cortos.

    Cómo decidir (lista rápida)

    Hazte estas preguntas antes de refactorizar:

    1. ¿Cuántos niveles atraviesa la prop? (<3 → probablemente ok)
    2. ¿Los componentes intermedios la usan? (si sí, deja el flujo)
    3. ¿El dato cambia con frecuencia? (si sí, evita Context)
    4. ¿Se comparte entre partes no relacionadas de la UI? (si sí, considera un store)

    Si la respuesta apunta a complejidad real, planifica: migración por fases, pruebas y medición de re-renders.

    Buenas prácticas finales

    • Mantén el estado lo más cerca posible del lugar donde se usa.
    • Prefiere composición cuando sea viable.
    • Usa Context para datos estables.
    • Reserva stores externos para coordinación entre subsistemas.
    • Evita micro-optimizaciones prematuras: primero estructura, luego perf.

    Referencias útiles

    Esto no acaba aquí: en el siguiente post veremos cómo migrar un árbol con props drilling a Zustand paso a paso, sin romper la app ni a los desarrolladores. Suscríbete al boletín de Dominicode para recibir la guía y los snippets listos para copiar.

    FAQ

    ¿Qué es exactamente el props drilling?

    Es el patrón donde pasas propiedades desde un componente superior hasta uno profundo, atravesando componentes intermedios que no las usan. Genera firmas de props infladas y acoplamiento innecesario.

    ¿Cuándo puedo ignorarlo?

    Cuando la prop atraviesa uno o dos niveles y no complica el mantenimiento. No todo pasaje de props requiere refactor.

    ¿Cuándo usar Context en lugar de un store?

    Usa Context para valores globales y estables (tema, idioma, sesión). Evita Context para datos que cambian con alta frecuencia o requieren escrituras concurrentes desde múltiples partes.

    ¿La composición siempre es la mejor opción?

    No siempre, pero es la primera estrategia a intentar: sin dependencias y con menor acoplamiento cuando puedes construir el subárbol desde el padre que tiene el dato.

    ¿Qué problemas de rendimiento trae Context?

    Si el valor del Provider cambia con frecuencia, todos los consumidores se re-renderizan, lo que puede impactar el rendimiento. Se puede mitigar con memos, splitting de contexts o stores que controlen re-renders finos.

    ¿Qué store elegir si la app escala?

    Depende: Zustand para simplicidad y rendimiento, Redux Toolkit para trazabilidad en enterprise, y Jotai/Recoil para control fino de re-renders.

  • Cómo evitar problemas al pedir código a la IA sin especificaciones

    Cómo evitar problemas al pedir código a la IA sin especificaciones

    ¿Quieres velocidad o quieres un desastre bonito en producción?

    Tiempo estimado de lectura: 6 min

    • Ideas clave:
    • Pedir código antes de una spec convierte velocidad aparente en deuda técnica real.
    • La spec funciona como el “system prompt” del repositorio: contratos, reglas y criterios de aceptación evitan improvisaciones.
    • Procesos concretos —plan, contratos, red teaming, tests— transforman las respuestas rápidas de IA en soluciones sostenibles.
    • El rol senior evoluciona hacia guardián de límites y políticas, no solo autor de código.

    Poca gente dice esto en las charlas con café gratis: pedir código antes de dar contexto es como contratar a un pintor y no decirle qué pared. Va a pintar rápido. Va a quedar espectacular al principio. Y al primer olor a humo descubrirás que pintó sobre el sistema eléctrico.

    Resumen rápido (lectores con prisa)

    La IA genera código probables según datos y prompts. Sin una spec que defina objetivos, stack, contratos y criterios de aceptación, las soluciones serán rápidas pero frágiles. Escribe SPEC.md, publica contratos, exige plan y tests; audita con red teaming. Conserva disciplina para convertir velocidad en sostenibilidad.

    Poca gente habla de esto: la IA no entiende tu negocio

    Los modelos de lenguaje son máquinas de probabilidades. No entienden SLAs, ni GDPR, ni las peleas internas por usar Next.js o Svelte. Responden con lo más probable según su entrenamiento y tu prompt. Si no les das reglas, toman decisiones por ti. Decisiones elegantes, pero improvisadas. Y la improvisación no escala.

    Lo que pasa cuando pides código demasiado pronto

    No es teoría. Es patrón repetido en equipos que adoptan IA rápido y disciplina lenta:

    Demo brillante en 48 horas. Integración rota, tokens expuestos, tests que fallan en producción. Dos semanas de refactor para rescatar el proyecto.

    Síntomas concretos

    • Componentes gigantes que hacen todo: UI, llamadas HTTP, validaciones y cambios en la base de datos. Un archivo de 500 líneas que asusta.
    • Mezcla de librerías por impulso: Fetch aquí, Axios allá, una dependencia vieja que “funcionaba” en un tutorial.
    • Flujos automatizados (n8n, Zapier) que fallan ante el primer timeout porque nadie pensó en idempotencia.
    • Tests que existen pero no validan casos reales. O peor: pruebas que pasan porque la spec nunca fue clara.

    Alucinación arquitectónica: la versión elegante del desastre

    No es solo que la IA invente funciones. Inventará abstracciones. Te propondrá un patrón porque en sus datos aparece muchas veces. Puede recomendarte Event Sourcing para una app de encuestas. Te entregará un PR perfecto. Y tú, encantado, lo mergeas.

    Hasta que llega la primera incidencia. Hasta que un miembro nuevo del equipo abre ese PR y no entiende nada. La IA actúa con convicción. Por eso hace falta liderazgo humano que coloque límites.

    La spec: no es burocracia. Es supervivencia

    Quien sigue llamando a la spec “ese PDF que nadie lee” está mirando el problema con los ojos cerrados. En la era de la IA la spec es la única forma de que la creatividad de la herramienta aterrice donde debe.

    Piensa en la spec como el System Prompt del repositorio. No es un texto largo que nadie abre; es la brújula del proyecto. Contiene: objetivos, stack, reglas innegociables, modelos de datos, respuestas ante fallos, y criterios de aceptación.

    Si la IA fuera un barco y tu equipo fuera la tripulación, la spec es la brújula. Sin ella, el barco navega rápido y choca.

    Cómo evitar pedir código demasiado pronto (pasos concretos)

    No es magia. Es disciplina con sentido. Haz esto antes del primer commit generado por IA.

    1) Escribe el objetivo en una frase

    ¿Qué problema resuelve este módulo? ¿Qué NO debe hacer? Si no puedes decirlo en una frase, no lo pidas. La IA no lo adivina.

    2) Define el stack y las reglas innegociables

    Next.js 14 OK. No usar SSR en X páginas. No introducir nueva dependencia sin CVE-check. ¿Postgres o Mongo? ¿Monolito o microservicios? Quítale opciones a la IA para que deje de improvisar.

    3) Publica contratos antes que código

    Interfaces TypeScript, esquemas Prisma, OpenAPI. Si la IA tiene contratos, genera lógica que encaje. Si no los tiene, generará sutilezas que rompen todo.

    4) Exige plan antes de ejecución

    Pide un plan en pasos. Repite: plan. No “hazlo tú ahora”. Pide la lista de entregables, aprobala y luego ejecuta cada paso con prompts acotados.

    5) Red Teaming desde el minuto cero

    Pídele a la IA que sea adversaria: “Rompe este diseño.” “¿Qué falla con 10k req/s?” “¿Qué pasa si el proveedor OAuth cae 30s?” Esto saca a la luz cuellos de botella y casos límite.

    6) Testes y ejemplos junto al contrato

    Cada endpoint debe venir con payloads válidos e inválidos y tests de aceptación. Si la IA genera código sin tests que validen la spec, recházalo.

    7) Guarda la spec en el repo (no en Google Docs)

    SPEC.md, .cursorrules, spec.json. Ponlo en la raíz. Que sea lo primero que lea el agente cuando genere código.

    Plantilla mínima de SPEC.md (pégala ya)

    No la copies sin adaptar, pero ten algo así en la raíz del repo:

    • Título en una frase: Objetivo del módulo.
    • Stack aprobado: Next.js 14, Node 20, Postgres 15.
    • Reglas innegociables:
      • No exponer secretos en frontend.
      • Mutaciones por Server Actions.
      • Máximo 2 dependencias nuevas sin revisión de seguridad.
    • Contratos principales:
      • /api/users POST -> CreateUserRequest, CreateUserResponse (interfaces TypeScript)
      • DB: users (id uuid, email text unique, password_hash text)
    • Criterios de aceptación:
      • Test de integración que crea usuario y valida hash.
      • Tiempo máximo respuesta: 500ms en endpoint crítico.
    • Política de secretos: usar Vault, nunca env vars en texto plano.
    • Responsables: Tech Lead: @ana, Owner: @carlos.

    Prompts que funcionan (ejemplos directos)

    Un buen prompt = contexto + restricciones + output esperado.

    Malo: “Hazme un CRUD de users.”

    Bueno: “Te doy la spec (inserta SPEC.md). Genera: 1) Interfaces TS 2) OpenAPI para /api/users 3) Tests de integración con ejemplos válidos/ inválidos. No uses librerías externas para hashing. Tiempo de respuesta <500ms.”

    Divide el trabajo en sprints cortos y verificables

    • Sprint A: Modelo de datos + contratos + tests.
    • Sprint B: Endpoints críticos + seguridad.
    • Sprint C: Observabilidad y despliegue.

    Aprobar cada sprint antes de pasar al siguiente.

    El nuevo rol del Senior: faro y guardián, no solo coder

    Antes bastaba con saber la sintaxis. Hoy el valor está en definir límites, auditar reglas y decidir qué complejidad merece implementarse. El senior no codifica menos; decide mejor. Su trabajo es preguntarse: ¿esta solución respeta la spec? Si no, veto.

    Historias que sirven como espejo

    Junior + Copilot = demo en 48h. Producción = caos. Reescritura 3 semanas.

    Mismo caso con spec: plan en 2 días + Claude para contratos + Copilot para implementación respetando interfaces = demo en 48h. Integración estable. Diferencia: disciplina.

    Metáfora corta y pegadiza

    La spec es el embudo; la IA es la manguera. Sin embudo, el agua corre por todos lados. Con embudo, llega donde debe.

    Cuándo no necesitas spec rígida

    Sí, hay espacio para improvisar. Para generar mocks, para prototipos exploratorios o pequeñas refactors locales. Pero regla práctica: si tocas contratos (APIs, DB, auth, infra), necesitas spec. Punto.

    Checklist rápido antes de pedir código a la IA

    • ¿Existe SPEC.md en la raíz?
    • ¿Hay interfaces/contractos definidos?
    • ¿Hay reglas de seguridad básicas?
    • ¿El prompt pide tests y ejemplos?
    • ¿Se solicitó plan paso a paso y fue aprobado?

    Si respondes no a cualquiera, NO pidas código aún.

    Urgencia real: deuda técnica multiplica costes

    Cada PR aceptado sin spec es una apuesta. Adivina quién paga si pierde la apuesta: tu equipo. La deuda técnica no se desintegra con buenas intenciones. Se compone. Actuar ahora cuesta horas. Rehacer después cuesta semanas, o clientes.

    CTA simple y directo

    Haz esto en los próximos 60 minutos: crea SPEC.md en la raíz con las seis secciones mínimas que te di. Respóndeme con “Quiero la plantilla” y te la mando lista para pegar en tu repo.

    Cierre que no cierra (a propósito)

    Si sigues pensando que la IA es una varita mágica, es tu opción. Tienes otra: gobernarla. La spec es la forma más barata de gobernarla. No es cómoda. Es efectiva. Y esto no acaba aquí: si quieres, te doy la plantilla, un prompt maestro listo para Claude y un .cursorrules de ejemplo. Dime cuál quieres y te lo envío ahora. Tus commits —y tu equipo dentro de seis meses— lo agradecerán.

    Dominicode Labs

    Si trabajas con automatización, agentes o workflows y quieres ejemplos prácticos de especificaciones y .cursorrules, revisa los recursos disponibles en Dominicode Labs. Es una continuación lógica para equipos que buscan convertir experimentos rápidos en procesos repetibles y seguros.

    FAQ

    ¿Qué es una SPEC.md y por qué es necesaria?

    Una SPEC.md es un archivo en la raíz del repositorio que define objetivo, stack, reglas innegociables, contratos y criterios de aceptación. Es necesaria para alinear generación de código automática con las restricciones del negocio y evitar decisiones improvisadas que generen deuda técnica.

    ¿Cuándo puedo pedir código sin spec?

    Para prototipos exploratorios, mocks o pequeños refactors locales. Si el cambio afecta APIs, DB, auth o infra, siempre usar spec. Esa es la regla práctica del artículo.

    ¿Cómo garantizo que la IA respete los contratos?

    Publica interfaces TypeScript, OpenAPI o esquemas en el repo antes de pedir código. Exige tests que validen esos contratos y revisa que las implementaciones pasen los tests de integración definidos en la spec.

    ¿Qué contiene un criterio de aceptación sólido?

    Entradas y salidas esperadas, límites de rendimiento (ej. tiempo máximo 500ms), condiciones de error y tests de integración que validen el comportamiento en casos válidos e inválidos.

    ¿Quién debe ser responsable de la spec?

    Responsables claros: Tech Lead y Product Owner. En el ejemplo: Tech Lead: @ana, Owner: @carlos. Debe estar versionada en el repo y ser lo primero que lea cualquier agente automatizado.

    ¿Cómo auditar seguridad en dependencias sugeridas por IA?

    No introducir nuevas dependencias sin revisión de seguridad: CVE-check, análisis de licencia y una prueba mínima en entorno aislado. La spec puede imponer un máximo de dependencias nuevas sin revisión.

  • Cómo la librería sin código redefine la automatización en desarrollo

    Cómo la librería sin código redefine la automatización en desarrollo

    Tiempo estimado de lectura: 5 min

    Ideas clave

    • Tests como IP: la suite de tests y la especificación pasan a ser el activo más valioso.
    • Aceleración parcial: los agentes cubren rápidamente la mayor parte, pero el último 10% exige juicio humano y arquitectura.
    • Arquitectura y desacoplo: sin contratos claros, las correcciones que arreglan un test pueden romper otros.
    • Proceso recomendado: invertir en specs y tests antes de delegar a agentes; mantener CI y revisiones humanas.

     

    So welcome. Uh I was invited here today to talk about a project I launched which was a software library with no code

    Introducción breve

    Drew Brunig publicó una librería “sin código” —solo especificación, tests (≈750) y un prompt de instalación— y el resultado no fue sólo viralidad: fue una lección práctica sobre qué parte del trabajo de ingeniería sigue siendo inevitable y cuál puede automatizarse con agentes. Este artículo organiza esos aprendizajes y aporta criterio técnico aplicable a equipos que piensan en Spec‑Driven Development con IA.

    Resumen rápido (lectores con prisa)

    Qué es: un enfoque donde la especificación y la suite de tests definen el comportamiento; los agentes generan la implementación.

    Cuándo usarlo: para acelerar prototipos y reimplementaciones cuando hay tests extensivos y contratos claros.

    Por qué importa: desplaza el valor hacia quien diseña tests y specs; reduce el trabajo manual inicial pero no elimina la necesidad de arquitectura y revisión humana.

    ¿Por qué la librería sin código fue relevante?

    El experimento es instructivo porque separó tres capas que normalmente vienen entremezcladas:

    • Intención (spec en Markdown).
    • Validación (tests de conformidad en YAML).
    • Implementación (el artefacto que aquí se delega a agentes).

    Al entregar intención y validación como artefactos primarios, Brunig probó qué tanto del trabajo de implementación es reproducible por LLMs y qué partes siguen exigiendo juicio humano y arquitectura.

    Evidencia práctica y proyectos comparables

    Proyectos recientes muestran el patrón a escala:

    • Vercel/just‑bash (reimplementación de comportamiento Bash con tests generados desde shell reales).
    • Reimplementaciones de CPython en Rust (uso intensivo de la suite de tests de CPython).
    • Experimentos de Anthropic (multi‑agent para construir un compilador C, con inversión significativa en tokens).

    Fuentes útiles: repositorios y suites de tests en GitHub, ejemplo: CPython, y artículos corporativos como los de Anthropic.

    Cuatro aprendizajes técnicos que importan hoy

    1) Los tests son la nueva propiedad intelectual

    La parte más valiosa deja de ser el código y pasa a ser la suite de tests y la especificación que define exactamente el comportamiento. Construir tests exhaustivos es caro y requiere dominio del dominio. No es trabajo trivial que se “externalice” a la IA sin invertir en diseño de casos límite.

    2) La aceleración inicial es real; la finalización no lo es

    Los agentes cumplen los primeros grandes hitos rápidamente: el 80–90% funcional puede aparecer en poco tiempo. El último 10% (reglas de borde, consistencia, rendimiento, seguridad) exige iteración humana, diseño arquitectónico y pruebas adicionales.

    3) La arquitectura es el verdadero cuello de botella

    Cuando el sistema crece, los cambios locales producen regresiones globales. En Anthropic vieron cómo arreglar un test rompía otro. Los LLMs actuales tienden a reaccionar al test que falla sin razonar sobre el acoplamiento global. Para evitar bucles de regresión necesitas módulos desacoplados, contratos claros e invariantes explícitas.

    4) El multi‑agent development exige paralelismo arquitectónico

    Para que múltiples agentes trabajen sin colisión, el código debe dividirse en módulos con APIs limpias y dependencias mínimas. Diseñar para desarrollo paralelo (contratos, stubs, simuladores de I/O) es un trabajo humano previo que habilita la escala con agentes.

    Implicaciones prácticas para equipos y líderes técnicos

    • Invierte primero en especificaciones y tests antes de desplegar agentes. Los tests son la palanca que convierte IA en automatización fiable.
    • Prioriza arquitectura modular: si un área del código requiere conocer todo el sistema para cambiarla, no será buena candidata para delegar a agentes.
    • Mantén el ciclo implementación→spec→test iterativo: la implementación te enseña sobre casos no anticipados y mejora la spec.
    • Automatiza CI con pruebas de regresión estrictas: cada PR generado por un agente debe pasar un pipeline riguroso antes de merge.

    Patrón de despliegue recomendado (práctico)

    1. Definir spec y escribir tests automáticos (TDD extendido).
    2. Probar localmente con agentes en entorno aislado (sandboxes, contenedores).
    3. Validar outputs en CI paralelo a los tests humanos.
    4. Hacer revisiones arquitectónicas humanas en cada salto de confianza (no sólo revisar diffs).

    Conclusión con criterio

    El experimento de la librería sin código no demuestra que el código vaya a desaparecer; demuestra que el valor en ingeniería se está desplazando hacia quien diseña la intención y la validación. Para DominiCode y equipos serios, eso significa dedicar recursos a especificaciones, suites de tests y arquitectura: cuando esas tres piezas están bien hechas, los agentes son aceleradores poderosos. Si no, introducen velocidad sin control y deuda técnica más rápido que nunca.

    Referencias y lectura adicional

    Para equipos que evalúan integrar agentes y workflows automáticos en su ciclo, una continuidad natural es explorar iniciativas experimentales y herramientas internas; una referencia útil para esos experimentos es Dominicode Labs, que agrupa instalaciones y guías para prototipado con agentes y testing automatizado.

    FAQ

    ¿Qué significa “librería sin código” en este contexto?

    Se refiere a un artefacto donde la especificación y la suite de tests son los insumos primarios y la implementación es generada por agentes (LLMs), en lugar de entregar código escrito manualmente.

    ¿Por qué los tests se consideran propiedad intelectual?

    Porque definen con precisión el comportamiento esperado. Una suite de tests bien diseñada encapsula conocimiento del dominio y casos límite que permiten reproducir o proteger la funcionalidad independientemente del código.

    ¿En qué casos es adecuado delegar implementación a agentes?

    Cuando existe una especificación clara y una suite de tests robusta que cubre los escenarios críticos. También es más adecuado en áreas modulares y poco acopladas donde el riesgo de regresión global es menor.

    ¿Cómo se evitan regresiones en desarrollos multi‑agent?

    Mediante módulos desacoplados, contratos explícitos, tests de regresión estrictos y pipelines CI que validen cada cambio generado por agentes antes del merge. Las revisiones arquitectónicas humanas siguen siendo necesarias.

    ¿Qué rol juegan las revisiones humanas?

    Las revisiones humanas validan diseño arquitectónico, casos límite no cubiertos por tests y decisiones de seguridad o rendimiento. Son críticas en los saltos de confianza donde un agente no puede evaluar impacto sistémico.

    ¿Cuál es el primer paso práctico para adoptar este enfoque?

    Invertir en escribir especificaciones claras y una suite de tests automatizados que cubran comportamientos clave, antes de encargar a agentes la generación de código o refactorizaciones.

     

  • TypeScript 7.0 en Go: Mejoras significativas en rendimiento y paralelismo

    TypeScript 7.0 en Go: Mejoras significativas en rendimiento y paralelismo

    TypeScript 7.0 en Go: qué está pasando y por qué es histórico

    Tiempo estimado de lectura: 3 min

    • Reescritura en Go: Microsoft está migrando el compilador oficial de TypeScript a Go, buscando binarios nativos, paralelismo real y un GC con latencias más predecibles.
    • Rendimiento práctico: Benchmarks internos muestran mejoras de orden de magnitud que reducen compilaciones de minutos a segundos, con impacto directo en CI/CD y experiencia de editor.
    • Compatibilidad y fricción: Integraciones que consumen la API interna de tsc requerirán adaptación (RPC, bindings, WASM) y pruebas exhaustivas en casos límite.
    • Acción inmediata: Estabilizar en TypeScript 6.0, automatizar chequeos de tipos en CI y mapear dependencias que usan la API interna de tsc.

    Tabla de contenidos

    TypeScript 7.0 en Go: qué está pasando y por qué es histórico — la frase debería ser familiar para cualquier Tech Lead que haya sufrido compilaciones lentas en monorepos. Microsoft está reescribiendo el compilador de TypeScript en Go, un movimiento que cambia la base de rendimiento y operacionalidad de todo el ecosistema. Esto no es una mejora incremental: es una rearquitectura que hace viable un análisis tipo‑a‑gran escala sin renunciar a la precisión semántica que define a TypeScript.

    Resumen rápido (lectores con prisa)

    TypeScript 7.0 es la reescritura del compilador oficial en Go, orientada a rendimiento y paralelismo. Ofrece binarios nativos, mejor paralelización y un GC con latencias más predecibles. Es relevante para monorepos, CI y experiencia de editor. Prepara la migración estabilizando en TypeScript 6.0 y automatizando chequeos de tipos en CI.

    TypeScript 7.0 en Go: qué está pasando y por qué es histórico (resumen técnico)

    El compilador actual está escrito en TypeScript y corre sobre Node/V8. Esa decisión fue pragmática en 2012, pero hoy limita la paralelización y sufre del JIT/GC de V8 en cargas largas. Reescribir tsc en Go aporta tres ventajas concretas:

    • Binarios nativos sin warm‑up de JIT.
    • Paralelismo real con goroutines y memoria compartida para analizar módulos en paralelo.
    • Un GC con latencias más predecibles, mejorando la experiencia de tsserver.

    Las herramientas que demostraron el valor del código nativo ya probaron que compilar fuera de Node puede multiplicar la velocidad. SWC, esbuild, Biome y Turbopack ya marcaron esa tendencia. Ahora el compilador oficial entra en esa categoría, pero manteniendo la verificación de tipos completa que esas herramientas no cubren.

    Por qué importa para proyectos grandes y monorepos

    Los beneficios no son teóricos. Microsoft reporta mejoras de orden de magnitud en benchmarks internos, reduciendo compilaciones que tardaban minutos a segundos. Traducido a la vida real:

    • CI/CD: menos minutos por ejecución ⇒ menos coste y despliegues más rápidos.
    • tsserver: indexado y respuestas en el editor que no degradan con el tiempo.
    • Compilaciones incrementales: casi instantáneas en repositorios con cientos de paquetes.

    Si tu pipeline actual dedica gran parte del tiempo a tsc --noEmit, esto cambia la economía del desarrollo.

    Impacto en Angular y React: matices prácticos

    Angular

    Angular está fuertemente integrado con el pipeline de TypeScript (Angular Compiler y Language Service). Proyectos enterprise con workspaces (Nx, monorepos) verán una mejora directa en ng build, ng serve y en la reactividad de las herramientas de plantilla.

    React/Next.js/Vite

    La cadena de transpilación de React/Next.js/Vite ya utiliza SWC o esbuild para velocidad, pero sigue ejecutando tsc para verificación de tipos en CI. Ahí la ganancia será ostensible: los chequeos de tipos dejarán de ser el cuello de botella de los pipelines.

    En ambos casos, el resultado es práctico: menos tiempo en loops edit→build→test y más capacidad para ejecutar validaciones costosas (análisis estático adicional) sin penalizar al equipo.

    Riesgos y fricciones en el ecosistema

    El cambio es histórico, no indoloro. Puntos a vigilar:

    • Herramientas que consumen la API del compilador (por ejemplo ts-morph) necesitarán adaptaciones para interoperar con el nuevo binario o exponer puentes (RPC, bindings, WASM).
    • Integraciones internas que dependen de detalles de implementación de tsc pueden requerir trabajo de migración.
    • Compatibility testing: aunque el lenguaje no debería cambiar, diferencias sutiles en corner cases exigen pruebas exhaustivas.

    La recomendación es seguir la guía oficial del repositorio de TypeScript y monitorizar los anuncios de Microsoft para migraciones y tooling.

    Qué hacer hoy: plan de preparación para equipos técnicos

    1. Estabiliza tu base de código en TypeScript 6.0: activa strict: true y corrige errores. TypeScript 6.0 actúa como puente hacia 7.0.
    2. Automatiza chequeos de tipos en CI: ejecuta tsc --noEmit y añade cobertura para casos límite de tipos.
    3. Identifica dependencias: detecta librerías y herramientas que usan la API interna de tsc y marca tickets de migración.
    4. Mide: registra tiempos actuales de compilación y coste de CI para cuantificar mejoras futuras.
    5. Mantén pruebas: pruebas end‑to‑end y contract tests; cualquier cambio del compilador debe validar el comportamiento real del producto.

    Perspectiva: por qué es histórico

    La convergencia de herramientas nativas (Rust/Go) con el ecosistema JavaScript es una tendencia clara: mayor velocidad sin perder integridad semántica. TypeScript 7.0 no es solo rendimiento; es la posibilidad de escalar el análisis estático a organizaciones enteras sin sacrificar productividad. Para equipos que priorizan calidad y velocidad operativa, esto reconfigura las decisiones de arquitectura y la inversión en tipado.

    Fuentes y lecturas

    Adoptar TypeScript 6.0 y preparar tu infraestructura ahora es la mejor forma de capitalizar la promesa de TypeScript 7.0 en Go cuando el binario esté listo para producción.

    FAQ

    ¿Qué cambia exactamente al reescribir tsc en Go?

    La implementación pasa de ejecutarse sobre Node/V8 a binarios nativos en Go. Esto aporta binarios sin warm‑up de JIT, paralelismo real con goroutines y un GC con latencias más predecibles.

    ¿Debo migrar mis repositorios ahora mismo?

    No necesariamente. La recomendación práctica es estabilizar en TypeScript 6.0 (activar strict: true, corregir errores) y preparar la infraestructura (CI, pruebas) para una futura migración cuando el binario sea estable.

    ¿Cómo afectará esto a mi CI/CD?

    En la mayoría de casos reducirá significativamente los tiempos de ejecución de chequeos de tipos, disminuyendo coste y acelerando despliegues. Es importante medir tiempos actuales para cuantificar la mejora.

    ¿Qué pasa con herramientas que usan la API de tsc?

    Esas herramientas necesitarán adaptaciones: exponer bridges (RPC), bindings o compilar a WASM según el caso. Herramientas como ts-morph son ejemplos que requerirán trabajo de migración.

    ¿Cambiará el lenguaje TypeScript?

    El lenguaje en sí no debería cambiar por la reescritura. Sin embargo, diferencias sutiles en casos límite podrían aparecer, por lo que se requieren pruebas exhaustivas de compatibilidad.

    ¿Cómo puedo medir el beneficio esperado?

    Registra métricas actuales de compilación y coste de CI, ejecuta benchmarks representativos y compara tiempos antes y después. Automatiza registros para cuantificar el impacto en pipelines y tiempos de desarrollador.

  • Cómo evitar la deuda técnica al integrar agentes de IA en el desarrollo

    Cómo evitar la deuda técnica al integrar agentes de IA en el desarrollo

    ¿Y si la velocidad que te vendieron como progreso es, en realidad, el motor que va a deshacer tu arquitectura?

    Tiempo estimado de lectura: 8 min

    • Ideas clave:
    • Integrar agentes de IA sin capturar intención produce deuda técnica a escala.
    • Necesitas trazar decisiones → requerimiento → test → código y hacerla canónica.
    • Una herramienta como Plum no pinta paredes; convierte intención volátil en artefactos persistentes.
    • Gobernanza debe vivir fuera del agente: hooks, CI y aprobaciones humanas son imprescindibles.

    Introducción

    ¿Y si la velocidad que te vendieron como progreso es, en realidad, el motor que va a deshacer tu arquitectura?

    Poca gente lo dice sin rodeos: integrar agentes de IA para escribir código sin un sistema que capture la intención es una receta perfecta para deuda técnica a escala industrial. Y no hablo de “posibles problemas”. Hablo de que, hoy, el código puede crecer más rápido de lo que cualquier humano puede leer —y eso duele en producción.

    This is her code. This is what she was managing. This is her VS code.

    Margaret Hamilton sujetó esa complejidad con una pila de impresiones. Ella no tenía prompts; tenía procedimientos. Nosotros tenemos prompts y convicciones ingenuas.

    Vamos al punto.

    Resumen rápido (lectores con prisa)

    Plum es una herramienta de gobernanza que intercepta commits, extrae decisiones y las convierte en artefactos trazables. Úsala cuando quieras que las decisiones que toman agentes o developers queden registradas y enlazadas a specs, tests y código. Importa porque previene deuda técnica acelerada por IA y funciona mediante git hooks, diffs, y un flujo de aprobación humana.

    1) El problema (simple y aterrador)

    Si un Product Manager edita una regla en producción, ¿el resto del sistema cambia con ella?

    En la práctica, no.

    Los hotfixes saltan directo al trunk.

    Los tests se rompen en silencio.

    Las specs siguen siendo documentos en Markdown que nadie actualiza.

    Y cuando introduces agentes de IA en ese mix, la cosa se acelera: los LLMs toman micro-decisiones en chats, tú implementas, haces commit y la “intención” se evapora.

    Resultado: código con autoría pero sin porqué. Comportamiento sin contrato. Equipos que arreglan cosas por intuición y no por diseño.

    2) Por qué los tests y specs no bastan

    Un test valida un output. No captura intención.

    Un spec define un contrato —hasta que alguien lo ignora.

    La implementación revela límites: casos borde, problemas de estado, compromisos de rendimiento. La única forma real de enriquecer una spec es escribir el maldito código. Implementar obliga a decidir. Y esas decisiones deben quedar registradas.

    3) ¿Qué hace falta?

    • Capturar decisiones. No dejar que vivan en el chat.
    • Vincular decisión → requerimiento → test → código.
    • Hacer que esa trazabilidad sea canónica y no opcional.

    Sin eso, tus agentes son obreros hiperproductivos que construyen habitaciones sin planos. Velocidad sin planos = casa que se cae.

    4) Plum: la plomada que no pinta paredes

    No es mágica. No genera código bonito.

    Plum hace otra cosa muchísimo más valiosa: transforma intención volátil en artefacto persistente.

    Qué hace Plum (sí, práctico)

    • Intercepta commits via git hooks.
    • Lee diffs y scans de traces de agentes.
    • Extrae decisiones (qué, por qué, quién).
    • Deduplica lógicas repetidas.
    • Te obliga a aprobar/rechazar/editar antes de permitir el commit.
    • Si apruebas, actualiza specs Markdown y genera un .jsonl con la decisión, autoría y trazas.
    • Ejecuta un sync que mapea spec ↔ tests ↔ código y muestra huecos de cobertura.

    Metáfora: la plomada cuelga del trípode y te dice si la pared está vertical. Plum no pinta; evita derrumbes.

    5) Por qué esto no puede ser una “skill” dentro del agente

    Una skill vive dentro del agente. Es una sugerencia.

    Un control de gobernanza tiene que vivir fuera. Debe poder bloquear commits, correr en CI y ser determinista.

    Si la herramienta fuera sólo otra respuesta del LLM, se ignoraría. Punto.

    6) Problemas reales a resolver (y por qué no es trivial)

    • Umbral de interrupción: si cada hotfix genera cinco decisiones para revisar, los devs odian la herramienta. Necesitas tolerancias dinámicas: que el sistema sólo te despierte para decisiones vagas, peligrosas o contradictorias.
    • Dedupe y fuzzy decision ID: identificar decisiones no es binario; es difuso y repo-específico. Necesitamos algoritmos ajustables y feedback humano.
    • Rollbacks automáticos: si rechazas una decisión, el sistema debería revertir el cambio relevante o pedir al agente que rehaga la tarea coherentemente. Hoy eso no está pulido.
    • Spec sharding: las specs crecen. Hay que fragmentarlas en requisitos testables. Un LLM puede ayudar a shardear, pero hay que diseñarlo.
    • Integración de test runners: en la versión actual Plum está acoplado a pytest. Necesitamos soporte agnóstico: conformance tests, runners multi-lenguaje, harnesses de integración.
    • Escalabilidad: en proyectos monolíticos gigantes aún no sabemos si el approach escala. Téstealo en una rama pequeña antes de clonar tu repo legacy.

    7) Cómo se gana valor real (dejando de ser postura)

    • Haz que cada decisión importante deje rastro. No excepciones.
    • Exige aprobación humana para decisiones con impacto.
    • Vuelve la spec viva: que el archivo Markdown no sea un monumento a la intención, sino el contrato vigente.
    • Los tests deben describir intención, no solo outputs. Property tests e invariantes sistémicas son tus nuevos héroes.
    • Si un agente necesita leer 50 archivos para cambiar una función, rehace la arquitectura: modularidad extrema, boundaries claros.

    8) Diseño técnico inteligente (lo que aprendí construyéndolo)

    • Usa git hooks como checkpoint. Si el commit no pasa la validación de decisiones, el commit falla.
    • Mantén un .plumignore para no disparar reviews por cambios triviales (README, docs, etc.).
    • Almacena estado y config en una carpeta oculta (.plum). Versiona el .jsonl.
    • Deduping y parsing de specs: estructura las llamadas LLM con DSPy para hacerlas más deterministas y testables.
    • Router de modelos: no todo exige GPT-costoso. En dedupe puedes usar un modelo OSS rápido. La experiencia del dev gira alrededor de latencia.
    • Diseña la UX: permitir modos (silent, strict, dangerously-approve) para distintos contextos.

    9) Ejemplo mínimo de flujo (para que lo pruebes en 15 minutos)

    • pip install plum-dev
    • cd repo (with specs.md and pytest suite)
    • plum init → apunta a folder de specs y a tests
    • Haz cambios con tu agente y commit
    • Si hay decisiones, git commit fallará y te pedirá revisión
    • Aprobar actualiza spec; reject detona rollback o workflow manual según tu configuración

    10) Umbral y gobernanza: políticas prácticas

    • En sistemas críticos: tolerancia cero. Todo pasa por aprobación humana.
    • En prototipos: modo “agile fast-lane” para no morir de fricción.
    • En equipos mixtos: definir perfiles por carpetas/paquetes. Modules core = strict; UI experimental = lenient.
    • Pipeline: bloquear merges si spec↔tests↔código no están sync. Es duro, sí. Necesario, también.

    11) Cultura y disciplina

    No se automatiza cultura. Se diseña.

    Pide que cada PR incluya:

    • ¿Qué decisión justificó este cambio?
    • ¿Qué requisitos se actualizaron?
    • ¿Qué tests nuevos cubren la decisión?

    Y deja que la herramienta coja esos metadatos y los convierta en .jsonl rastreables.

    12) Lo práctico y lo urgente

    • Si ya usas agentes y no tienes este tipo de control, estás acelerando una deuda técnica que no podrás pagar. No es dramático; es inevitable.
    • Prioridad de adopción:
      • 1. Empezar a capturar traces.
      • 2. Agregar hooks que bloqueen commits sin revisión de intención.
      • 3. Transformar specs en contratos testables.
      • 4. Automatizar sync y coverage mapping.

    13) ¿Qué pasa si no lo haces?

    Velocidad hoy = caos mañana.

    Cuando un bug crítico aparezca a las 2 AM, nadie sabrá por qué la regla se cambió. Commits huérfanos. Blame que no sirve. Migraciones peligrosas. Equipos quemados. Clientes enfadados.

    14) No todo es miedo: oportunidades enormes

    • Auditoría real sobre decisiones: útil para compliance y seguridad.
    • Mejor onboarding: nuevos devs leen el árbol de decisiones para comprender el porqué.
    • Menos discusiones eternas en PRs: si la decisión está bien documentada, la discusión baja y la calidad sube.
    • Productividad con control: velocidad + gobernanza = ventaja competitiva.

    15) Cierre con acción concreta

    Instala la plomada. Prueba en una rama pequeña. No por postureo. Por supervivencia técnica.

    Si quieres:

    • Te mando un template de .jsonl para decisiones.
    • Te paso un flujo de PR que puedes pegar en tu repo.
    • Te doy el checklist para integrar Plum en CI en 15 minutos.

    Respóndeme este mensaje con “Mándame el template” o corre ahora:

    • pip install plum-dev
    • cd tu-repo
    • plum init
    • haz un commit con un agente y observa qué decisiones aparecen.

    Esto no acaba aquí.

    Si no empiezas a capturar intención hoy, tus agentes construirán un legado que nadie querrá mantener mañana. Empieza por un archivo .jsonl. Empieza por una regla dura en tu CI. Haz que la próxima vez que alguien pregunte “¿por qué esto existe?” la respuesta esté en el repo y no en el recuerdo difuso de una conversación vieja.

    ¿Quieres el checklist y el template ahora? Dímelo. Y mientras lo instalas, piensa en esto: velocidad sin plomada es solo una forma elegante de cavar tu propia trampa.

    Para quien está explorando gobernanza de agentes y workflows, una continuación lógica es revisar investigaciones y herramientas de integridad técnica desarrolladas por equipos que experimentan con estos retos. Consulta Dominicode Labs como punto de referencia para materiales y experimentos relacionados con trazabilidad de decisiones y automatización segura.

    FAQ

    ¿Qué es Plum y para qué sirve?

    Plum es una herramienta de gobernanza que intercepta commits, extrae decisiones desde diffs y trazas de agentes, obliga a revisarlas y las convierte en artefactos persistentes (.jsonl) y actualizaciones en specs Markdown. Sirve para capturar intención y vincularla con tests y código.

    ¿Por qué no bastan los tests y las specs?

    Porque un test valida un output y una spec es un contrato que puede quedarse desactualizado. La implementación revela decisiones operacionales que deben quedarse registradas; solo ejecutar y aprobar esos cambios garantiza que la spec refleje intención real.

    ¿Cómo se integra Plum en el flujo de trabajo?

    Plum se integra mediante git hooks que interceptan commits, revisan diffs y traces, y requieren aprobación humana para cambios con decisión. Si se aprueba, Plum actualiza specs y genera el registro .jsonl; si no, puede revertir o pedir una re-ejecución coherente.

    ¿Qué pasa si rechazo una decisión durante el commit?

    Según la configuración, el rechazo puede detonar un rollback automático del cambio relevante o iniciar un workflow manual que pida al agente rehacer la tarea coherentemente. El comportamiento exacto depende de la policy definida.

    ¿Plum afecta la experiencia del desarrollador?

    Sí: introduce una fricción intencional para decisiones relevantes. Para evitar rechazo por exceso de ruido, Plum debe soportar tolerancias dinámicas (modos silent, strict, dangerously-approve) y un .plumignore para cambios triviales.

    ¿Es Plum dependiente de un test runner?

    En su versión inicial Plum está acoplado a pytest, pero el objetivo es soportar runners multi-lenguaje y conformance tests para ser agnóstico respecto al ecosistema de pruebas.

    ¿Cómo empezar con Plum sin romper el equipo?

    Prueba en una rama pequeña, habilita modos lenientes para partes experimentales del repo y aplica tolerancia cero solo en módulos críticos. Empieza por capturar traces y agregar hooks progresivamente.

  • Cómo elegir el formato adecuado para contenido técnico

    Cómo elegir el formato adecuado para contenido técnico

    ¿Quieres que esto sea útil o que suene bonito en una página y nadie haga nada?

    Tiempo estimado de lectura: 1 min

    Ideas clave

    • Tienes un post ya escrito y necesitas decidir el siguiente paso: expandirlo, convertirlo en guía técnica o adaptarlo a redes.
    • Se ofrecen tres opciones claras con resultados distintos según objetivo y audiencia.
    • Puedes solicitar tono y extras (CI / .env / JSONL) para ajustar el entregable.

    Contenido principal

    1) Expandirlo a largo (1.500–2.000 palabras)

    • Versión profunda, técnica y persuasiva.
    • Gancho potente, ejemplos reales, checklist de adopción, riesgos, pasos de CI, y cierre con CTA.
    • Ideal si quieres un artículo para tu blog o newsletter.

    2) Transformarlo en una guía técnica práctica (800–1.200 palabras)

    • Comandos, .env ejemplo, flujo CI, script de rotación de credenciales, y best practices para agentes IA.
    • Directo al grano. Para equipos que van a implementar ya.

    3) Recortar y adaptar a LinkedIn/Twitter thread + TL;DR

    • Versión corta, viral, con 8–12 tuits o un post largo en LinkedIn que invite a comentar.
    • Perfecto para provocar conversación y atraer gente al artículo.

    Cómo responder

    Dime cuál opción y si quieres tono: más técnico, más comercial, o más provocador (yo voto por provocador). También puedo añadir: checklist de seguridad, fragmento de CI (GitHub Actions), o template de .env y JSONL para decisiones.

    Respóndeme “Opción 1/2/3” y si quieres el extra (CI / .env / JSONL). Me pongo a escribir.

    Recursos

    Si tu post toca automatización, agentes o workflows y quieres material adicional para pruebas y experimentos, puedes consultar recursos relacionados en Dominicode Labs. Es un complemento lógico cuando se trabaja con implementaciones prácticas y plantillas.

    FAQ

    ¿Qué respondo?

    Responde con “Opción 1”, “Opción 2” o “Opción 3”. Si quieres algún extra, añádelo entre paréntesis, por ejemplo: “Opción 2 (CI, .env)”.

    ¿Qué incluye la Opción 1?

    Una versión larga (1.500–2.000 palabras) orientada a profundidad técnica y persuasión, con gancho, ejemplos, checklist, riesgos, pasos de CI y un cierre con CTA.

    ¿Qué incluye la Opción 2?

    Guía técnica práctica de 800–1.200 palabras con comandos, ejemplo de .env, flujo CI, scripts de rotación y recomendaciones para agentes IA, enfocada en implementación.

    ¿Qué incluye la Opción 3?

    Versión corta pensada para redes: 8–12 tuits o un post largo en LinkedIn con TL;DR para generar conversación y atraer lectores al artículo principal.

    ¿Puedo pedir extras?

    Sí. Puedes solicitar checklist de seguridad, fragmentos de CI (por ejemplo GitHub Actions), o templates de .env y JSONL para decisiones. Indica claramente qué extras quieres al responder.

    ¿En qué formato recibo el entregable?

    El contenido se entregará listo para pegar en WordPress. Si pides fragmentos de CI o templates, se incluirán como bloques de texto listos para copiar.

  • Cómo evitar el uso de `any` en TypeScript y mejorar tu código

    Cómo evitar el uso de `any` en TypeScript y mejorar tu código

    ¿Sigues parcheando con any porque “es más rápido”? Felicidades: acabas de convertir a tu compilador en un cómplice silencioso de los bugs nocturnos.

    Tiempo estimado de lectura: 5 min

    • TypeScript no te salva por arte de magia: es una herramienta que hay que configurar y aplicar, no decoración del IDE.
    • No uses any como parche: usa unknown o validación runtime para datos externos.
    • Activa strict y prioriza validación en la frontera: tsconfig, linters, CI y validadores como Zod.

    Introducción

    Poca gente lo dice tan claro: TypeScript no te salva automáticamente. Si lo tratas como decoración del IDE, te dará una falsa sensación de seguridad. Y cuando las cosas se rompan en producción, nadie recordará quién puso ese as any a las tres de la mañana.

    Voy a ser directo. Esto es lo que rompe proyectos y cómo lo arreglas para que deje de romperlos.

    Resumen rápido (lectores con prisa)

    TypeScript proporciona tipos estáticos para detectar errores tempranos en desarrollo. No valida tipos en runtime; para datos externos hay que usar validación en la frontera (por ejemplo Zod) y mantener "strict": true en tsconfig. Evita any y el operador de aserción no-nula !; prefiere unknown, encadenamiento opcional y guard clauses. Integra linters y CI que ejecuten tsc --noEmit y pruebas de contratos para evitar deuda técnica silenciosa.

    Qué falla y cómo lo arreglas

    1) Deja de usar any como parche rápido

    any = apagar las comprobaciones. unknown = obligarte a pensar.

    Usa unknown cuando no conoces la forma de un dato. Forcear any es como cerrar los ojos y conducir a 140 km/h: puedes llegar, o no.

    Ejemplo idiota, pero real:

    // NO
    function process(payload: any) {
      console.log(payload.name.toUpperCase());
    }
    
    // SÍ
    function processSafe(payload: unknown) {
      if (typeof payload === 'object' && payload !== null && 'name' in payload) {
        console.log((payload as { name: string }).name.toUpperCase());
      }
    }
    

    No te apetece escribir esa comprobación ahora. Perfecto: pon una validación con Zod y delega la detección a la frontera.

    2) Activa strict. No negociable.

    Si tu tsconfig dice "strict": false estás firmando cheques a la deuda técnica.

    Síntomas: parámetros sin tipado, nulos que aparecen sin avisar, inicialización incompleta de clases. Solución simple: "strict": true y arreglar las fallas una por una. ¿Migración? Usa @ts-expect-error puntualmente. No rebajes la seguridad global.

    3) El operador ! es una mentira elegante

    usuario.address!.street parece limpio. Es una bomba.

    Mejor: encadenamiento opcional o guard clauses.

    • usuario.address?.street — seguro, devuelve undefined.
    • if (!usuario.address) return — claro, explícito.

    Si ven ! en un PR, que explique por qué. Si no puede explicar, rechaza el PR.

    4) as T NO valida datos externos

    const data = await res.json() as User es confiarle la vida a un string.

    En la frontera (red, persistencia, input externo), usa validación runtime. Zod, io-ts, AJV: cualquiera que genere el guard que puedas correr al recibir datos. Y sí: extrae el esquema a un único lugar para que el tipo y el validador sean la misma verdad.

    Ejemplo con Zod:

    import { z } from 'zod';
    const UserSchema = z.object({ id: z.string(), name: z.string() });
    type User = z.infer;
    
    const raw = await res.json();
    const user = UserSchema.parse(raw); // lanza si no concuerda
    

    5) La “gimnasia de tipos” rompe equipos

    Type Gymnastics — esos tipos de 40 líneas que solo el autor entiende — son deuda técnica disfrazada. Úsalos donde aporten valor: librerías, infra, utilities core. No en cada componente. Si un tipo necesita 30 minutos para entenderlo, lo estás usando mal.

    Buenas prácticas: alias cortos, nombres claros, ejemplos en comentarios y tests de tipos (tsd) para que no se rompa en silencio.

    Checklist operativo (copia y pega y aplica ya)

    • tsconfig.json: "strict": true
    • ESLint: activar reglas
      • @typescript-eslint/no-explicit-any: error
      • @typescript-eslint/strict-boolean-expressions: warn/error
    • Pre-commit: husky + lint-staged para bloquear any y !
    • CI: job que ejecuta tsc --noEmit y tests de contratos (Zod parse)
    • Boundary validation: todas las respuestas HTTP parseadas con Zod/io-ts
    • Tests de tipos con tsd en PRs críticos

    Snippet de CI (esqueleto GitHub Actions)

    name: Validate Types
    on: [pull_request]
    jobs:
      types:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v3
          - run: pnpm install
          - run: pnpm build # incluye tsc --noEmit
          - run: pnpm test:contracts # tests que hacen parse de esquemas Zod
    

    Cómo aplicarlo en equipos (cultura > herramientas)

    • Regla simple: todo dato que venga de fuera pasa por un esquemas.
    • PRs deben documentar la asunción: “Por qué este ! está justificado”.
    • Prohibe any en lint. No excepciones.
    • Revisión de tipos en pair programming para cambios complejos.
    • Añade tests e2e que verifiquen la integración real del esquema (no solo mocks).

    Errores típicos y la respuesta corta

    • “No activamos strict porque produce demasiados errores” → Activarlo e ir resolviendo; cada corrección es una deuda pagada.
    • “Validar en runtime es caro” → El coste es mínimo comparado con el tiempo perdido debugueando un null en producción.
    • “Los tipos complejos son elegantes” → Sí. Elegantes y peligrosos si nadie los entiende.

    Mini-guía de herramientas que te salvan la vida

    • Zod: validación runtime + inferencia de tipos. Ganador simple.
    • @typescript-eslint: reglas para prohibir any, !, etc.
    • tsd: tests de tipos que evitan roturas silenciosas.
    • husky + lint-staged: bloqueo en pre-commit de malas prácticas.
    • Sentry / logs: cuando la validación falla en producción, registra payload + endpoint.

    Métrica que deberías vigilar semanalmente

    • PRs con any encontrados: objetivo = 0.
    • Rechazos por ! sin justificación: objetivo = 0.
    • Número de validaciones runtime faltantes en endpoints críticos: objetivo = 0.

    Si tienes más de 1 en cualquiera, tienes trabajo de deuda técnica.

    Cierre sin azúcar: esto es disciplina, no postureo

    TypeScript te da herramientas para poner reglas fuertes y claras en el código. Sin disciplina, esas reglas se convierten en adorno. Cambiar la cultura es más duro que tocar tsconfig, pero mucho más rentable.

    ¿Quieres algo práctico para arrancar mañana? Te puedo enviar:

    • Un repo template con tsconfig, ESLint, husky, Zod y pruebas de contratos listas.
    • Un workflow de GitHub Actions que falla el CI si hay any o ! no justificado.
    • Un checklist PDF para code reviews centrado en tipado seguro.

    Respóndeme “Envíame el template” o “Quiero el workflow” y te lo paso listo. No es sexy. Es lo que evita que pases la noche arreglando prod por culpa de un as any. Esto no acaba aquí.

    FAQ

    ¿Por qué no debo usar any?

    Porque desactiva las comprobaciones de tipos y oculta errores que el compilador podría detectar. Usar any convierte el compilador en cómplice de bugs que aparecen en producción.

    ¿Cuándo usar unknown en lugar de any?

    Usa unknown cuando recibes datos sin estructura conocida. Obliga a validar o refinar el tipo antes de operar sobre el valor, evitando asunciones peligrosas.

    ¿Qué hace exactamente “strict”: true?

    Activa un conjunto de opciones de compilador que refuerzan la seguridad de tipos: strictNullChecks, noImplicitAny, strictBindCallApply, entre otras. Detecta parámetros sin tipado, nulos no manejados y problemas de inicialización.

    ¿Cómo valido respuestas HTTP correctamente?

    Usa validación runtime en la frontera con esquemas compartidos (por ejemplo Zod). Parseas el payload recibido con el esquema y manejas el error si no concuerda antes de propagar datos al resto de la aplicación.

    ¿Qué hacer si activar strict rompe demasiados archivos a la vez?

    Actívalo y corrige las fallas progresivamente. Para casos puntuales usa @ts-expect-error temporalmente, pero no como solución permanente.

    ¿Cómo evitar que los tipos complejos sean incomprensibles?

    Prefiere alias cortos y nombres claros, añade ejemplos y tests de tipos (tsd) y reserva tipos largos para librerías o infraestrutura donde el equipo esté alineado.