Todos los recursos

Un refactor cambia la estructura del código, no lo que hace. Lo difícil es probar que esa segunda parte se mantuvo, y la única prueba honesta es un test que estaba en verde antes y sigue en verde después. Este es un skill de Claude Code que no toca código sin tests, avanza un paso a la vez y revierte apenas un test se pone en rojo. Aquí te cuento qué hace, cuándo debería activarse, cómo funciona y la única regla que evita que una limpieza te cuele un bug.

Un skill de refactor que cambia la forma, no el comportamiento

En resumen

  • Un refactor cambia la estructura sin cambiar el comportamiento. Esa segunda parte es todo el trabajo, y por eso el skill depende tanto de los tests.
  • Sin tests no hay refactor. Si falta cobertura, el skill se detiene y primero escribe characterization tests que dejan amarrado el comportamiento de hoy, aunque ese comportamiento sea feo.
  • Avanza en pasos chiquitos y reversibles. Un extract, inline o rename por ciclo, y después corre la suite. Si pasa, sigue. Si falla, revierte justo ese paso.
  • Primero el plan, después editar. Te muestra la duplicación y el código muerto que encontró y propone un plan ordenado que apruebas antes de que se mueva una sola línea.
  • Un refactor que te cambia un edge case sin avisar es el peor tipo de bug. En el diff parece una limpieza, así que nadie lo revisa buscando cambios de lógica.

Refactorizar es la tarea donde "déjame limpiar esto rapidito" tiene más probabilidades de colarte un bug a producción. Una edición estructural que te cambia un edge case sin que te enteres se ve idéntica a un arreglo inofensivo en el diff. El skill de refactor existe para volver eso casi imposible. Se niega a tocar código que no tenga tests, avanza un paso verificable a la vez y revierte apenas la suite se pone en rojo. Aquí repaso qué hace el skill, cuándo debería activarse, cómo funciona, una invocación real con su salida, la configuración que importa y los detalles que deciden si es seguro o no.

Arranquemos por la definición. Un refactor cambia la estructura del código sin cambiar el comportamiento. Esa segunda parte no es un extra opcional. Es la tarea. Y lo único que puede probar que el comportamiento no cambió es un test que estaba en verde antes y sigue en verde después. Quítale los tests y un refactor pasa a ser puro editar y cruzar los dedos.

01 · Qué hace el skill en realidad

Invocas este skill cuando un archivo se te volvió inmanejable, cuando ves la misma lógica copiada y pegada en tres lugares, o justo antes de agregar un feature a código en el que no confías. Por debajo corre cuatro trabajos, en este orden:

  1. Verificar la seguridad. Confirmar que existe una suite de tests y que pasa ahora mismo. Si no, el skill se detiene y ofrece escribir characterization tests primero. Sin excepciones.
  2. Diagnosticar y planear. Encontrar duplicación, código muerto, funciones largas y condicionales enredados. Después propone un plan ordenado de refactors pequeños y te lo muestra antes de tocar nada.
  3. Aplicar un cambio. Ejecutar un solo refactor. Extraer una función, hacer inline de una variable, renombrar un símbolo, sacar un guard clause hacia arriba. Nada más.
  4. Re-verificar. Correr los tests. Si pasan, avanza al siguiente paso. Si fallan, revierte ese único paso y reporta qué se rompió, para que el working tree nunca quede roto.

La disciplina es el producto. Cualquiera puede pedirle a un modelo que "limpie este archivo", y feliz te lo reescribe entero de una. Y ahí terminas con un diff de 300 líneas que mezcla un rename, una extracción y un cambio de comportamiento accidental, sin forma de saber qué línea provocó el test que de repente está fallando. El valor del skill es que hace cada cambio lo bastante chico como para poder atribuirlo.

Importante

Refactorizar sin tests no es refactorizar. Es editar y cruzar los dedos. Si el código no tiene cobertura, lo único honesto es escribir characterization tests primero, capturando el comportamiento de hoy aunque sea feo o discutiblemente incorrecto. Dejas amarrado lo que el código hace hoy y luego le cambias la forma por debajo, con los tests en verde. Arreglar el comportamiento feo es un cambio aparte, hecho a propósito y revisado como lo que es: un cambio de comportamiento.

02 · Cuándo debería activarse

Recurre al skill de refactor en tres momentos puntuales, y sáltatelo en todos los demás.

Actívalo cuando:

  • Un archivo se volvió inmanejable. Un módulo de 600 líneas, una función que no cabe en la pantalla, una clase que hace cinco cosas. La estructura ya es el obstáculo para leerlo.
  • Ves la misma lógica en tres lugares. La regla de tres: una vez está bien, dos es coincidencia, tres ya es duplicación que vale la pena extraer. El copy-paste que con el tiempo se desincroniza es una fuente clásica de bugs.
  • Estás por agregar un feature a código en el que no confías. Refactoriza primero hacia una forma que haga fácil ese feature, y después agrégalo. Mezclar un refactor y un feature en un mismo commit es justo lo que vuelve irrevisables las revisiones.

No lo actives cuando:

  • No hay tests y no vas a dejar que los escriba. Ahí no es un refactor, es una apuesta. O le permites agregar characterization tests o mejor no lo corras.
  • De verdad quieres cambiar el comportamiento. Arreglar un bug, agregar validación, cambiar una salida. Eso es un feature o un fix, no un refactor. Déjalos en commits separados para que el diff diga la verdad sobre lo que cambió.
  • El código está por borrarse o reescribirse de cero. No pulas lo que se va. El refactor solo justifica su costo en código que vas a conservar y a seguir tocando.

El encuadre honesto: un refactor es una inversión que hoy no le da nada visible al usuario. Inviertes esfuerzo ahora para que el próximo cambio salga más barato y más seguro. Si no hay ningún próximo cambio a la vista para ese código, el refactor es un hobby, no ingeniería.

03 · Cómo funciona por dentro

Un skill de Claude Code es un directorio con un archivo markdown: un frontmatter (un nombre y una descripción) más un cuerpo que le dice al modelo qué hacer. La descripción es lo que decide si el skill se activa. Es lo que Claude lee para juzgar si el skill viene al caso, así que tiene que decir cuándo usarlo, no solo qué es.

Aquí va una definición completa y lista para usar:

---
name: refactor-assistant
description: >
  Mejora la estructura del código SIN cambiar el comportamiento, en
  pasos pequeños verificados con tests. Úsalo cuando un archivo se
  haya vuelto inmanejable, cuando haya lógica duplicada en 3+ lugares,
  o antes de agregar un feature a código poco confiable — cuando el
  usuario diga "refactoriza", "limpia este archivo" o "extrae esta
  duplicación".
---

Refactorizas código. Refactorizar es cambiar la ESTRUCTURA, nunca el
COMPORTAMIENTO. Sigue estos pasos en orden y no saltes el paso 1.

1. PUERTA DE SEGURIDAD. Encuentra y corre la suite de tests. Si los
   tests existen y pasan, continúa. Si ningún test cubre el código
   objetivo, DETENTE. Ofrece escribir characterization tests que
   capturen el comportamiento actual (incluyendo cualquier
   comportamiento feo o sorprendente) y déjalos en verde ANTES de
   cualquier refactor. No avances sin una red de seguridad en verde.

2. PLAN. Identifica duplicación, código muerto, funciones largas y
   ramas enredadas. Presenta una lista ORDENADA de refactors pequeños
   (extraer, inline, renombrar, mover). Espera aprobación. NO metas un
   cambio de comportamiento en el plan.

3. APLICA UNO. Ejecuta exactamente UN refactor del plan. Mantén el
   diff mínimo. No arregles de paso cosas no relacionadas.

4. VERIFICA. Corre la suite completa. Si está en VERDE, reporta y pasa
   al siguiente paso. Si está en ROJO, REVIERTE ese único paso,
   reporta qué se rompió y detente para pedir guía.

Nunca cambies el comportamiento observable. Si un refactor parece
requerir un cambio de comportamiento, DETENTE y márcalo como una
decisión aparte.

El flujo es mecánico. Cuando tu pedido coincide con la descripción, Claude carga el cuerpo en contexto, encuentra y corre tu comando de tests, y solo cruza la puerta de seguridad si la suite está en verde. Después propone el plan, espera, y recorre los pasos uno por uno, corriendo la suite entre cada uno. Como el cuerpo fija el orden y las restricciones duras, el modelo queda empujado lejos de una reescritura big-bang aunque ese fuera el camino más fácil para él. Trátalo como un guardarraíl fuerte, no como un candado: igual depende de que el modelo siga el cuerpo, así que la puerta de tests es tu verdadera red de seguridad.

La instrucción que sostiene todo está en el paso 4: revierte el paso, no arregles hacia adelante. Cuando un test se pone en rojo, la tentación es seguir editando hasta que vuelva al verde. Pero eso entierra la causa y corre el riesgo de ir acumulando el error. Revertir en limpio te devuelve a un estado que sabes que estaba bien, y desde ahí decides tú qué hacer.

04 · Una invocación concreta y su salida

Tienes un módulo de facturación con el mismo cálculo de impuestos copiado y pegado en tres handlers. No pones nada en stage, abres el archivo y pides: "Refactoriza esto. El cálculo de impuestos está duplicado en tres lugares." El skill corre la puerta de seguridad, encuentra una suite que pasa y vuelve con:

PUERTA DE SEGURIDAD
Corrí "npm test" — 47 pasando, 0 fallando. La lógica de impuestos
está cubierta por billing.test.ts (líneas 80-140). Seguro avanzar.

PLAN (3 pasos, ordenados)
1. Extraer el cálculo de impuestos duplicado de invoice.ts,
   refund.ts y quote.ts a un único calculateTax(amount, region) en
   billing/tax.ts.
2. Reemplazar las tres copias inline con llamadas a calculateTax.
3. Renombrar la variable local "t" a "taxAmount" en cada call site
   por legibilidad.

Aprueba para empezar, o dime cómo ajustar el plan.

Apruebas. Aplica el paso 1 (solo la extracción: las tres copias siguen ahí, se agrega la función nueva y se testea), corre la suite, reporta verde y avanza. Después del paso 2 la suite se pone en rojo:

PASO 2 — ROJO. Revertido.
refund.ts usaba una regla de redondeo (Math.floor) que las otras no.
Reemplazarla con calculateTax (que redondea hacia arriba) cambió un
test: "refund tax rounds down". Revertí el paso 2 completo.

Esto es una diferencia de COMPORTAMIENTO, no un refactor. Opciones:
(a) mantener el floor de refund como una opción de calculateTax, o
(b) tratar el redondeo como un fix intencional — commit aparte.
Tú decides.

Ese rojo es el skill ganándose el sueldo. Una reescritura de una sola pasada habría adoptado el redondeo hacia arriba en todos lados sin avisar, el test "refund tax rounds down" habría fallado en CI horas más tarde, y alguien habría perdido una tarde haciendo bisect de una "limpieza inofensiva". En cambio, la diferencia salió a flote al instante, atribuida a un paso concreto y planteada como lo que de verdad es: una decisión de comportamiento.

Atención

No dejes que el skill "arregle hacia adelante" pasándose por encima de un test en rojo durante un refactor. Toda la garantía, cambió la estructura y no el comportamiento, descansa en que la suite se mantenga en verde en cada paso. Si un paso la pone en rojo, ese paso cambió el comportamiento. Revierte y decide a propósito. Editar hasta que el test vuelva al verde puede esconder justo el bug que querías evitar.

05 · Configuración y los ajustes que importan

Casi toda la configuración vive en el cuerpo del skill, no en flags. Los ajustes que vale la pena definir:

  • Comando de tests. Sé explícito sobre cómo correr la suite (y un subconjunto rápido para los chequeos del inner loop). El skill es tan seguro como su capacidad de correr tus tests de verdad, así que no lo pongas a adivinar.
  • Política de characterization tests. Decide desde el arranque si el skill escribe solo los tests que falten (después de mostrártelos) o si siempre se detiene y te pregunta. Para código legacy que no conoces, "preguntar siempre" es el default más seguro.
  • Catálogo de refactors. Limítalo a movimientos que preserven el comportamiento: extraer función o variable, inline, renombrar, mover, introducir un objeto de parámetros, reemplazar un condicional con un guard clause. Tener el catálogo nombrado evita que se desvíe hacia un rediseño.
  • Tamaño de paso y cadencia de commits. Que haga commit (o al menos un checkpoint) después de cada paso en verde, con un mensaje tipo refactor: extraer calculateTax (sin cambio de comportamiento). Los commits chicos hacen trivial la revisión final y quirúrgico el revert.
  • Límite de alcance. Dile qué archivos o directorios están dentro del juego. Un refactor que se mete en módulos vecinos convierte un diff ordenado en uno desparramado que nadie quiere revisar.

El no-objetivo, a propósito: nunca metas un cambio de comportamiento dentro de un refactor. En el momento en que una "limpieza" también arregla un bug o ajusta una salida, el diff deja de decir la verdad, y un revisor que pasa la vista buscando "solo un refactor" deja pasar un cambio de lógica. Si el skill descubre un bug real a mitad del refactor, lo correcto es marcarlo como una decisión aparte: terminar el cambio estructural con los tests en verde y después arreglar el bug en su propio commit, bien etiquetado.

06 · Detalles que muerden

La línea que decide todo es la puerta de seguridad: sin tests en verde, no hay refactor. Sin ella, el skill se vuelve un editor confiado que reforma el código y cruza los dedos a ver si no rompió nada, que es justo la falla que lo adoptaste para prevenir.

Unos cuantos más que muerden:

  • Los characterization tests dejan amarrado el comportamiento feo. Cuando escribes tests para capturar el comportamiento de hoy, puede que estés amarrando un bug. Y está bien que así sea, es a propósito. El refactor tiene que preservar el comportamiento de hoy para que el diff siga siendo honesto. Arregla el bug después, como un cambio deliberado y revisado aparte, no como efecto secundario de una limpieza.
  • Los tests flaky envenenan el loop. Si la suite no es determinista, un "rojo después de un paso" puede ser un test flaky y no una regresión real, y el skill terminará revirtiendo trabajo bueno o, peor, empezarás a ignorar los rojos. Pon en cuarentena o arregla los tests flaky antes de confiar en un loop de refactor automatizado.
  • Teatro de cobertura. Una suite en verde que en realidad no ejercita los edge cases te da una confianza falsa. El skill puede preservar el comportamiento que los tests chequean. El que ignoran todavía puede romperse sin que te des cuenta. Antes de un refactor serio, dale un vistazo a si están cubiertas las rutas interesantes, no solo al número de líneas.
  • Renames que parecen nada. Un rename que toca muchos archivos produce un diff enorme y aterrador que en realidad es trivial, y los revisores o lo aprueban a ciegas (mala costumbre) o pierden tiempo en él. Haz los renames en su propio commit, separados de las extracciones, para que cada diff signifique una sola cosa. (En Infuse, el gestor de secretos que estoy construyendo, mantengo los refactors y los cambios de comportamiento en commits estrictamente separados, justo para que nada que toque el manejo de llaves se cuele dentro de una "limpieza".)

Un buen skill de refactor no va a mejorar tu diseño por sí solo. Ese juicio sigue siendo tuyo. Lo que te da es la disciplina de mover la estructura sin apostar con el comportamiento: tests primero, un paso a la vez, revertir en rojo y los cambios de comportamiento bien separados y honestos. Constrúyelo una vez, aprieta fuerte la puerta de seguridad, y el día que te frene ante una suite de tests faltante en vez de seguir de largo, vas a saber que está haciendo el trabajo para el que lo contrataste.

Puntos clave

  • Un refactor cambia la estructura sin cambiar el comportamiento. Esa segunda parte es todo el trabajo, y solo los tests en verde pueden probarlo.
  • Sin tests no hay refactor. El skill se detiene y primero escribe characterization tests, dejando amarrado el comportamiento de hoy aunque sea feo.
  • Avanza en pasos chiquitos y reversibles, un extract/inline/rename por ciclo, y corre la suite entre cada uno. Si pasa, sigue. Si falla, revierte ese paso.
  • Primero planea, después edita, y nunca metas un cambio de comportamiento en un refactor, para que el diff siga diciendo la verdad sobre lo que cambió.
  • Ojo con los tests flaky, el teatro de cobertura y los renames que parecen triviales, y mantén los refactors y los fixes de comportamiento en commits estrictamente separados.

Preguntas frecuentes

¿Y si el código que quiero refactorizar no tiene ningún test?

Entonces escribes characterization tests primero. Eso no se negocia. Un characterization test captura lo que el código hace hoy, no lo que debería hacer, aunque el comportamiento de hoy sea feo o discutiblemente incorrecto. Una vez que esos tests están en verde, tienes una red de seguridad que demuestra que tus cambios estructurales no alteraron el comportamiento. Refactorizar sin esa red no es refactorizar, es editar y cruzar los dedos a ver si no se rompió nada.

¿Por qué no dejar que el modelo reescriba el archivo entero de una sola pasada?

Porque un diff de 300 líneas hecho de una sola pasada mezcla un rename, una extracción y, posiblemente, un cambio de comportamiento accidental, sin forma de distinguirlos. Cuando un test falla, no puedes atribuirlo a un solo cambio, y la revisión se vuelve imposible de revisar. Los pasos chiquitos, uno a la vez, con una corrida de tests entre cada uno, te dejan rastrear cada falla hasta su causa exacta, y revertir solo ese paso en lugar de todo.

¿Qué hace el skill cuando un paso deja la suite en rojo?

Revierte ese único paso y se detiene. No sigue editando para forzar los tests de vuelta al verde. Un rojo después de un paso de refactor significa que ese paso cambió el comportamiento, que es justo lo que un refactor no debe hacer. Revertir te devuelve a un estado que sabes que estaba bien y saca la diferencia a flote como una decisión deliberada (por ejemplo, 'esto en realidad es un cambio en el redondeo, ¿lo quieres como un fix aparte?').

¿Puedo arreglar un bug mientras refactorizo, ya que igual estoy metido ahí?

Aguántate las ganas. En el momento en que un refactor también cambia el comportamiento, el diff deja de decir la verdad, y un revisor que pasa la vista buscando 'solo un refactor' deja pasar un cambio de lógica directo. Termina el cambio estructural con los tests en verde, hazle commit como refactor, y después arregla el bug en su propio commit bien etiquetado. Dos diffs honestos valen más que un diff que miente sobre lo que hace.

Mis tests pasan pero son superficiales. ¿Con una suite en verde basta?

Una suite en verde solo prueba que preservaste el comportamiento que los tests chequean de verdad. El que ignoran todavía puede romperse sin que te enteres. Eso es teatro de cobertura. Antes de un refactor serio, dale un vistazo a si están ejercitadas las rutas interesantes (edge cases, manejo de errores, los condicionales complicados), no solo al porcentaje de líneas. Si las partes peligrosas no están cubiertas, agrega characterization tests ahí primero.

¿Cuándo no vale la pena refactorizar?

Cuando el código está por borrarse o reescribirse de cero, y cuando no hay ningún próximo cambio a la vista. Un refactor hoy no le da nada visible al usuario. Todo su valor está en hacer más barato y más seguro el próximo cambio. Si nunca vas a volver a tocar ese código, pulirlo es un hobby, no ingeniería. Invierte el esfuerzo donde de verdad vas a regresar.

¿Prefieres que lo hagamos por ti?

Esto mismo lo construimos para negocios como el tuyo. La primera conversación es gratis y sin compromiso.

Escríbenos por WhatsApp

Escríbenos por WhatsApp

Escanéalo con tu teléfono para escribirnos por WhatsApp.

Escanéalo con tu teléfono para escribirnos por WhatsApp.

¿Estás desde el teléfono y no puedes escanear? Escríbenos a info@ilustrari.com

Primera conversación gratis. Te responde el fundador.

Recursos relacionados