1. El momento: cuando la app funciona por fuera pero cruje por dentro
Al principio todo es magia. Le dices a la IA "añade una pantalla de perfil" y aparece. "Ahora un botón para exportar", y aparece. Vas rápido, muy rápido. Pero hay un momento — casi siempre entre la tercera y la décima semana — en que algo cambia. Pedir una función pequeña ya no es instantáneo. La IA tarda más, se confunde, toca cosas que no debía. Aparecen bugs en sitios que ni tocaste. La app funciona, pero moverla se volvió pesado, como caminar con barro en los zapatos.
Ese es EL momento. No pasó nada dramático: no se rompió nada visible. Lo que pasó es invisible y se llama deuda técnica. La IA construyó rápido y, como todo el que construye rápido, dejó escombros: código que ya nadie usa pero sigue ahí, la misma lógica copiada en cinco archivos, tipos any que apagan todas las alarmas, animaciones montadas de cualquier forma. Nada de eso se ve en la pantalla. Todo eso hace que cada cambio futuro sea más difícil.
2. El dolor: de dónde sale y por qué la IA ensucia (aunque escriba "bien")
Aquí lo importante y honesto: la IA no escribe código malo. Escribe código que funciona. El problema es que optimiza para "que funcione ahora", no para "que sea fácil de mantener dentro de tres meses". Y esas dos cosas tiran en direcciones distintas. Por eso, aunque cada trozo esté bien, la suma se ensucia. Estos son los cuatro tipos de escombro que deja, y por qué los deja:
- Código muerto. Le pides un cambio, la IA reescribe una función nueva… pero olvida borrar la vieja. Se queda ahí, huérfana, sin que nadie la llame. Multiplica esto por cientos de cambios y tienes archivos enteros que ya no sirven para nada.
- Duplicación. La IA no siempre recuerda que ya escribió esa misma lógica antes, así que la vuelve a escribir. Ahora la misma regla vive en cinco sitios. El día que cambie la regla, hay que corregir cinco veces — y siempre se olvida uno.
- `any` y tipos flojos. Cuando la IA no está segura del tipo de un dato, toma el atajo: lo marca como
any. Con eso apaga todas las alarmas que TypeScript tiene para avisarte de errores. El código compila… y explota en producción. - Animaciones y efectos montados a lo bruto. La IA pone gradientes animados, desenfoques, sombras — se ven bien, pero mal montados hacen sudar a la GPU y la app se siente lenta en móviles y portátiles modestos.
3. Las 7 fases de la cirugía (el corazón de todo)
Un cirujano no abre y hurga al azar: sigue un protocolo, en orden, paso a paso. La cirugía de código es igual. Son siete fases, y el orden importa: primero quitas lo muerto (para no limpiar código que ibas a borrar), luego fundes duplicados, luego endureces animaciones, luego el rendimiento de React, luego los tipos, luego calmas la GPU, y al final emites un reporte de salud. Aquí va cada una.
Fase 1 · Eliminar código muerto
Lo primero es sacar de la mesa todo lo que ya no respira. Es la fase más rentable porque limpia el terreno para todas las demás: no tiene sentido optimizar una función que vas a borrar.
- Archivos huérfanos — ficheros que nadie importa desde ningún sitio. Están ahí de una versión vieja que nunca se borró.
- Exports sin consumidores — funciones o componentes exportados que nadie usa. Se exportaron "por si acaso" y el por si acaso nunca llegó.
- Variables, funciones e imports sin usar — declarados y olvidados. El linter suele marcarlos, pero la IA los deja porque "no molestan". Sí molestan: son ruido.
- Ramas de código inalcanzables — condiciones que nunca pueden ser verdad, código después de un
return,ifque ya nadie dispara.
Fase 2 · Auditar duplicados
Con el terreno limpio, ahora buscas lo que está repetido. La regla del oficio es simple: si algo aparece tres veces o más, deja de ser casualidad y pasa a ser un patrón que merece un solo lugar donde vivir.
- Lógica repetida → sácala a una función ayudante (
helper) que ambos sitios llaman. Una regla, un solo lugar. - Números y textos mágicos repetidos (el mismo
48, la misma URL, el mismo color) → centralízalos en constantes con nombre. Cambias una vez, cambia en todos lados. - JSX repetido tres o más veces (la misma tarjeta, el mismo botón con leves variantes) → conviértelo en un subcomponente que recibe sus diferencias por props.
- El patrón `useState` + su handler repetido (el mismo estado con su función de actualización copiado en varios componentes) → extráelo a un hook propio (un
custom hook) que encapsula la lógica una sola vez.
Fase 3 · Cumplir las reglas de animación
Las animaciones son donde la IA improvisa más y donde más fallos sutiles deja — cosas que no rompen pero que hacen que la app se sienta "barata": parpadeos, saltos, transiciones que no arrancan. Estas son las reglas concretas que la cirugía verifica (aplican a librerías de animación de React como Motion / Framer Motion, el estándar del ecosistema):
- Animar hacia/desde `transparent` puede parpadear → usa
rgba(0,0,0,0)en su lugar. Cuando interpolas la palabratransparentcon un color, la transición puede dar un parpadeo feo a mitad de camino;rgba(0,0,0,0)interpola limpio. - Sin `transition` duplicado — una animación con dos definiciones de transición peleando entre sí da un resultado impredecible. Una sola fuente de verdad para el timing.
- No animar el atajo `border` (el shorthand que junta grosor, estilo y color) → anima propiedades separadas como
borderColor. El shorthand no interpola limpio. - `background` → `backgroundColor` en animaciones — animar el atajo completo
backgroundes problemático; anima solo la propiedad específica que cambia. - Keys estables en listas que entran y salen (
AnimatePresence) — si los elementos de una lista animada no tienen unakeyestable y única, las animaciones de salida se rompen y los elementos saltan. La key debe ser un id real, nunca el índice del array.
Fase 4 · Rendimiento de React
Aquí la cirugía busca el trabajo que React repite sin necesidad. Cada re-render innecesario es un poquito de lentitud; sumados, hacen que la app se sienta pesada. Cuatro cosas concretas se revisan:
- Handlers que se pasan como props sin `useCallback` → envuélvelos. Si no, cada render crea una función nueva y obliga a los componentes hijos a re-renderizarse aunque nada haya cambiado.
- Cómputos caros sin `useMemo` (filtrar/ordenar una lista grande, cálculos pesados) → memoízalos. Si no, se recalculan en cada render aunque los datos sean idénticos.
- `useEffect` con dependencias mal declaradas — dependencias de más disparan el efecto sin razón; dependencias de menos hacen que use datos viejos. Ambas son bugs. El array de dependencias debe listar exactamente lo que el efecto usa.
- `.map` sin `key` estable — renderizar listas sin una key única (o usando el índice) hace que React se confunda al reordenar y pierda estado. Cada elemento necesita su id propio.
useCallback y useMemo "por si acaso". No: memoizar también cuesta (memoria, complejidad). La cirugía solo memoiza donde hay un beneficio real y medible — un handler que baja a muchos hijos, un cómputo de verdad caro. Optimizar de más es su propia forma de suciedad.Fase 5 · Higiene de TypeScript
TypeScript es el sistema de alarmas de tu código: te avisa antes de que un error llegue al usuario. Pero solo funciona si le dejas ver los tipos. Cada any es una alarma que alguien apagó. Esta fase las vuelve a encender.
- `any` → un tipo real, o `unknown` — el
anydesactiva todas las comprobaciones. Si de verdad no sabes el tipo, usaunknown, que te obliga a verificarlo antes de usarlo (seguro), en vez deany, que no obliga a nada (peligroso). - Revisar los casts `as Tipo` — decirle a TypeScript "confía en mí, esto es de este tipo" es una promesa que puede ser mentira. Cada
ases un punto donde el compilador dejó de comprobar. Se revisan uno por uno: ¿es cierto, o es un parche? - Internalizar exports de un solo uso — si un tipo o función se exporta pero solo se usa en su propio archivo, no debería ser público. Bájalo a privado: menos superficie, menos ruido.
- Tipar las props de los componentes — cada componente debe declarar qué props recibe y de qué tipo. Props sin tipar son
anydisfrazados.
Fase 6 · Auditar el colapso de la GPU
Esta es la fase que casi nadie conoce y la que más se nota en dispositivos modestos. Ciertos efectos visuales son bellísimos pero brutalmente caros de dibujar: si abusas de ellos, la tarjeta gráfica se satura y la app va a tirones. La cirugía busca los tres culpables clásicos:
- Gradiente cónico (`conic-gradient`) animado → muévelo a una animación CSS con
@keyframes. Animar un gradiente cónico por JavaScript en cada frame es carísimo; con keyframes el navegador lo optimiza. - Muchos `repeat: Infinity` (varias animaciones en bucle infinito a la vez) → consolídalas. Diez animaciones eternas corriendo en paralelo mantienen la GPU despierta y quemando batería sin parar. Únelas o reduce las que de verdad hacen falta.
- `backdrop-blur` en muchos elementos pequeños repetidos → si el mismo desenfoque de fondo se repite en veinte tarjetitas, la GPU lo recalcula veinte veces. Para elementos pequeños y repetidos, un fondo sólido (o semitransparente) se ve casi igual y cuesta una fracción.
backdrop-blur, ese efecto de cristal esmerilado tan de moda) obliga a la GPU a mirar TODO lo que hay detrás del elemento y difuminarlo en tiempo real. Uno solo, grande, no pasa nada. Veinte pequeños repitiéndose es como pedirle a la tarjeta que difumine la pantalla veinte veces por frame. Ahí es donde el portátil de tu usuario empieza a soplar el ventilador.Fase 7 · El reporte de salud
Toda cirugía termina con un parte. Sin reporte no sabes qué se tocó ni puedes confiar en que no hubo daños colaterales. La última fase es que el agente te entregue un resumen claro, en tu idioma, de todo lo que hizo:
- Conteo por fase — cuántos archivos huérfanos, cuántos duplicados fundidos, cuántos
anyeliminados, cuántas animaciones corregidas, etc. - Líneas purgadas — el total de líneas de código muerto que salieron. Es la cifra más satisfactoria: código que ya no tienes que mantener.
- Veredicto de "listo para producción" — la confirmación explícita de que no se cambió nada visual ni de comportamiento, solo estructura interna.
- Lo que NO tocó y por qué — las cosas que parecían candidatas pero se dejaron a propósito (duplicados que cambian por razones distintas, memoize que no valía la pena). La honestidad de lo que se decidió no hacer.
4. El hábito: la cirugía es mantenimiento, no una operación única
El error más común es pensar la cirugía como algo que haces una vez, cuando ya está todo hecho un desastre. No. El código de IA se ensucia CONTINUAMENTE, porque cada sesión de construcción deja escombro nuevo. La cirugía no es una operación de urgencia: es la limpieza de dientes que haces cada seis meses para no llegar nunca a la endodoncia.
- Después de un sprint grande de construcción — cuando la IA acaba de generar mucho código de golpe, ese es el escombro fresco. Límpialo antes de que se acumule sobre él.
- Antes de empezar una función importante — dale a la IA un lienzo limpio para construir. Sobre código sucio, construye sucio.
- Cuando notas que la IA empieza a confundirse — si la herramienta toca cosas que no debía o se pierde, es señal de que hay demasiado ruido. La cirugía le devuelve claridad.
- Un archivo o módulo a la vez, no todo el proyecto de golpe — operar un solo módulo es seguro y revisable. Operar todo a la vez es una cirugía a corazón abierto sin anestesia. Ve por partes.
5. El prompt maestro · pásaselo a tu agente y opera fase por fase
Aquí está la pieza clave: UN solo prompt que convierte a tu agente de código en un cirujano que aplica las 7 fases, en orden, a un archivo o módulo — sin tocar nada visual. Llena los [corchetes], pégalo, y deja que opere. Un consejo antes: haz un commit en GitHub primero (tu red de seguridad) y apúntale a UN módulo, no a todo el proyecto.
Actúa como un cirujano de código experto en debug. Vas a operar este archivo/módulo: [RUTA DEL ARCHIVO O CARPETA, ej: src/components/Dashboard/]. El stack es: [ej: React + TypeScript + Motion/Framer Motion + Tailwind]. REGLA SAGRADA E INVIOLABLE: CERO cambios visuales y CERO cambios de comportamiento. La app debe verse y comportarse EXACTAMENTE igual antes y después. Solo limpias y endureces por dentro. Ante cualquier duda entre limpiar más o preservar el comportamiento, SIEMPRE gana preservar el comportamiento. No borres nada si no estás seguro de que no se usa; márcalo y pregúntame. Aplica estas 7 fases EN ORDEN. No pases a la siguiente sin terminar la anterior. Al final de cada fase, dime en una línea qué encontraste y qué cambiaste. FASE 1 — CÓDIGO MUERTO: elimina archivos huérfanos (que nadie importa), exports sin consumidores, variables/funciones/imports sin usar, y ramas de código inalcanzables. Antes de borrar algo dudoso, lístamelo y espera mi confirmación. FASE 2 — DUPLICADOS: busca lógica repetida (→ extrae a un helper), números/textos mágicos repetidos (→ constantes con nombre), JSX repetido 3+ veces (→ subcomponente con props), y el patrón useState+handler repetido (→ custom hook). NO fundas cosas que solo se parecen pero cambian por razones distintas. FASE 3 — REGLAS DE ANIMACIÓN: corrige transparent→rgba(0,0,0,0), elimina transition duplicado, no animes el shorthand border (usa borderColor), cambia background→backgroundColor en animaciones, y asegura keys estables y únicas (nunca el índice) en listas con AnimatePresence. FASE 4 — RENDIMIENTO REACT: envuelve en useCallback los handlers que se pasan como props, memoiza con useMemo los cómputos caros, corrige los arrays de dependencias de useEffect (ni de más ni de menos), y añade key estable a cada .map. NO memoices por si acaso: solo donde haya beneficio real. FASE 5 — TYPESCRIPT: reemplaza cada any por un tipo real o por unknown; revisa cada cast 'as Tipo' (¿es cierto o es un parche?); internaliza los exports que solo se usan en su propio archivo; y tipa las props de todos los componentes. FASE 6 — COLAPSO DE GPU: mueve gradientes cónicos animados a CSS @keyframes; consolida los repeat:Infinity si hay muchos a la vez; y reemplaza backdrop-blur por un fondo sólido/semitransparente en elementos pequeños que se repiten muchas veces. FASE 7 — REPORTE DE SALUD: al terminar, entrégame un reporte con: conteo por fase, total de líneas purgadas, la confirmación explícita de que no cambiaste nada visual ni de comportamiento, y una lista de lo que decidiste NO tocar y por qué. Trabaja fase por fase, muéstrame el diff de cada una, y si algo pone en riesgo la regla sagrada, PARA y pregúntame antes de seguir.
6. Verifica que la cirugía no dejó heridas
Una cirugía no termina cuando cierras: termina cuando confirmas que el paciente está bien. La regla sagrada (cero cambios de comportamiento) hay que comprobarla, no solo confiar en ella. Hay dos redes de seguridad automáticas que te lo confirman en segundos, y que tu agente puede correr sin que tú programes nada.
# 1) El chequeo de tipos: cero errores = la cirugía no rompió los contratos npx tsc --noEmit # 2) Los tests: si pasaban antes y pasan igual después, # el comportamiento se preservó npm test
git diff. Regla de lectura: casi todo lo que veas deben ser líneas ROJAS (borradas) o movimientos de sitio, no lógica nueva. Si aparecen cadenas de texto que el usuario ve cambiadas, valores por defecto distintos, o condiciones nuevas, ahí hay una posible herida — pregúntale a la IA por qué antes de aceptar.7. Los caminos más fáciles · qué hace la IA por chat y qué decides tú
Para que no se complique: la mayor parte de la cirugía la hace tu agente de código solo, por el chat. Lo tuyo es dirigir y aprobar. Este es el reparto.
- Recorrer el módulo y detectar el código muerto, los duplicados, los
anyy las animaciones mal montadas — tú solo le das el prompt maestro. - Aplicar las correcciones fase por fase, mostrándote el diff de cada una.
- Correr
tscy los tests para confirmar que no rompió nada. - Escribir el reporte de salud final con los conteos y lo que decidió no tocar.
- Hacer el commit de seguridad ANTES — tu botón de deshacer. Eso lo haces tú desde GitHub Desktop o el chat, antes de operar.
- Aprobar los borrados dudosos — cuando la IA no está segura de si algo se usa, te lo pregunta; la decisión final es tuya.
- Revisar el diff — leer los cambios y confirmar que no hay heridas de comportamiento antes de aceptar.
- Decidir el alcance — qué módulo se opera y en qué orden. No delegues "opera todo": ve por partes.